diff --git a/src/main/java/de/s42/dl/DLCore.java b/src/main/java/de/s42/dl/DLCore.java index c8b9a0a4..dcdac8db 100644 --- a/src/main/java/de/s42/dl/DLCore.java +++ b/src/main/java/de/s42/dl/DLCore.java @@ -29,6 +29,7 @@ import de.s42.dl.exceptions.DLException; import de.s42.dl.exceptions.InvalidPragma; import de.s42.dl.exceptions.InvalidInstance; +import de.s42.dl.exceptions.InvalidType; import java.util.*; /** @@ -97,7 +98,7 @@ public interface DLCore extends DLEntity public List getTypes(); - public List getTypes(Class annotationType); + public List getTypes(Class annotationType); public boolean isAllowDefineTypes(); @@ -148,8 +149,10 @@ public interface DLCore extends DLEntity public List getExported(); public Optional getExported(String name); + + public List getExportedByJavaType(Class annotationType) throws InvalidType; - public List getExported(Class annotationType); + public List getExported(Class annotationType); // PRAGMAS public DLPragma definePragma(DLPragma pragma, String... aliases) throws DLException; diff --git a/src/main/java/de/s42/dl/DLInstance.java b/src/main/java/de/s42/dl/DLInstance.java index 32009bea..f885f71c 100644 --- a/src/main/java/de/s42/dl/DLInstance.java +++ b/src/main/java/de/s42/dl/DLInstance.java @@ -137,7 +137,9 @@ default public DLCore getCore() public Optional getChildAsJavaObject(DLType type); - public List getChildrenAsJavaType(Class javaType); + public Optional getChildAsJavaObject(Class javaType); + + public List getChildrenAsJavaType(Class javaType); public List getChildrenAsJavaType(); } diff --git a/src/main/java/de/s42/dl/annotations/AbstractDLAnnotated.java b/src/main/java/de/s42/dl/annotations/AbstractDLAnnotated.java index 87844d8f..aeca3fab 100644 --- a/src/main/java/de/s42/dl/annotations/AbstractDLAnnotated.java +++ b/src/main/java/de/s42/dl/annotations/AbstractDLAnnotated.java @@ -50,13 +50,13 @@ public void addAnnotation(DLAnnotation annotation) } @Override - public Optional getAnnotation(Class type) + public Optional getAnnotation(Class type) { assert type != null; for (DLAnnotation annotation : annotations) { if (type.isAssignableFrom(annotation.getClass())) { - return Optional.of(annotation); + return Optional.of((AnnotationType)annotation); } } @@ -78,15 +78,15 @@ public Optional getAnnotation(String name) } @Override - public List getAnnotations(Class type) + public List getAnnotations(Class type) { assert type != null; - List result = new ArrayList<>(); + List result = new ArrayList<>(); for (DLAnnotation annotation : annotations) { if (type.isAssignableFrom(annotation.getClass())) { - result.add(annotation); + result.add((AnnotationType)annotation); } } @@ -110,7 +110,7 @@ public List getAnnotations(String name) } @Override - public boolean hasAnnotation(Class type) + public boolean hasAnnotation(Class type) { assert type != null; diff --git a/src/main/java/de/s42/dl/annotations/DLAnnotated.java b/src/main/java/de/s42/dl/annotations/DLAnnotated.java index a45b7f2a..6e40f0f9 100644 --- a/src/main/java/de/s42/dl/annotations/DLAnnotated.java +++ b/src/main/java/de/s42/dl/annotations/DLAnnotated.java @@ -39,17 +39,17 @@ public interface DLAnnotated extends DLEntity public List getAnnotations(); - public List getAnnotations(Class type); + public List getAnnotations(Class type); public List getAnnotations(String name); - public Optional getAnnotation(Class type); + public Optional getAnnotation(Class type); public Optional getAnnotation(String name); public boolean hasAnnotations(); - public boolean hasAnnotation(Class type); + public boolean hasAnnotation(Class type); public boolean hasAnnotation(String name); diff --git a/src/main/java/de/s42/dl/core/BaseDLCore.java b/src/main/java/de/s42/dl/core/BaseDLCore.java index ef6af8ca..a41b3704 100644 --- a/src/main/java/de/s42/dl/core/BaseDLCore.java +++ b/src/main/java/de/s42/dl/core/BaseDLCore.java @@ -117,7 +117,7 @@ private void init(boolean allowAll) allowUsePragmas = allowAll; allowRequire = allowAll; allowUseAsserts = allowAll; - + referenceResolver = DEFAULT_REFERENCE_RESOLVER; pathResolver = new DefaultDLPathResolver(); loadModuleType(this); @@ -245,21 +245,21 @@ protected void bindAnnotation(DLAnnotation annotation, DLAnnotated container) th assert annotation != null; assert container != null; - if (container instanceof DLAttribute) { + if (container instanceof DLAttribute dLAttribute) { if (annotation instanceof DLValidator && !((DLValidator) annotation).canValidateAttribute()) { throw new InvalidAnnotation("Annotation '" + annotation + "' can not validate attributes"); } - annotation.bindToAttribute((DLAttribute) container); - } else if (container instanceof DLInstance) { + annotation.bindToAttribute(dLAttribute); + } else if (container instanceof DLInstance dLInstance) { if (annotation instanceof DLValidator && !((DLValidator) annotation).canValidateInstance()) { throw new InvalidAnnotation("Annotation '" + annotation + "' can not validate instances"); } - annotation.bindToInstance((DLInstance) container); - } else if (container instanceof DLType) { + annotation.bindToInstance(dLInstance); + } else if (container instanceof DLType dLType) { if (annotation instanceof DLValidator && !(((DLValidator) annotation).canValidateType() @@ -267,7 +267,7 @@ protected void bindAnnotation(DLAnnotation annotation, DLAnnotated container) th throw new InvalidAnnotation("Annotation '" + annotation + "' can not validate types"); } - annotation.bindToType((DLType) container); + annotation.bindToType(dLType); } } @@ -511,14 +511,38 @@ public Optional getExported(String name) } @Override - public List getExported(Class annotationType) + public List getExportedByJavaType(Class javaType) throws InvalidType + { + assert javaType != null; + + List result = new ArrayList<>(); + + Optional optDlType = getType(javaType); + + if (optDlType.isEmpty()) { + throw new InvalidType("No type mapped for " + javaType); + } + + DLType dlType = optDlType.orElseThrow(); + + for (DLInstance instance : exported.values()) { + if (dlType.isAssignableFrom(instance.getType())) { + result.add(instance); + } + } + + return result; + } + + @Override + public List getExported(Class annotationType) { assert annotationType != null; List result = new ArrayList<>(); for (DLInstance instance : exported.values()) { - Optional optEventAnnotation = instance.getAnnotation(annotationType); + Optional optEventAnnotation = instance.getAnnotation(annotationType); if (optEventAnnotation.isPresent()) { result.add(instance); @@ -545,14 +569,14 @@ public List getTypes() } @Override - public List getTypes(Class annotationType) + public List getTypes(Class annotationType) { assert annotationType != null; List result = new ArrayList<>(); for (DLType type : types.values()) { - Optional optEventAnnotation = type.getAnnotation(annotationType); + Optional optEventAnnotation = type.getAnnotation(annotationType); if (optEventAnnotation.isPresent()) { result.add(type); @@ -658,8 +682,8 @@ public DLType defineType(DLType type, String... aliases) throws InvalidCore, Inv } // Default types get this core set as core - if (type instanceof DefaultDLType) { - ((DefaultDLType) type).setCore(this); + if (type instanceof DefaultDLType defaultDLType) { + defaultDLType.setCore(this); } // Make sure the type is valid @@ -919,15 +943,15 @@ && hasType(ObjectDLType.DEFAULT_SYMBOL)) { // Handle contains with searching for DLContainer for (Type interfaceType : typeClass.getGenericInterfaces()) { - if (interfaceType instanceof ParameterizedType) { + if (interfaceType instanceof ParameterizedType parameterizedType) { - ParameterizedType paramType = ((ParameterizedType) interfaceType); + ParameterizedType paramType = parameterizedType; // validate if the type is a DLContainer if (DLContainer.class.isAssignableFrom((Class) paramType.getRawType())) { // check and add its types in diamond operator as contained types - for (Type type : ((ParameterizedType) interfaceType).getActualTypeArguments()) { + for (Type type : parameterizedType.getActualTypeArguments()) { // container uses the current type - use the new type if ((type instanceof Class) && ((Class) type).equals(typeClass)) { @@ -1444,34 +1468,34 @@ public synchronized Object convertFromInstance(DLInstance instance) throws Inval convertInstance = type.createJavaInstance(); //allow maps to be set by that - if (convertInstance instanceof Map) { + if (convertInstance instanceof Map map) { //write properties of the instance for (String attributeName : instance.getAttributeNames()) { Object value = instance.get(attributeName); - if (value instanceof Object[]) { + if (value instanceof Object[] objects) { - Object[] convValue = new Object[((Object[]) value).length]; + Object[] convValue = new Object[objects.length]; - for (int i = 0; i < ((Object[]) ((Object[]) value)).length; ++i) { + for (int i = 0; i < ((Object[]) objects).length; ++i) { - Object val = ((Object[]) value)[i]; + Object val = objects[i]; - if (val instanceof DLInstance) { - convValue[i] = ((DLInstance) val).toJavaObject(); + if (val instanceof DLInstance dLInstance) { + convValue[i] = dLInstance.toJavaObject(); } else { convValue[i] = val; } } value = convValue; - } else if (value instanceof DLInstance) { - value = ((DLInstance) value).toJavaObject(); + } else if (value instanceof DLInstance dLInstance) { + value = dLInstance.toJavaObject(); } - ((Map) convertInstance).put(attributeName, value); + map.put(attributeName, value); } for (DLInstance child : instance.getChildren()) { @@ -1480,7 +1504,7 @@ public synchronized Object convertFromInstance(DLInstance instance) throws Inval Object convertChild = convertFromInstance(child); - ((Map) convertInstance).put(child.getName(), convertChild); + map.put(child.getName(), convertChild); } } } //default to assume its a bean @@ -1494,26 +1518,26 @@ public synchronized Object convertFromInstance(DLInstance instance) throws Inval Object value = instance.get(attributeName); - if (value instanceof Object[]) { + if (value instanceof Object[] objects) { - Object[] convValue = new Object[((Object[]) value).length]; + Object[] convValue = new Object[objects.length]; - for (int i = 0; i < ((Object[]) ((Object[]) value)).length; ++i) { + for (int i = 0; i < ((Object[]) objects).length; ++i) { - Object val = ((Object[]) value)[i]; + Object val = objects[i]; - if (val instanceof DLInstance) { - convValue[i] = ((DLInstance) val).toJavaObject(); + if (val instanceof DLInstance dLInstance) { + convValue[i] = dLInstance.toJavaObject(); } else { convValue[i] = val; } } value = convValue; - } else if (value instanceof DLInstance) { + } else if (value instanceof DLInstance dLInstance) { try { - value = ((DLInstance) value).toJavaObject(); + value = dLInstance.toJavaObject(); } catch (AssertionError ex) { throw new AssertionError("Error converting value '" + attributeName + "' to JavaObject in instance '" + instance.getName() + "'", ex); } @@ -1618,7 +1642,6 @@ public void setAllowUseAsserts(boolean allowUseAsserts) this.allowUseAsserts = allowUseAsserts; } - @Override public String getName() { diff --git a/src/main/java/de/s42/dl/core/DefaultCore.java b/src/main/java/de/s42/dl/core/DefaultCore.java index 64cfe474..d97984e3 100644 --- a/src/main/java/de/s42/dl/core/DefaultCore.java +++ b/src/main/java/de/s42/dl/core/DefaultCore.java @@ -85,6 +85,7 @@ import de.s42.log.LogLevel; import de.s42.log.LogManager; import de.s42.log.Logger; +import java.util.Optional; /** * @@ -360,5 +361,8 @@ public static void loadTypes(BaseDLCore core) throws DLException "java.util.Collections$UnmodifiableSet", "java.util.ImmutableCollections$SetN", SetDLType.class.getName()); + + // Define type for Optional<> + core.defineType(Optional.class); } } diff --git a/src/main/java/de/s42/dl/instances/DefaultDLInstance.java b/src/main/java/de/s42/dl/instances/DefaultDLInstance.java index 0ea23962..81bf3a43 100644 --- a/src/main/java/de/s42/dl/instances/DefaultDLInstance.java +++ b/src/main/java/de/s42/dl/instances/DefaultDLInstance.java @@ -97,6 +97,7 @@ public DefaultDLInstance(DLType type, String name) this.type = type; } + @Override public DLCore getCore() { return type.getCore(); @@ -486,8 +487,8 @@ protected void traverseChildren(DLInstance current, Consumer callbac assert callback != null; current.getChildren().forEach((child) -> { - traverseChildren(child, callback); - callback.accept(child); + traverseChildren((DLInstance) child, callback); + callback.accept((DLInstance) child); }); } @@ -552,19 +553,34 @@ public synchronized Object toJavaObject() } @Override - public List getChildrenAsJavaType(Class javaType) + public Optional getChildAsJavaObject(Class javaType) { assert javaType != null; DLType instanceType = getCore().getType(javaType).orElseThrow(); - List result = new ArrayList<>(children.size()); + for (DLInstance child : getChildren(instanceType)) { + + return Optional.of((ObjectType) child.toJavaObject()); + } + + return Optional.empty(); + } + + @Override + public List getChildrenAsJavaType(Class javaType) + { + assert javaType != null; + + DLType instanceType = getCore().getType(javaType).orElseThrow(); + + List result = new ArrayList<>(children.size()); for (DLInstance child : getChildren(instanceType)) { Object childJavaObject = child.toJavaObject(); - result.add(childJavaObject); + result.add((ObjectType) childJavaObject); } return result; diff --git a/src/main/java/de/s42/dl/io/json/JsonReader.java b/src/main/java/de/s42/dl/io/json/JsonReader.java index 7c7de38c..ac37460c 100644 --- a/src/main/java/de/s42/dl/io/json/JsonReader.java +++ b/src/main/java/de/s42/dl/io/json/JsonReader.java @@ -145,6 +145,10 @@ public static DLInstance fromJSON(DLCore core, JSONObject json) throws DLExcepti else if (value instanceof JSONArray) { value = ((JSONArray) value).toList().toArray(); } + + if (value instanceof String && ((String)value).isBlank()) { + value = null; + } // Set the attribute and make sure it is converted accordingly type.setAttributeFromValue(result, key, value); diff --git a/src/main/java/de/s42/dl/io/json/JsonWriter.java b/src/main/java/de/s42/dl/io/json/JsonWriter.java index 574ed6a0..2edc6654 100644 --- a/src/main/java/de/s42/dl/io/json/JsonWriter.java +++ b/src/main/java/de/s42/dl/io/json/JsonWriter.java @@ -28,12 +28,16 @@ import de.s42.base.conversion.ConversionHelper; import de.s42.base.files.FilesHelper; import de.s42.dl.DLAnnotation; +import de.s42.dl.DLAttribute; import de.s42.dl.DLCore; import de.s42.dl.DLInstance; import de.s42.dl.DLPragma; import de.s42.dl.DLType; +import de.s42.dl.annotations.persistence.DontPersistDLAnnotation; import de.s42.dl.exceptions.DLException; import de.s42.dl.io.DLWriter; +import de.s42.log.LogManager; +import de.s42.log.Logger; import java.io.IOException; import java.nio.file.Path; import java.util.ArrayList; @@ -53,6 +57,8 @@ public class JsonWriter implements DLWriter { + private final static Logger log = LogManager.getLogger(JsonWriter.class.getName()); + protected final Path file; protected final DLCore core; protected final List json = new ArrayList<>(); @@ -110,6 +116,15 @@ protected static Object convert(DLCore core, Object value) throws DLException return null; } else if (value instanceof DLInstance) { return toJSON(core, (DLInstance) value); + } else if (value.getClass().isArray()) { + List list = new ArrayList(); + + for (Object el : (Object[]) value) { + + list.add(convert(core, el)); + } + + return list; } else if (value instanceof Collection) { List list = new ArrayList(); @@ -124,15 +139,8 @@ protected static Object convert(DLCore core, Object value) throws DLException return ((Date) value).getTime(); } else if (value instanceof Boolean) { return value; - } else if (value instanceof Float) { - return value; - } else if (value instanceof Double) { - return value; - } else if (value instanceof Long) { - return value; - } else if (value instanceof Integer) { - return value; - } else if (value instanceof Short) { + // This also catches BigDecimal and BigInteger (which may be present when retrieved from JSON Objects etc.) + } else if (value instanceof Number) { return value; } else if (value instanceof String) { return value; @@ -162,10 +170,18 @@ public static JSONObject toJSON(DLCore core, DLInstance instance) throws DLExcep result.put("type", instance.getType().getCanonicalName()); - // write attributes + // Write attributes + // HINT: if the object contains an attribute "type" it can overwrite the internal type doing that (with its pros and cons) for (String attributeName : instance.getAttributeNames()) { Object val = instance.get(attributeName); + + DLAttribute attribute = instance.getType().getAttribute(attributeName).orElse(null); + + // Ignore attribute that shall not be persisted (may be null on special types like maps) + if ((attribute != null) && attribute.hasAnnotation(DontPersistDLAnnotation.class)) { + continue; + } result.put( attributeName, @@ -174,7 +190,7 @@ public static JSONObject toJSON(DLCore core, DLInstance instance) throws DLExcep } // @todo write dynamic attributes with types - // write annotations + // Write annotations if (instance.hasAnnotations()) { JSONArray annotations = new JSONArray(); result.put("annotations", annotations); @@ -202,7 +218,7 @@ public static JSONObject toJSON(DLCore core, DLInstance instance) throws DLExcep } } - // write children + // Write children if (instance.hasChildren()) { JSONArray children = new JSONArray(); @@ -240,6 +256,6 @@ public void close() throws IOException @Override public void flush() throws IOException { - // do nothing + // Do nothing } } diff --git a/src/main/java/de/s42/dl/types/collections/MapDLType.java b/src/main/java/de/s42/dl/types/collections/MapDLType.java index ad67319d..efb073d1 100644 --- a/src/main/java/de/s42/dl/types/collections/MapDLType.java +++ b/src/main/java/de/s42/dl/types/collections/MapDLType.java @@ -108,6 +108,8 @@ public boolean canRead() @Override public boolean mayContainType(DLType type) { + assert type != null; + if (!isGenericType()) { return true; } @@ -118,6 +120,8 @@ public boolean mayContainType(DLType type) @Override public DLInstance fromJavaObject(Object object) throws DLException { + assert object != null; + if (!(object instanceof Map)) { throw new InvalidInstance("object is required to be of class Map"); } @@ -148,6 +152,10 @@ public DLInstance fromJavaObject(Object object) throws DLException @Override public void setAttributeFromValue(DLInstance instance, String name, Object value) throws DLException { + assert instance != null; + assert name != null; + + if (isGenericType()) { Class valueType = getMapValueType(); diff --git a/src/main/java/de/s42/dl/util/DLHelper.java b/src/main/java/de/s42/dl/util/DLHelper.java index bd21bad5..45e5cb3c 100644 --- a/src/main/java/de/s42/dl/util/DLHelper.java +++ b/src/main/java/de/s42/dl/util/DLHelper.java @@ -96,8 +96,8 @@ public static StringBuilder describe(ContractAnnotationFactory factory, StringBu builder.append(factory.getOperatorAsString()); DLContract contract = factory.getContract(); - if (contract instanceof ContractAnnotationFactory) { - describe((ContractAnnotationFactory) contract, builder); + if (contract instanceof ContractAnnotationFactory contractAnnotationFactory) { + describe(contractAnnotationFactory, builder); } else if (contract != null) { builder .append("@") @@ -117,20 +117,20 @@ public static StringBuilder describe(AbstractBinaryContractFactory factory, Stri // First DLContract first = factory.getContractFirst(); - if (first instanceof AbstractBinaryContractFactory) { - describe((AbstractBinaryContractFactory) first, builder); - } else if (first instanceof ContractAnnotationFactory) { - describe((ContractAnnotationFactory) first, builder); + if (first instanceof AbstractBinaryContractFactory abstractBinaryContractFactory) { + describe(abstractBinaryContractFactory, builder); + } else if (first instanceof ContractAnnotationFactory contractAnnotationFactory) { + describe(contractAnnotationFactory, builder); } builder.append(factory.getOperatorAsString()); // Second DLContract second = factory.getContractSecond(); - if (second instanceof AbstractBinaryContractFactory) { - describe((AbstractBinaryContractFactory) second, builder); - } else if (second instanceof ContractAnnotationFactory) { - describe((ContractAnnotationFactory) second, builder); + if (second instanceof AbstractBinaryContractFactory abstractBinaryContractFactory) { + describe(abstractBinaryContractFactory, builder); + } else if (second instanceof ContractAnnotationFactory contractAnnotationFactory) { + describe(contractAnnotationFactory, builder); } builder.append(")"); @@ -155,14 +155,14 @@ public static StringBuilder describe(DLAnnotation annotation, StringBuilder buil .append(Arrays.toString(annotation.getFlatParameters())); // Special handling for contracts -> reconstruct expression - if (annotation instanceof AbstractBinaryContractFactory) { + if (annotation instanceof AbstractBinaryContractFactory abstractBinaryContractFactory) { builder .append(" "); - describe((AbstractBinaryContractFactory) annotation, builder); - } else if (annotation instanceof ContractAnnotationFactory) { + describe(abstractBinaryContractFactory, builder); + } else if (annotation instanceof ContractAnnotationFactory contractAnnotationFactory) { builder .append(" "); - describe((ContractAnnotationFactory) annotation, builder); + describe(contractAnnotationFactory, builder); } return builder; @@ -479,10 +479,11 @@ protected static String singleValueToString(Object value, boolean prettyPrint, i { if (value == null) { return ""; - } else if (value instanceof DLInstance) { - return toString((DLInstance) value, prettyPrint, indent + 1); - } else if (value instanceof Date) { - return "\"" + ConversionHelper.DATE_FORMAT.format(value) + "\""; + } else if (value instanceof DLInstance dLInstance) { + return toString(dLInstance, prettyPrint, indent + 1); + } else if (value instanceof Date date) { + return "" + date.getTime(); + //return "\"" + ConversionHelper.DATE_FORMAT.format(value) + "\""; } else if (value.getClass().isArray()) { StringBuilder builder = new StringBuilder(); @@ -516,7 +517,7 @@ protected static String singleValueToString(Object value, boolean prettyPrint, i public static String toString(DLInstance instance, boolean prettyPrint, int indent) { assert instance != null; - + StringBuilder result = new StringBuilder(); result.append(instance.getType().getCanonicalName()); @@ -540,10 +541,10 @@ public static String toString(DLInstance instance, boolean prettyPrint, int inde DLType type = instance.getType(); for (String attributeName : attributeNames) { - DLAttribute attribute = type.getAttribute(attributeName).orElseThrow(); + DLAttribute attribute = type.getAttribute(attributeName).orElse(null); - // Ignore attribute that shall not be persisted - if (attribute.hasAnnotation(DontPersistDLAnnotation.class)) { + // Ignore attribute that shall not be persisted (may be null on special types like maps) + if ((attribute != null) && attribute.hasAnnotation(DontPersistDLAnnotation.class)) { continue; }