import java.util.Arrays;
import java.util.Base64;
import java.util.List;
-import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
+import javax.xml.namespace.NamespaceContext;
import javax.xml.namespace.QName;
/**
// we do not support short and float, like recent additions to Java
// (e.g. optional primitives)
DATE_TIME(Instant.class, W3C_XML_SCHEMA_NS_URI, "dateTime", new InstantFormatter()), //
- UUID(UUID.class, CrName.CR_NAMESPACE_URI, "uuid", new UuidFormatter()), //
+ UUID(UUID.class, ArgeoNamespace.CR_NAMESPACE_URI, "uuid", new UuidFormatter()), //
+ QNAME(QName.class, W3C_XML_SCHEMA_NS_URI, "QName", new QNameFormatter()), //
ANY_URI(URI.class, W3C_XML_SCHEMA_NS_URI, "anyUri", new UriFormatter()), //
STRING(String.class, W3C_XML_SCHEMA_NS_URI, "string", new StringFormatter()), //
;
qName = new ContentName(namespaceUri, localName, RuntimeNamespaceContext.getNamespaceContext());
}
- public QName getqName() {
+ public QName getQName() {
return qName;
}
/** Default parsing procedure from a String to an object. */
public static Object parse(String str) {
+ return parse(RuntimeNamespaceContext.getNamespaceContext(), str);
+ }
+
+ /** Default parsing procedure from a String to an object. */
+ public static Object parse(NamespaceContext namespaceContext, String str) {
if (str == null)
throw new IllegalArgumentException("String cannot be null");
// order IS important
try {
if (str.length() == 4 || str.length() == 5)
- return BOOLEAN.getFormatter().parse(str);
+ return BOOLEAN.getFormatter().parse(namespaceContext, str);
} catch (IllegalArgumentException e) {
// silent
}
try {
- return INTEGER.getFormatter().parse(str);
+ return INTEGER.getFormatter().parse(namespaceContext, str);
} catch (IllegalArgumentException e) {
// silent
}
try {
- return LONG.getFormatter().parse(str);
+ return LONG.getFormatter().parse(namespaceContext, str);
} catch (IllegalArgumentException e) {
// silent
}
try {
- return DOUBLE.getFormatter().parse(str);
+ return DOUBLE.getFormatter().parse(namespaceContext, str);
} catch (IllegalArgumentException e) {
// silent
}
try {
- return DATE_TIME.getFormatter().parse(str);
+ return DATE_TIME.getFormatter().parse(namespaceContext, str);
} catch (IllegalArgumentException e) {
// silent
}
try {
if (str.length() == 36)
- return UUID.getFormatter().parse(str);
+ return UUID.getFormatter().parse(namespaceContext, str);
+ } catch (IllegalArgumentException e) {
+ // silent
+ }
+
+ // CURIE
+ if (str.startsWith("[") && str.endsWith("]")) {
+ try {
+ if (str.indexOf(":") >= 0) {
+ QName qName = (QName) QNAME.getFormatter().parse(namespaceContext, str);
+ return (java.net.URI) ANY_URI.getFormatter().parse(qName.getNamespaceURI() + qName.getLocalPart());
+ }
+ } catch (IllegalArgumentException e) {
+ // silent
+ }
+ }
+
+ try {
+ if (str.indexOf(":") >= 0) {
+ QName qName = (QName) QNAME.getFormatter().parse(namespaceContext, str);
+ // note: this QName may not be valid
+ // note: CURIE should be explicitly defined with surrounding brackets
+ return qName;
+ }
} catch (IllegalArgumentException e) {
// silent
}
try {
- java.net.URI uri = (java.net.URI) ANY_URI.getFormatter().parse(str);
+ java.net.URI uri = (java.net.URI) ANY_URI.getFormatter().parse(namespaceContext, str);
if (uri.getScheme() != null)
return uri;
String path = uri.getPath();
// see https://www.oreilly.com/library/view/xml-schema/0596002521/re91.html
// default
- return STRING.getFormatter().parse(str);
+ return STRING.getFormatter().parse(namespaceContext, str);
}
/**
* object.
*
*/
- @SuppressWarnings("unchecked")
public static <T> Optional<T> cast(Class<T> clss, Object value) {
- // TODO Or should we?
- Objects.requireNonNull(value, "Cannot cast a null value");
+ return cast(RuntimeNamespaceContext.getNamespaceContext(), clss, value);
+ }
+
+ /**
+ * Cast well know java types based on {@link Object#toString()} of the provided
+ * object.
+ *
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> Optional<T> cast(NamespaceContext namespaceContext, Class<T> clss, Object value) {
+ // if value is null, optional is empty
+ if (value == null)
+ return Optional.empty();
+
+ // if a default has been explicitly requested by passing Object.class
+ // we parse the related String
+ if (clss.isAssignableFrom(Object.class)) {
+ return Optional.of((T) parse(value.toString()));
+ }
+
+ // if value can be cast directly, let's do it
+ if (value.getClass().isAssignableFrom(clss)) {
+ return Optional.of(((T) value));
+ }
+
+ // let's cast between various numbers (possibly losing precision)
+ if (value instanceof Number number) {
+ if (Long.class.isAssignableFrom(clss))
+ return Optional.of((T) (Long) number.longValue());
+ else if (Integer.class.isAssignableFrom(clss))
+ return Optional.of((T) (Integer) number.intValue());
+ else if (Double.class.isAssignableFrom(clss))
+ return Optional.of((T) (Double) number.doubleValue());
+ }
+
+ // let's now try with the string representation
+ String strValue = value instanceof String ? (String) value : value.toString();
+
if (String.class.isAssignableFrom(clss)) {
- return Optional.of((T) value.toString());
+ return Optional.of((T) strValue);
+ }
+ if (QName.class.isAssignableFrom(clss)) {
+ return Optional.of((T) NamespaceUtils.parsePrefixedName(namespaceContext, strValue));
}
// Numbers
else if (Long.class.isAssignableFrom(clss)) {
if (value instanceof Long)
return Optional.of((T) value);
- return Optional.of((T) Long.valueOf(value.toString()));
+ return Optional.of((T) Long.valueOf(strValue));
} else if (Integer.class.isAssignableFrom(clss)) {
if (value instanceof Integer)
return Optional.of((T) value);
- return Optional.of((T) Integer.valueOf(value.toString()));
+ return Optional.of((T) Integer.valueOf(strValue));
} else if (Double.class.isAssignableFrom(clss)) {
if (value instanceof Double)
return Optional.of((T) value);
- return Optional.of((T) Double.valueOf(value.toString()));
+ return Optional.of((T) Double.valueOf(strValue));
}
- // Numbers
-// else if (Number.class.isAssignableFrom(clss)) {
-// if (value instanceof Number)
-// return Optional.of((T) value);
-// return Optional.of((T) Number.valueOf(value.toString()));
-// }
- return Optional.empty();
+
+ // let's now try to parse the string representation to a well-known type
+ Object parsedValue = parse(strValue);
+ if (parsedValue.getClass().isAssignableFrom(clss)) {
+ return Optional.of(((T) value));
+ }
+ throw new ClassCastException("Cannot convert " + value.getClass() + " to " + clss);
}
/** Utility to convert a data: URI to bytes. */
* contract than {@link Boolean#parseBoolean(String)}.
*/
@Override
- public Boolean parse(String str) throws IllegalArgumentException {
+ public Boolean parse(NamespaceContext namespaceContext, String str) throws IllegalArgumentException {
if ("true".equals(str))
return Boolean.TRUE;
if ("false".equals(str))
static class IntegerFormatter implements AttributeFormatter<Integer> {
@Override
- public Integer parse(String str) throws NumberFormatException {
+ public Integer parse(NamespaceContext namespaceContext, String str) throws NumberFormatException {
return Integer.parseInt(str);
}
}
static class LongFormatter implements AttributeFormatter<Long> {
@Override
- public Long parse(String str) throws NumberFormatException {
+ public Long parse(NamespaceContext namespaceContext, String str) throws NumberFormatException {
return Long.parseLong(str);
}
}
static class DoubleFormatter implements AttributeFormatter<Double> {
@Override
- public Double parse(String str) throws NumberFormatException {
+ public Double parse(NamespaceContext namespaceContext, String str) throws NumberFormatException {
return Double.parseDouble(str);
}
}
static class InstantFormatter implements AttributeFormatter<Instant> {
@Override
- public Instant parse(String str) throws IllegalArgumentException {
+ public Instant parse(NamespaceContext namespaceContext, String str) throws IllegalArgumentException {
try {
return Instant.parse(str);
} catch (DateTimeParseException e) {
static class UuidFormatter implements AttributeFormatter<UUID> {
@Override
- public UUID parse(String str) throws IllegalArgumentException {
+ public UUID parse(NamespaceContext namespaceContext, String str) throws IllegalArgumentException {
return java.util.UUID.fromString(str);
}
}
static class UriFormatter implements AttributeFormatter<URI> {
@Override
- public URI parse(String str) throws IllegalArgumentException {
+ public URI parse(NamespaceContext namespaceContext, String str) throws IllegalArgumentException {
try {
return new URI(str);
} catch (URISyntaxException e) {
}
+ static class QNameFormatter implements AttributeFormatter<QName> {
+
+ @Override
+ public QName parse(NamespaceContext namespaceContext, String str) throws IllegalArgumentException {
+ return NamespaceUtils.parsePrefixedName(namespaceContext, str);
+ }
+
+ }
+
static class StringFormatter implements AttributeFormatter<String> {
@Override
- public String parse(String str) {
+ public String parse(NamespaceContext namespaceContext, String str) {
return str;
}