IntegerCastFunction.java
/*******************************************************************************
* Copyright (c) 2016 Eclipse RDF4J contributors.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Distribution License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: BSD-3-Clause
*******************************************************************************/
package org.eclipse.rdf4j.query.algebra.evaluation.function.xsd;
import java.math.BigInteger;
import java.util.Optional;
import org.eclipse.rdf4j.model.Literal;
import org.eclipse.rdf4j.model.Value;
import org.eclipse.rdf4j.model.ValueFactory;
import org.eclipse.rdf4j.model.base.CoreDatatype;
import org.eclipse.rdf4j.model.datatypes.XMLDatatypeUtil;
import org.eclipse.rdf4j.query.algebra.evaluation.ValueExprEvaluationException;
/**
* Abstract superclass for {@link CastFunction}s that cast their arguments to an xsd:integer or one of its derived
* types.
*
* @author Jeen Broekstra
*/
public abstract class IntegerCastFunction extends CastFunction {
@Override
protected Literal convert(ValueFactory valueFactory, Value value) throws ValueExprEvaluationException {
if (value instanceof Literal) {
Literal literal = (Literal) value;
CoreDatatype.XSD datatype = literal.getCoreDatatype().asXSDDatatypeOrNull();
if (datatype != null && datatype.isNumericDatatype()) {
if (datatype.isIntegerDatatype()) {
String lexicalValue = XMLDatatypeUtil.collapseWhiteSpace(literal.getLabel());
if (isValidForDatatype(lexicalValue)) {
return valueFactory.createLiteral(lexicalValue, getCoreXsdDatatype());
}
}
// decimals, floats and doubles must be processed
// separately, see
// http://www.w3.org/TR/xpath-functions/#casting-from-primitive-to-primitive
BigInteger integerValue;
if (CoreDatatype.XSD.DECIMAL == datatype
|| datatype.isXSDDatatype() && datatype.isFloatingPointDatatype()) {
integerValue = literal.decimalValue().toBigInteger();
} else {
integerValue = literal.integerValue();
}
try {
return createTypedLiteral(valueFactory, integerValue).orElseThrow(() -> typeError(literal, null));
} catch (ArithmeticException | NumberFormatException e) {
throw typeError(literal, e);
}
} else if (datatype == CoreDatatype.XSD.BOOLEAN) {
try {
return createTypedLiteral(valueFactory, literal.booleanValue())
.orElseThrow(() -> typeError(literal, null));
} catch (IllegalArgumentException e) {
throw typeError(literal, e);
}
}
}
throw typeError(value, null);
}
/**
* create a {@link Literal} with the specific datatype for the supplied {@link BigInteger} value.
*
* @param vf the {@link ValueFactory} to use for creating the {@link Literal}
* @param integerValue the integer value to use for creating the {@link Literal}
* @return an {@link Optional} literal value, which may be empty if the supplied integerValue can not be
* successfully converted to the specific datatype.
* @throws ArithmeticException if an error occurs when attempting to convert the supplied value to a value of the
* specific datatype.
*/
protected abstract Optional<Literal> createTypedLiteral(ValueFactory vf, BigInteger integerValue)
throws ArithmeticException;
/**
* create a {@link Literal} with the specific datatype for the supplied boolean value.
*
* @param vf the {@link ValueFactory} to use for creating the {@link Literal}
* @param booleanValue the boolean value to use for creating the {@link Literal}
* @return an {@link Optional} literal value, which may be empty if the supplied boolean value can not be
* successfully converted to the specific datatype.
*/
protected Optional<Literal> createTypedLiteral(ValueFactory vf, boolean booleanValue) {
return Optional.of(vf.createLiteral(booleanValue ? "1" : "0", getCoreXsdDatatype()));
}
}