X-Git-Url: http://git.argeo.org/?a=blobdiff_plain;f=org.argeo.api.acr%2Fsrc%2Forg%2Fargeo%2Fapi%2Facr%2FCrAttributeType.java;h=888d376c44bb7346c19367c6d12ddeeaac0f9538;hb=5d7ebadd9fe583fd9d3b2e4ca6e99079b99aac5a;hp=0bbf63e710142bd881c18c6815e0181b57cbe1f6;hpb=7e464c3cedfa41ece64811fb55ddc9ce740a1050;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 0bbf63e71..888d376c4 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,14 +9,16 @@ import java.time.format.DateTimeParseException; import java.util.Arrays; import java.util.Base64; import java.util.List; +import java.util.Optional; import java.util.UUID; +import javax.xml.namespace.NamespaceContext; import javax.xml.namespace.QName; /** * Minimal standard attribute types that MUST be supported. All related classes * belong to java.base and can be implicitly derived form a given - * String. + * String. */ public enum CrAttributeType { BOOLEAN(Boolean.class, W3C_XML_SCHEMA_NS_URI, "boolean", new BooleanFormatter()), // @@ -26,7 +28,8 @@ public enum CrAttributeType { // 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()), // ; @@ -34,7 +37,7 @@ public enum CrAttributeType { private final Class clss; private final AttributeFormatter formatter; - private ContentName qName; + private final ContentName qName; private CrAttributeType(Class clss, String namespaceUri, String localName, AttributeFormatter formatter) { this.clss = clss; @@ -43,14 +46,10 @@ public enum CrAttributeType { qName = new ContentName(namespaceUri, localName, RuntimeNamespaceContext.getNamespaceContext()); } - public QName getqName() { + public QName getQName() { return qName; } - public void setqName(ContentName qName) { - this.qName = qName; - } - public Class getClss() { return clss; } @@ -77,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 { - java.net.URI uri = (java.net.URI) ANY_URI.getFormatter().parse(str); + 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(namespaceContext, str); if (uri.getScheme() != null) return uri; String path = uri.getPath(); @@ -131,7 +158,83 @@ 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); + } + + /** + * Cast well know java types based on {@link Object#toString()} of the provided + * object. + * + */ + public static Optional cast(Class clss, Object 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) strValue); + } + if (java.util.UUID.class.isAssignableFrom(clss)) { + return Optional.of((T) java.util.UUID.fromString(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(strValue)); + } else if (Integer.class.isAssignableFrom(clss)) { + if (value instanceof Integer) + return Optional.of((T) value); + 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(strValue)); + } + + // 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. */ @@ -169,7 +272,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)) @@ -180,14 +283,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); } } @@ -195,7 +298,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); } } @@ -203,7 +306,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) { @@ -215,7 +318,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); } } @@ -223,7 +326,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) { @@ -233,10 +336,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; }