Skip to content
This repository was archived by the owner on Feb 15, 2024. It is now read-only.

Commit aeedf00

Browse files
DaespenMatthias Böckmann
authored andcommitted
Pull request #6: Fix/refactor dataformat xml
Merge in EAR/aas-serializer from fix/refactor-dataformat-xml to master * commit 'efbef75ef68abcef71aaf1d764c17d5facbc9f01': Fix AccesControlMixin for xml dataformat Add default property order for xml dataformat Add xml annotation introspector for default namespace Add missing headers Remove unnecessary custom reference serializer annotations Add ReflectionHelper usage in xml dataformat Remove unnecessary custom xml (de)serializers Encapsulates xml list (de)serializer Refactor XML-Serializer Mixins
2 parents 85c59aa + efbef75 commit aeedf00

61 files changed

Lines changed: 423 additions & 1375 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/core/ReflectionHelper.java

Lines changed: 33 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,24 @@
1515
*/
1616
package io.adminshell.aas.v3.dataformat.core;
1717

18-
import io.adminshell.aas.v3.model.Constraint;
19-
import io.adminshell.aas.v3.model.Referable;
20-
import io.github.classgraph.ClassGraph;
21-
import io.github.classgraph.ClassInfo;
22-
import io.github.classgraph.ClassInfoList;
23-
import io.github.classgraph.ScanResult;
2418
import java.util.ArrayList;
2519
import java.util.HashMap;
2620
import java.util.List;
2721
import java.util.Map;
2822
import java.util.Objects;
2923
import java.util.Set;
3024
import java.util.stream.Collectors;
25+
3126
import org.slf4j.Logger;
3227
import org.slf4j.LoggerFactory;
3328

29+
import io.adminshell.aas.v3.model.Constraint;
30+
import io.adminshell.aas.v3.model.Referable;
31+
import io.github.classgraph.ClassGraph;
32+
import io.github.classgraph.ClassInfo;
33+
import io.github.classgraph.ClassInfoList;
34+
import io.github.classgraph.ScanResult;
35+
3436
/**
3537
* Helper class to collect relevant data needed for
3638
* ReflectionAnnotationIntrospector via reflection.
@@ -49,10 +51,15 @@ public class ReflectionHelper {
4951
*/
5052
public static final String DEFAULT_IMPLEMENTATION_PACKAGE_NAME = MODEL_PACKAGE_NAME + ".impl";
5153
/**
52-
* Name of package where the mixins are defined. These mixins are
54+
* Name of package where the json mixins are defined. These mixins are
5355
* automatically added to JsonSerializer and JsonDeserializer.
5456
*/
55-
public static final String MIXINS_PACKAGE_NAME = ROOT_PACKAGE_NAME + ".dataformat.json.mixins";
57+
public static final String JSON_MIXINS_PACKAGE_NAME = ROOT_PACKAGE_NAME + ".dataformat.json.mixins";
58+
/**
59+
* Name of package where the xml mixins are defined. These mixins are
60+
* automatically added to XmlSerializer and XmlDeserializer.
61+
*/
62+
public static final String XML_MIXINS_PACKAGE_NAME = ROOT_PACKAGE_NAME + ".dataformat.xml.mixins";
5663
/**
5764
* Suffix that identifies a class as a mixin.
5865
*/
@@ -77,10 +84,15 @@ public class ReflectionHelper {
7784
*/
7885
public static final Map<Class<?>, Set<Class<?>>> SUBTYPES;
7986
/**
80-
* Expanded list of all mixin classes defined in the MIXINS_PACKAGE_NAME
87+
* Expanded list of all mixin classes defined in the JSON_MIXINS_PACKAGE_NAME
8188
* package together with the corresponding class they should be applied to.
8289
*/
83-
public static final Map<Class<?>, Class<?>> MIXINS;
90+
public static final Map<Class<?>, Class<?>> JSON_MIXINS;
91+
/**
92+
* Expanded list of all mixin classes defined in the XML_MIXINS_PACKAGE_NAME
93+
* package together with the corresponding class they should be applied to.
94+
*/
95+
public static final Map<Class<?>, Class<?>> XML_MIXINS;
8496
/**
8597
* Expanded list of all default implementations in the
8698
* DEFAULT_IMPLEMENTATION_PACKAGE_NAME package together with the interface
@@ -123,7 +135,7 @@ public Class<? extends T> getImplementationType() {
123135
*
124136
* @param type the class to check
125137
* @return whether the given class is an interface and from within the
126-
* MODEL_PACKAGE_NAME package
138+
* MODEL_PACKAGE_NAME package
127139
*/
128140
public static boolean isModelInterface(Class<?> type) {
129141
return type.isInterface() && MODEL_PACKAGE_NAME.equals(type.getPackageName());
@@ -155,7 +167,7 @@ public static boolean hasDefaultImplementation(Class<?> interfaceType) {
155167
*
156168
* @param type the class to check
157169
* @return whether the given class is an interface from within the
158-
* MODEL_PACKAGE_NAME package as well as a default implementation or not
170+
* MODEL_PACKAGE_NAME package as well as a default implementation or not
159171
*/
160172
public static boolean isModelInterfaceOrDefaultImplementation(Class<?> type) {
161173
return isModelInterface(type) || isDefaultImplementation(type);
@@ -167,7 +179,7 @@ public static boolean isModelInterfaceOrDefaultImplementation(Class<?> type) {
167179
*
168180
* @param clazz the class to find the type information for
169181
* @return the type information for the given class or null if there is no
170-
* type information or type information should not be included
182+
* type information or type information should not be included
171183
*/
172184
public static String getModelType(Class<?> clazz) {
173185
Class<?> type = getMostSpecificTypeWithModelType(clazz);
@@ -193,7 +205,7 @@ public static String getModelType(Class<?> clazz) {
193205
*
194206
* @param clazz the class to find the type for
195207
* @return the most specific supertype of given class that contains some AAS
196-
* type information or null if there is none
208+
* type information or null if there is none
197209
*/
198210
public static Class<?> getMostSpecificTypeWithModelType(Class<?> clazz) {
199211
return TYPES_WITH_MODEL_TYPE.stream()
@@ -224,7 +236,8 @@ public static Class<?> getMostSpecificTypeWithModelType(Class<?> clazz) {
224236
.scan();
225237
TYPES_WITH_MODEL_TYPE = scanModelTypes(modelScan);
226238
SUBTYPES = scanSubtypes(modelScan);
227-
MIXINS = scanMixins(modelScan);
239+
JSON_MIXINS = scanMixins(modelScan, JSON_MIXINS_PACKAGE_NAME);
240+
XML_MIXINS = scanMixins(modelScan, XML_MIXINS_PACKAGE_NAME);
228241
DEFAULT_IMPLEMENTATIONS = scanDefaultImplementations(modelScan);
229242
ENUMS = modelScan.getAllEnums().loadClasses(Enum.class);
230243
INTERFACES_WITHOUT_DEFAULT_IMPLEMENTATION = getInterfacesWithoutDefaultImplementation(modelScan);
@@ -247,7 +260,7 @@ private static List<ImplementationInfo> scanDefaultImplementations(ScanResult mo
247260
.loadClasses()
248261
.stream()
249262
.forEach(x -> {
250-
String interfaceName = x.getSimpleName().substring(DEFAULT_IMPLEMENTATION_PREFIX.length());//using conventions
263+
String interfaceName = x.getSimpleName().substring(DEFAULT_IMPLEMENTATION_PREFIX.length());// using conventions
251264
ClassInfoList interfaceClassInfos = modelScan.getAllClasses().filter(y -> y.isInterface() && Objects.equals(y.getSimpleName(), interfaceName));
252265
if (interfaceClassInfos.isEmpty()) {
253266
logger.warn("could not find interface realized by default implementation class '{}'", x.getSimpleName());
@@ -263,10 +276,10 @@ private static List<ImplementationInfo> scanDefaultImplementations(ScanResult mo
263276
return defaultImplementations;
264277
}
265278

266-
private static Map<Class<?>, Class<?>> scanMixins(ScanResult modelScan) {
279+
private static Map<Class<?>, Class<?>> scanMixins(ScanResult modelScan, String packageName) {
267280
ScanResult mixinScan = new ClassGraph()
268281
.enableClassInfo()
269-
.acceptPackagesNonRecursive(MIXINS_PACKAGE_NAME)
282+
.acceptPackagesNonRecursive(packageName)
270283
.scan();
271284
Map<Class<?>, Class<?>> mixins = new HashMap<>();
272285
mixinScan.getAllClasses()
@@ -290,13 +303,13 @@ private static Map<Class<?>, Class<?>> scanMixins(ScanResult modelScan) {
290303
private static Map<Class<?>, Set<Class<?>>> scanSubtypes(ScanResult modelScan) {
291304
return modelScan.getAllInterfaces().stream()
292305
.filter(ReflectionHelper::hasSubclass)
293-
.collect(Collectors.toMap(x -> x.loadClass(), ReflectionHelper::getSubclasses));
306+
.collect(Collectors.toMap(ClassInfo::loadClass, ReflectionHelper::getSubclasses));
294307
}
295308

296309
private static Set<Class<?>> getSubclasses(ClassInfo clazzInfo) {
297310
return clazzInfo.getClassesImplementing()
298311
.directOnly()
299-
.filter(x -> x.isInterface())
312+
.filter(ClassInfo::isInterface)
300313
.loadClasses()
301314
.stream()
302315
.collect(Collectors.toSet());

dataformat-json/src/main/java/io/adminshell/aas/v3/dataformat/json/JsonDeserializer.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
*/
1616
package io.adminshell.aas.v3.dataformat.json;
1717

18+
import java.util.Map;
19+
1820
import com.fasterxml.jackson.core.JsonProcessingException;
1921
import com.fasterxml.jackson.databind.DeserializationFeature;
2022
import com.fasterxml.jackson.databind.json.JsonMapper;
@@ -29,7 +31,6 @@
2931
import io.adminshell.aas.v3.dataformat.json.modeltype.ModelTypeProcessor;
3032
import io.adminshell.aas.v3.model.AssetAdministrationShellEnvironment;
3133
import io.adminshell.aas.v3.model.EmbeddedDataSpecification;
32-
import java.util.Map;
3334

3435
/**
3536
* Class for deserializing/parsing AAS JSON documents.
@@ -55,12 +56,12 @@ protected void buildMapper() {
5556
.addModule(buildImplementationModule())
5657
.addModule(buildCustomDeserializerModule())
5758
.build();
58-
ReflectionHelper.MIXINS.entrySet().forEach(x -> mapper.addMixIn(x.getKey(), x.getValue()));
59+
ReflectionHelper.JSON_MIXINS.entrySet().forEach(x -> mapper.addMixIn(x.getKey(), x.getValue()));
5960
}
6061

6162
protected SimpleModule buildCustomDeserializerModule() {
6263
SimpleModule module = new SimpleModule();
63-
customDeserializers.forEach((k, v) -> module.addDeserializer(k, v));
64+
customDeserializers.forEach(module::addDeserializer);
6465
return module;
6566
}
6667

dataformat-json/src/main/java/io/adminshell/aas/v3/dataformat/json/JsonSerializer.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,13 @@ protected void buildMapper() {
4848
.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
4949
.serializationInclusion(JsonInclude.Include.NON_NULL)
5050
.addModule(buildEnumModule())
51-
.addModule(buildCustomDeserializerModule())
51+
.addModule(buildCustomSerializerModule())
5252
.annotationIntrospector(new ReflectionAnnotationIntrospector())
5353
.build();
54-
ReflectionHelper.MIXINS.entrySet().forEach(x -> mapper.addMixIn(x.getKey(), x.getValue()));
54+
ReflectionHelper.JSON_MIXINS.entrySet().forEach(x -> mapper.addMixIn(x.getKey(), x.getValue()));
5555
}
5656

57-
protected SimpleModule buildCustomDeserializerModule() {
57+
protected SimpleModule buildCustomSerializerModule() {
5858
SimpleModule module = new SimpleModule();
5959
module.addSerializer(EmbeddedDataSpecification.class, new EmbeddedDataSpecificationSerializer());
6060
return module;
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package io.adminshell.aas.v3.dataformat.xml;
17+
18+
import com.fasterxml.jackson.databind.introspect.Annotated;
19+
import com.fasterxml.jackson.databind.introspect.AnnotatedClass;
20+
import com.fasterxml.jackson.dataformat.xml.JacksonXmlAnnotationIntrospector;
21+
22+
/**
23+
* This class helps to dynamically decide how to de-/serialize classes and
24+
* properties defined in the AAS model library. It will automatically add a default namespace
25+
* to property names and set a default property order for contained elements.
26+
*/
27+
public class XmlDataformatAnnotationIntrospector extends JacksonXmlAnnotationIntrospector {
28+
private static final long serialVersionUID = 1L;
29+
30+
protected String myDefaultNamespace = "";
31+
32+
public XmlDataformatAnnotationIntrospector() {
33+
super();
34+
myDefaultNamespace = AasXmlNamespaceContext.AAS_URI;
35+
}
36+
37+
@Override
38+
public String findNamespace(Annotated ann) {
39+
String ns = super.findNamespace(ann);
40+
if (ns == null) {
41+
return myDefaultNamespace;
42+
} else {
43+
return ns;
44+
}
45+
}
46+
47+
@Override
48+
public String[] findSerializationPropertyOrder(AnnotatedClass ac) {
49+
String[] order = super.findSerializationPropertyOrder(ac);
50+
if (order == null) {
51+
order = new String[] {
52+
"extensions", "idShort", "displayNames", "category", "descriptions", "administration", "identification", "kind", "semanticId",
53+
"qualifiers", "embeddedDataSpecification", "dataSpecifications", "isCaseOf", "security", "derivedFrom", "submodels", "assetInformation", "views", "externalSubjectId", "key", "allowDuplicates", "ordered", "valueId", "value",
54+
"max", "min", "type", "valueType", "mimeType", "first", "second", "annotations", "revision", "version", "defaultThumbnail", "globalAssetId", "externalAssetId", "entityType", "statements", "assetKind", "billOfMaterials",
55+
"specificAssetIds", "observed", "inoutputVariables", "inputVariables", "outputVariables", "submodelElements", "containedElements"
56+
};
57+
}
58+
return order;
59+
}
60+
}

0 commit comments

Comments
 (0)