X-Git-Url: https://git.argeo.org/?a=blobdiff_plain;f=org.argeo.api.acr%2Fsrc%2Forg%2Fargeo%2Fapi%2Facr%2FCrAttributeType.java;fp=org.argeo.api.acr%2Fsrc%2Forg%2Fargeo%2Fapi%2Facr%2FCrAttributeType.java;h=3e0dddee4c55ed6cf6f6f81e836d8941dca3fd52;hb=117eaabc86f6c09eff9a4b971ac137d51f45e953;hp=3e12fb1c87067fd188bfa34cac4c44794c9ec5d2;hpb=be6d2dbdf3ccafc9b8ac8820a68a3eb7de859b06;p=lgpl%2Fargeo-commons.git diff --git a/org.argeo.api.acr/src/org/argeo/api/acr/CrAttributeType.java b/org.argeo.api.acr/src/org/argeo/api/acr/CrAttributeType.java index 3e12fb1c8..3e0dddee4 100644 --- a/org.argeo.api.acr/src/org/argeo/api/acr/CrAttributeType.java +++ b/org.argeo.api.acr/src/org/argeo/api/acr/CrAttributeType.java @@ -9,10 +9,10 @@ import java.time.format.DateTimeParseException; 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; /** @@ -29,6 +29,7 @@ public enum CrAttributeType { // (e.g. optional primitives) DATE_TIME(Instant.class, W3C_XML_SCHEMA_NS_URI, "dateTime", new InstantFormatter()), // 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()), // ; @@ -45,7 +46,7 @@ public enum CrAttributeType { qName = new ContentName(namespaceUri, localName, RuntimeNamespaceContext.getNamespaceContext()); } - public QName getqName() { + public QName getQName() { return qName; } @@ -75,43 +76,71 @@ public enum CrAttributeType { /** 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(); @@ -129,7 +158,7 @@ public enum CrAttributeType { // see https://www.oreilly.com/library/view/xml-schema/0596002521/re91.html // default - return STRING.getFormatter().parse(str); + return STRING.getFormatter().parse(namespaceContext, str); } /** @@ -137,34 +166,72 @@ public enum CrAttributeType { * object. * */ - @SuppressWarnings("unchecked") public static Optional cast(Class 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 Optional cast(NamespaceContext namespaceContext, Class 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. */ @@ -202,7 +269,7 @@ public enum CrAttributeType { * 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)) @@ -213,14 +280,14 @@ public enum CrAttributeType { static class IntegerFormatter implements AttributeFormatter { @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 { @Override - public Long parse(String str) throws NumberFormatException { + public Long parse(NamespaceContext namespaceContext, String str) throws NumberFormatException { return Long.parseLong(str); } } @@ -228,7 +295,7 @@ public enum CrAttributeType { static class DoubleFormatter implements AttributeFormatter { @Override - public Double parse(String str) throws NumberFormatException { + public Double parse(NamespaceContext namespaceContext, String str) throws NumberFormatException { return Double.parseDouble(str); } } @@ -236,7 +303,7 @@ public enum CrAttributeType { static class InstantFormatter implements AttributeFormatter { @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) { @@ -248,7 +315,7 @@ public enum CrAttributeType { static class UuidFormatter implements AttributeFormatter { @Override - public UUID parse(String str) throws IllegalArgumentException { + public UUID parse(NamespaceContext namespaceContext, String str) throws IllegalArgumentException { return java.util.UUID.fromString(str); } } @@ -256,7 +323,7 @@ public enum CrAttributeType { static class UriFormatter implements AttributeFormatter { @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) { @@ -266,10 +333,19 @@ public enum CrAttributeType { } + static class QNameFormatter implements AttributeFormatter { + + @Override + public QName parse(NamespaceContext namespaceContext, String str) throws IllegalArgumentException { + return NamespaceUtils.parsePrefixedName(namespaceContext, str); + } + + } + static class StringFormatter implements AttributeFormatter { @Override - public String parse(String str) { + public String parse(NamespaceContext namespaceContext, String str) { return str; }