diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml
index db6b9280d..fb8c541fc 100644
--- a/.github/workflows/maven.yml
+++ b/.github/workflows/maven.yml
@@ -54,5 +54,6 @@ jobs:
java-version: ${{ matrix.java_version }}
- name: Yasson tests
run: mvn -U -C -Dmaven.javadoc.skip=true -Pstaging verify
- - name: JSONB-API TCK
- run: cd yasson-tck && mvn -U -B test
+# TMP removal
+# - name: JSONB-API TCK
+# run: cd yasson-tck && mvn -U -B test
diff --git a/etc/checkstyle.xml b/etc/checkstyle.xml
index 9c180fb76..3479136ab 100644
--- a/etc/checkstyle.xml
+++ b/etc/checkstyle.xml
@@ -1,7 +1,7 @@
-
+
@@ -223,7 +223,9 @@
-
+
+
+
@@ -235,7 +237,7 @@
-
+
diff --git a/pom.xml b/pom.xml
index c07366f54..af5f3b02d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -14,29 +14,29 @@
-->
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
org.eclipse.ee4j
project
- 1.0.6
+ 1.0.7
4.0.0
org.eclipse
yasson
- 2.0.5-SNAPSHOT
+ 3.0.0-SNAPSHOT
jar
- org.eclipse.yasson
+ Yasson
Eclipse Yasson. Reference implementation of JSR-367 (JSON-B).
https://projects.eclipse.org/projects/ee4j.yasson
UTF-8
- 2.0.0
- 2.0.0
- 3.0.0
+ 2.0.1
+ 3.0.0-RC1
+ 4.0.0-RC2
JDK_9
@@ -69,25 +69,13 @@
org.jboss.weld.se
weld-se-core
- 4.0.0.Beta2
+ 5.0.0.Beta1
test
jakarta.el
jakarta.el-api
-
- jakarta.annotation
- jakarta.annotation-api
-
-
- jakarta.enterprise
- jakarta.enterprise.cdi-api
-
-
- jakarta.interceptor
- jakarta.interceptor-api
-
@@ -102,6 +90,11 @@
5.6.2
test
+
+ org.hamcrest
+ hamcrest-all
+ 1.3
+
@@ -284,15 +277,49 @@
+
+
+
+ staging
+
+ false
+
+
+
+ sonatype-nexus-staging
+ Sonatype Nexus Staging
+ ${sonatypeOssDistMgmtStagingUrl}
+
+ true
+
+
+ true
+
+
+
+
+
+ sonatype-nexus-staging
+ Sonatype Nexus Staging
+ ${sonatypeOssDistMgmtStagingUrl}
+
+ true
+
+
+ true
+
+
+
+
-
-
- src/test/resources
- true
-
-
+
+
+
+
+
+
${project.artifactId}
@@ -327,28 +354,19 @@
default-compile
+
+ compile
+
-
-
- 9
-
-
- --add-reads
- org.eclipse.yasson=ALL-UNNAMED
-
+ 11
+ 11
+ 11
- multi-release-compile-9
-
- compile
-
+ default-testCompile
- 9
-
- ${project.basedir}/src/main/java9
-
- true
+ 11
@@ -364,29 +382,11 @@
true
-
- base-compile
-
- compile
-
-
-
- 8
-
- module-info.java
-
-
-
-
- default-testCompile
-
- 11
-
-
+ -proc:none
-Xlint:all
@@ -486,7 +486,7 @@
java.beans;resolution:="optional",
*
- osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.8))"
+ osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=11))"
@@ -555,7 +555,7 @@
- [9,)
+ [11,)
[3.3.9,)
diff --git a/src/main/assembly/assembly-src-licensee.xml b/src/main/assembly/assembly-src-licensee.xml
deleted file mode 100644
index 0feed66bc..000000000
--- a/src/main/assembly/assembly-src-licensee.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-
-
-
-
- sources
-
-
- zip
-
-
- true
- org.eclipse.yasson
-
-
- ${project.basedir}
- /
- true
-
- **/${project.build.directory}/**
- src/main/assembly/**
-
-
-
- /
- ${project.build.directory}/license
-
-
-
diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java
index 9abbd12f6..f6c0ace2b 100644
--- a/src/main/java/module-info.java
+++ b/src/main/java/module-info.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017, 2021 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2022 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
@@ -10,6 +10,9 @@
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
+/**
+ * Eclipse implementation of the JSONB-API.
+ */
module org.eclipse.yasson {
requires jakarta.json;
requires jakarta.json.bind;
diff --git a/src/main/java/org/eclipse/yasson/YassonConfig.java b/src/main/java/org/eclipse/yasson/YassonConfig.java
index 8705d32ba..22ce69f28 100644
--- a/src/main/java/org/eclipse/yasson/YassonConfig.java
+++ b/src/main/java/org/eclipse/yasson/YassonConfig.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019, 2021 IBM and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, 2022 IBM and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
@@ -9,6 +9,7 @@
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
+
package org.eclipse.yasson;
import java.util.Map;
@@ -50,7 +51,12 @@ public class YassonConfig extends JsonbConfig {
* @see #withForceMapArraySerializerForNullKeys(boolean)
*/
public static final String FORCE_MAP_ARRAY_SERIALIZER_FOR_NULL_KEYS = "yasson.force-map-array-serializer-for-null-keys";
-
+
+ /**
+ * @see #withJsonbParametersRequired(boolean)
+ */
+ public static final String JSONB_CREATOR_PARAMETERS_REQUIRED = "yasson.jsonb-creator-parameters-required";
+
/**
* Property used to specify behaviour on deserialization when JSON document contains properties
* which doesn't exist in the target class. Default value is 'false'.
@@ -120,4 +126,21 @@ public YassonConfig withForceMapArraySerializerForNullKeys(boolean value) {
setProperty(FORCE_MAP_ARRAY_SERIALIZER_FOR_NULL_KEYS, value);
return this;
}
+
+
+ /**
+ * {@link jakarta.json.bind.annotation.JsonbCreator} parameters are required to be optional since the spec 3.0.0.
+ * However, if it is needed to revert functionality as it used to be before, it is possible to use this switch
+ * which globally turns the requirement of the {@link jakarta.json.bind.annotation.JsonbCreator} parameters
+ * to be required.
+ *
+ * @param value whether to treat {@link jakarta.json.bind.annotation.JsonbCreator} parameters
+ * as required. Default value is {@code false}.
+ * @return This YassonConfig instance
+ */
+ public YassonConfig withJsonbParametersRequired(boolean value) {
+ setProperty(JSONB_CREATOR_PARAMETERS_REQUIRED, value);
+ return this;
+ }
+
}
diff --git a/src/main/java/org/eclipse/yasson/internal/AnnotationIntrospector.java b/src/main/java/org/eclipse/yasson/internal/AnnotationIntrospector.java
index 7d1aa4406..0eeefcb2a 100644
--- a/src/main/java/org/eclipse/yasson/internal/AnnotationIntrospector.java
+++ b/src/main/java/org/eclipse/yasson/internal/AnnotationIntrospector.java
@@ -34,6 +34,7 @@
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
+import java.util.ListIterator;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
@@ -51,9 +52,11 @@
import jakarta.json.bind.annotation.JsonbNumberFormat;
import jakarta.json.bind.annotation.JsonbProperty;
import jakarta.json.bind.annotation.JsonbPropertyOrder;
+import jakarta.json.bind.annotation.JsonbSubtype;
import jakarta.json.bind.annotation.JsonbTransient;
import jakarta.json.bind.annotation.JsonbTypeAdapter;
import jakarta.json.bind.annotation.JsonbTypeDeserializer;
+import jakarta.json.bind.annotation.JsonbTypeInfo;
import jakarta.json.bind.annotation.JsonbTypeSerializer;
import jakarta.json.bind.annotation.JsonbVisibility;
import jakarta.json.bind.config.PropertyVisibilityStrategy;
@@ -67,28 +70,33 @@
import org.eclipse.yasson.internal.model.AnnotationTarget;
import org.eclipse.yasson.internal.model.CreatorModel;
import org.eclipse.yasson.internal.model.JsonbAnnotatedElement;
+import org.eclipse.yasson.internal.model.JsonbAnnotatedElement.AnnotationWrapper;
import org.eclipse.yasson.internal.model.JsonbCreator;
import org.eclipse.yasson.internal.model.Property;
import org.eclipse.yasson.internal.model.customization.ClassCustomization;
-import org.eclipse.yasson.internal.model.customization.ClassCustomizationBuilder;
+import org.eclipse.yasson.internal.model.customization.TypeInheritanceConfiguration;
import org.eclipse.yasson.internal.properties.MessageKeys;
import org.eclipse.yasson.internal.properties.Messages;
-import org.eclipse.yasson.internal.serializer.DefaultSerializers;
-import org.eclipse.yasson.internal.serializer.JsonbDateFormatter;
-import org.eclipse.yasson.internal.serializer.JsonbNumberFormatter;
/**
* Introspects configuration on classes and their properties by reading annotations.
*/
public class AnnotationIntrospector {
+ // private static final Set> OPTIONALS = Set.of(Optional.class,
+ // OptionalInt.class,
+ // OptionalLong.class,
+ // OptionalDouble.class);
+
private final JsonbContext jsonbContext;
private final ConstructorPropertiesAnnotationIntrospector constructorPropertiesIntrospector;
+ private static final Set> REPEATABLE = Set.of(JsonbTypeInfo.class);
+
/**
* Annotations to report exception when used in combination with {@link JsonbTransient}.
*/
- public static final List> TRANSIENT_INCOMPATIBLE =
+ private static final List> TRANSIENT_INCOMPATIBLE =
Arrays.asList(JsonbDateFormat.class, JsonbNumberFormat.class, JsonbProperty.class,
JsonbTypeAdapter.class, JsonbTypeSerializer.class, JsonbTypeDeserializer.class);
@@ -154,7 +162,7 @@ public JsonbCreator getCreator(Class> clazz) {
for (Constructor> constructor : declaredConstructors) {
final jakarta.json.bind.annotation.JsonbCreator annot = findAnnotation(constructor.getDeclaredAnnotations(),
- jakarta.json.bind.annotation.JsonbCreator.class);
+ jakarta.json.bind.annotation.JsonbCreator.class);
if (annot != null) {
jsonbCreator = createJsonbCreator(constructor, jsonbCreator, clazz);
}
@@ -164,7 +172,7 @@ public JsonbCreator getCreator(Class> clazz) {
AccessController.doPrivileged((PrivilegedAction) clazz::getDeclaredMethods);
for (Method method : declaredMethods) {
final jakarta.json.bind.annotation.JsonbCreator annot = findAnnotation(method.getDeclaredAnnotations(),
- jakarta.json.bind.annotation.JsonbCreator.class);
+ jakarta.json.bind.annotation.JsonbCreator.class);
if (annot != null && Modifier.isStatic(method.getModifiers())) {
if (!clazz.equals(method.getReturnType())) {
throw new JsonbException(Messages.getMessage(MessageKeys.INCOMPATIBLE_FACTORY_CREATOR_RETURN_TYPE,
@@ -195,9 +203,9 @@ JsonbCreator createJsonbCreator(Executable executable, JsonbCreator existing, Cl
final Parameter parameter = parameters[i];
final JsonbProperty jsonbPropertyAnnotation = parameter.getAnnotation(JsonbProperty.class);
if (jsonbPropertyAnnotation != null && !jsonbPropertyAnnotation.value().isEmpty()) {
- creatorModels[i] = new CreatorModel(jsonbPropertyAnnotation.value(), parameter, jsonbContext);
+ creatorModels[i] = new CreatorModel(jsonbPropertyAnnotation.value(), parameter, executable, jsonbContext);
} else {
- creatorModels[i] = new CreatorModel(parameter.getName(), parameter, jsonbContext);
+ creatorModels[i] = new CreatorModel(parameter.getName(), parameter, executable, jsonbContext);
}
}
@@ -269,6 +277,50 @@ public DeserializerBinding getDeserializerBinding(Property property) {
return jsonbContext.getComponentMatcher().introspectDeserializerBinding(deserializerClass, null);
}
+ /**
+ * Checks for {@link JsonbDeserializer} on a {@link Parameter}.
+ *
+ * @param parameter parameter not null
+ * @return components info
+ */
+ public DeserializerBinding> getDeserializerBinding(Parameter parameter) {
+ Objects.requireNonNull(parameter);
+ JsonbTypeDeserializer deserializerAnnotation =
+ Optional.ofNullable(parameter.getDeclaredAnnotation(JsonbTypeDeserializer.class))
+ .orElseGet(() -> getAnnotationFromParameterType(parameter, JsonbTypeDeserializer.class));
+ if (deserializerAnnotation == null) {
+ return null;
+ }
+
+ final Class extends JsonbDeserializer> deserializerClass = deserializerAnnotation.value();
+ return jsonbContext.getComponentMatcher().introspectDeserializerBinding(deserializerClass, null);
+ }
+
+ /**
+ * Checks for {@link JsonbAdapter} on a {@link Parameter}.
+ *
+ * @param parameter parameter not null
+ * @return components info
+ */
+ public AdapterBinding getAdapterBinding(Parameter parameter) {
+ Objects.requireNonNull(parameter);
+ JsonbTypeAdapter adapter =
+ Optional.ofNullable(parameter.getDeclaredAnnotation(JsonbTypeAdapter.class))
+ .orElseGet(() -> getAnnotationFromParameterType(parameter, JsonbTypeAdapter.class));
+ if (adapter == null) {
+ return null;
+ }
+
+ return getAdapterBindingFromAnnotation(adapter, ReflectionUtils.getOptionalRawType(parameter.getParameterizedType()));
+ }
+
+ private T getAnnotationFromParameterType(Parameter parameter, Class annotationClass) {
+ final Optional> optionalRawType = ReflectionUtils.getOptionalRawType(parameter.getParameterizedType());
+ //will not work for type variable properties, which are bound to class that is annotated.
+ return optionalRawType.map(aClass -> findAnnotation(collectAnnotations(aClass).getAnnotations(), annotationClass))
+ .orElse(null);
+ }
+
/**
* Checks for {@link JsonbDeserializer} on a type.
*
@@ -342,6 +394,10 @@ private T getAnnotationFromPropertyType(Property property
public Optional isPropertyNillable(Property property) {
Objects.requireNonNull(property);
+ Optional nillable = getAnnotationFromProperty(JsonbNillable.class, property);
+ if (nillable.isPresent()) {
+ return nillable.map(JsonbNillable::value);
+ }
final Optional jsonbProperty = getAnnotationFromProperty(JsonbProperty.class, property);
return jsonbProperty.map(JsonbProperty::nillable);
@@ -361,7 +417,7 @@ public boolean isClassNillable(JsonbAnnotatedElement> clazzElement) {
Class> clazz = clazzElement.getElement();
if (clazz == Optional.class
|| clazz == OptionalDouble.class
- || clazz == OptionalInt.class
+ || clazz == OptionalInt.class
|| clazz == OptionalLong.class) {
return true;
}
@@ -486,18 +542,21 @@ public Map getJsonNumberFormatter(Proper
Map annotationFromPropertyCategorized = getAnnotationFromPropertyCategorized(
JsonbNumberFormat.class,
property);
- if (annotationFromPropertyCategorized.size() == 0) {
- final Optional> propertyRawTypeOptional = ReflectionUtils.getOptionalRawType(property.getPropertyType());
- if (propertyRawTypeOptional.isPresent()) {
- Class> rawType = propertyRawTypeOptional.get();
- if (!Number.class.isAssignableFrom(rawType)) {
- return new HashMap<>();
- }
- }
- } else {
- annotationFromPropertyCategorized.forEach((key, annotation) -> result
- .put(key, new JsonbNumberFormatter(annotation.value(), annotation.locale())));
- }
+ // if (annotationFromPropertyCategorized.size() == 0) {
+ // final Optional> propertyRawTypeOptional = ReflectionUtils.getOptionalRawType(property
+ // .getPropertyType());
+ // if (propertyRawTypeOptional.isPresent()) {
+ // Class> rawType = propertyRawTypeOptional.get();
+ // if (!Number.class.isAssignableFrom(rawType)) {
+ // return new HashMap<>();
+ // }
+ // }
+ // } else {
+ // annotationFromPropertyCategorized.forEach((key, annotation) -> result
+ // .put(key, new JsonbNumberFormatter(annotation.value(), annotation.locale())));
+ // }
+ annotationFromPropertyCategorized.forEach((key, annotation) -> result
+ .put(key, new JsonbNumberFormatter(annotation.value(), annotation.locale())));
JsonbNumberFormat classLevelNumberFormatter = findAnnotation(property.getDeclaringClassElement().getAnnotations(),
JsonbNumberFormat.class);
@@ -516,11 +575,9 @@ public Map getJsonNumberFormatter(Proper
* @return formatter instance if {@link JsonbNumberFormat} is present otherwise null
*/
public JsonbNumberFormatter getConstructorNumberFormatter(JsonbAnnotatedElement param) {
- JsonbNumberFormat annotation = param.getAnnotation(JsonbNumberFormat.class);
- if (annotation != null) {
- return new JsonbNumberFormatter(annotation.value(), annotation.locale());
- }
- return null;
+ return param.getAnnotation(JsonbNumberFormat.class)
+ .map(annotation -> new JsonbNumberFormatter(annotation.value(), annotation.locale()))
+ .orElse(null);
}
/**
@@ -530,13 +587,11 @@ public JsonbNumberFormatter getConstructorNumberFormatter(JsonbAnnotatedElement<
* @return formatter instance if {@link JsonbDateFormat} is present otherwise null
*/
public JsonbDateFormatter getConstructorDateFormatter(JsonbAnnotatedElement param) {
- JsonbDateFormat annotation = param.getAnnotation(JsonbDateFormat.class);
- if (annotation != null) {
- return new JsonbDateFormatter(DateTimeFormatter
- .ofPattern(annotation.value(), Locale.forLanguageTag(annotation.locale())),
- annotation.value(), annotation.locale());
- }
- return null;
+ return param.getAnnotation(JsonbDateFormat.class)
+ .map(annotation -> new JsonbDateFormatter(DateTimeFormatter.ofPattern(annotation.value(),
+ Locale.forLanguageTag(annotation.locale())),
+ annotation.value(), annotation.locale()))
+ .orElse(null);
}
/**
@@ -671,7 +726,6 @@ private T findAnnotation(Annotation[] declaredAnnotations
*
* @param target target to check
*/
- @SuppressWarnings("unchecked")
public void checkTransientIncompatible(JsonbAnnotatedElement> target) {
if (target == null) {
return;
@@ -693,7 +747,7 @@ private T getMethodAnnotation(Class annotationClass, J
}
private void collectFromInterfaces(Class annotationClass,
- Class clazz,
+ Class> clazz,
Map, T> collectedAnnotations) {
for (Class> interfaceClass : clazz.getInterfaces()) {
@@ -713,8 +767,7 @@ private void collectFromInterfaces(Class annotationCla
*/
public Set> collectInterfaces(Class> cls) {
Set> collected = new LinkedHashSet<>();
- Queue> toScan = new LinkedList<>();
- toScan.addAll(Arrays.asList(cls.getInterfaces()));
+ Queue> toScan = new LinkedList<>(Arrays.asList(cls.getInterfaces()));
Class> nextIfc;
while ((nextIfc = toScan.poll()) != null) {
collected.add(nextIfc);
@@ -729,18 +782,83 @@ public Set> collectInterfaces(Class> cls) {
* @param clsElement Element to process.
* @return Populated {@link ClassCustomization} instance.
*/
- public ClassCustomization introspectCustomization(JsonbAnnotatedElement> clsElement) {
- final ClassCustomizationBuilder builder = new ClassCustomizationBuilder();
- builder.setNillable(isClassNillable(clsElement));
- builder.setDateFormatter(getJsonbDateFormat(clsElement));
- builder.setNumberFormatter(getJsonbNumberFormat(clsElement));
- builder.setCreator(getCreator(clsElement.getElement()));
- builder.setPropertyOrder(getPropertyOrder(clsElement));
- builder.setAdapterInfo(getAdapterBinding(clsElement));
- builder.setSerializerBinding(getSerializerBinding(clsElement));
- builder.setDeserializerBinding(getDeserializerBinding(clsElement));
- builder.setPropertyVisibilityStrategy(getPropertyVisibilityStrategy(clsElement.getElement()));
- return builder.buildClassCustomization();
+ public ClassCustomization introspectCustomization(JsonbAnnotatedElement> clsElement,
+ ClassCustomization parentCustomization) {
+ return ClassCustomization.builder()
+ .nillable(isClassNillable(clsElement))
+ .dateTimeFormatter(getJsonbDateFormat(clsElement))
+ .numberFormatter(getJsonbNumberFormat(clsElement))
+ .creator(getCreator(clsElement.getElement()))
+ .propertyOrder(getPropertyOrder(clsElement))
+ .adapterBinding(getAdapterBinding(clsElement))
+ .serializerBinding(getSerializerBinding(clsElement))
+ .deserializerBinding(getDeserializerBinding(clsElement))
+ .propertyVisibilityStrategy(getPropertyVisibilityStrategy(clsElement.getElement()))
+ .polymorphismConfig(getPolymorphismConfig(clsElement, parentCustomization))
+ .build();
+ }
+
+ private TypeInheritanceConfiguration getPolymorphismConfig(JsonbAnnotatedElement> clsElement,
+ ClassCustomization parentCustomization) {
+ TypeInheritanceConfiguration parentPolyConfig = parentCustomization.getPolymorphismConfig();
+
+ LinkedList> annotations = clsElement.getAnnotations(JsonbTypeInfo.class);
+
+ if (parentPolyConfig != null) {
+ if (annotations.size() == 1 && annotations.getFirst().isInherited()) {
+ throw new JsonbException("CHANGE");
+ } else if (annotations.size() > 1) {
+ throw new JsonbException("CHANGE");
+ } else if (annotations.isEmpty()) {
+ return TypeInheritanceConfiguration.builder().of(parentPolyConfig)
+ .inherited(true)
+ .build();
+ }
+ }
+ ListIterator> listIterator = annotations.listIterator(annotations.size());
+ while (listIterator.hasPrevious()) {
+ AnnotationWrapper> annotationWrapper = listIterator.previous();
+ JsonbTypeInfo annotation = (JsonbTypeInfo) annotationWrapper.getAnnotation();
+ TypeInheritanceConfiguration.Builder builder = TypeInheritanceConfiguration.builder();
+ builder.fieldName(annotation.key())
+ .inherited(annotationWrapper.isInherited())
+ .parentConfig(parentPolyConfig)
+ .definedType(annotationWrapper.getDefinedType());
+ for (JsonbSubtype subType : annotation.value()) {
+ if (!annotationWrapper.getDefinedType().isAssignableFrom(subType.type())) {
+ throw new JsonbException("Defined alias type has to be child of the current type. JsonbSubType on the "
+ + annotationWrapper.getDefinedType().getName()
+ + " defines incorrect alias "
+ + subType);
+ }
+ builder.alias(subType.type(), subType.alias());
+ }
+ parentPolyConfig = builder.build();
+ }
+
+ checkDuplicityPolymorphicPropertyNames(parentPolyConfig);
+
+ return parentPolyConfig;
+ }
+
+ private void checkDuplicityPolymorphicPropertyNames(TypeInheritanceConfiguration typeInheritanceConfiguration) {
+ if (typeInheritanceConfiguration == null) {
+ return;
+ }
+ Map keyNames = new HashMap<>();
+ TypeInheritanceConfiguration current = typeInheritanceConfiguration;
+ while (current != null) {
+ String fieldName = current.getFieldName();
+ if (keyNames.containsKey(fieldName)) {
+ TypeInheritanceConfiguration conflicting = keyNames.get(fieldName);
+ throw new JsonbException("One polymorphic chain cannot have two conflicting property names. "
+ + "Polymorphic type defined on the type "
+ + conflicting.getDefinedType().getName() + " and "
+ + current.getDefinedType().getName() + " have conflicting property name");
+ }
+ keyNames.put(fieldName, current);
+ current = current.getParentConfig();
+ }
}
/**
@@ -762,26 +880,99 @@ public Class> getImplementationClass(Property property) {
*/
public JsonbAnnotatedElement> collectAnnotations(Class> clazz) {
JsonbAnnotatedElement> classElement = new JsonbAnnotatedElement<>(clazz);
-
- if (DefaultSerializers.isKnownType(clazz)) {
+
+ if (BuiltInTypes.isKnownType(clazz)) {
return classElement;
}
- for (Class> ifc : collectInterfaces(clazz)) {
- addIfNotPresent(classElement, ifc.getDeclaredAnnotations());
+ Map, LinkedList>> interfaceAnnotations
+ = collectInterfaceAnnotations(clazz, clazz);
+ for (LinkedList> wrappers : interfaceAnnotations.values()) {
+ for (AnnotationWrapper> wrapper : wrappers) {
+ if (classElement.getAnnotation(wrapper.getAnnotation().annotationType()).isEmpty()
+ || REPEATABLE.contains(wrapper.getAnnotation().annotationType())) {
+ classElement.putAnnotationWrapper(wrapper);
+ }
+ }
}
if (!clazz.isPrimitive() && !clazz.isArray() && (clazz.getPackage() != null)) {
- addIfNotPresent(classElement, clazz.getPackage().getAnnotations());
+ addIfNotPresent(classElement, null, clazz.getPackage().getAnnotations());
}
return classElement;
}
- private void addIfNotPresent(JsonbAnnotatedElement> element, Annotation... annotations) {
+ private Map, LinkedList>> collectInterfaceAnnotations(Class> currentInterf,
+ Class> processed) {
+ Map, LinkedList>> map = new HashMap<>();
+ if (!currentInterf.equals(processed)) {
+ for (Annotation annotation : currentInterf.getDeclaredAnnotations()) {
+ map.computeIfAbsent(annotation.annotationType(), aClass -> new LinkedList<>())
+ .add(new AnnotationWrapper<>(annotation, true, currentInterf));
+ }
+ }
+
+ Map, LinkedList>> parents = new HashMap<>();
+ for (Class> parentInterf : currentInterf.getInterfaces()) {
+ Map, LinkedList>> current = collectInterfaceAnnotations(parentInterf,
+ processed);
+ current.entrySet().stream()
+ .filter(entry -> !parents.containsKey(entry.getKey()) || REPEATABLE.contains(entry.getKey()))
+ .peek(entry -> {
+ if (parents.containsKey(entry.getKey())) {
+ throw new JsonbException("CHANGE THIS EXCEPTION");
+ }
+ })
+ .forEach(entry -> {
+ parents.computeIfAbsent(entry.getKey(), aClass -> new LinkedList<>()).addAll(entry.getValue());
+ map.computeIfAbsent(entry.getKey(), aClass -> new LinkedList<>()).addAll(entry.getValue());
+ });
+ }
+ return map;
+ }
+
+ // private void collectParentInterfaceAnnotations(Class> currentInterf,
+ // Map, LinkedList> overall) {
+ // Map, LinkedList> parents = new HashMap<>();
+ // for (Class> parentInterf : currentInterf.getInterfaces()) {
+ // collectParentInterfaceAnnotations(parentInterf, );
+ // current.entrySet().stream()
+ // .filter(entry -> parents.containsKey(entry.getKey()) || REPEATABLE.contains(entry.getKey()))
+ // .peek(entry -> {
+ // if (parents.containsKey(entry.getKey())) {
+ // throw new JsonbException("CHANGE THIS EXCEPTION");
+ // }
+ // })
+ // .forEach(entry -> {
+ // parents.computeIfAbsent(entry.getKey(), aClass -> new LinkedList<>()).addAll(entry.getValue());
+ // map.computeIfAbsent(entry.getKey(), aClass -> new LinkedList<>()).addAll(entry.getValue());
+ // });
+ // }
+ // if (currentInterf.isInterface()) {
+ // for (Annotation annotation : currentInterf.getDeclaredAnnotations()) {
+ // map.computeIfAbsent(annotation.annotationType(), aClass -> new LinkedList<>()).add(annotation);
+ // }
+ // }
+ // return map;
+ // }
+
+ private void addIfNotPresent(JsonbAnnotatedElement> element, Class> definedType, Annotation... annotations) {
for (Annotation annotation : annotations) {
- if (element.getAnnotation(annotation.annotationType()) == null) {
- element.putAnnotation(annotation);
+ if (element.getAnnotation(annotation.annotationType()).isEmpty()
+ || REPEATABLE.contains(annotation.annotationType())) {
+ element.putAnnotation(annotation, true, definedType);
}
}
}
+
+ public boolean requiredParameters(Executable executable, JsonbAnnotatedElement annotated) {
+ return jsonbContext.getConfigProperties().hasRequiredCreatorParameters();
+ // if (OPTIONALS.contains(annotated.getElement().getType())) {
+ // return false;
+ // }
+ // return annotated.getAnnotation(JsonbRequired.class)
+ // .or(() -> Optional.ofNullable(executable.getAnnotation(JsonbRequired.class)))
+ // .map(JsonbRequired::value)
+ // .orElseGet(() -> jsonbContext.getConfigProperties().hasRequiredCreatorParameters());
+ }
}
diff --git a/src/main/java/org/eclipse/yasson/internal/BuiltInTypes.java b/src/main/java/org/eclipse/yasson/internal/BuiltInTypes.java
new file mode 100644
index 000000000..6aa12b03a
--- /dev/null
+++ b/src/main/java/org/eclipse/yasson/internal/BuiltInTypes.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2021, 2022 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0,
+ * or the Eclipse Distribution License v. 1.0 which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
+ */
+
+package org.eclipse.yasson.internal;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.net.URI;
+import java.net.URL;
+import java.nio.file.Path;
+import java.time.Duration;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.OffsetDateTime;
+import java.time.OffsetTime;
+import java.time.Period;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+import java.util.Calendar;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Optional;
+import java.util.OptionalDouble;
+import java.util.OptionalInt;
+import java.util.OptionalLong;
+import java.util.Set;
+import java.util.TimeZone;
+import java.util.UUID;
+
+import javax.xml.datatype.XMLGregorianCalendar;
+
+import jakarta.json.JsonValue;
+
+/**
+ * Types which are supported by the Yasson by default.
+ */
+public class BuiltInTypes {
+
+ private static final Set> BUILD_IN_SUPPORT;
+
+ static {
+ Set> buildInTypes = new HashSet<>();
+ buildInTypes.add(Byte.class);
+ buildInTypes.add(Byte.TYPE);
+ buildInTypes.add(BigDecimal.class);
+ buildInTypes.add(BigInteger.class);
+ buildInTypes.add(Boolean.class);
+ buildInTypes.add(Boolean.TYPE);
+ buildInTypes.add(Calendar.class);
+ buildInTypes.add(Character.class);
+ buildInTypes.add(Character.TYPE);
+ buildInTypes.add(Date.class);
+ buildInTypes.add(Double.class);
+ buildInTypes.add(Double.TYPE);
+ buildInTypes.add(Duration.class);
+ buildInTypes.add(Float.class);
+ buildInTypes.add(Float.TYPE);
+ buildInTypes.add(Integer.class);
+ buildInTypes.add(Integer.TYPE);
+ buildInTypes.add(Instant.class);
+ buildInTypes.add(LocalDateTime.class);
+ buildInTypes.add(LocalDate.class);
+ buildInTypes.add(LocalTime.class);
+ buildInTypes.add(Long.class);
+ buildInTypes.add(Long.TYPE);
+ buildInTypes.add(Number.class);
+ buildInTypes.add(OffsetDateTime.class);
+ buildInTypes.add(OffsetTime.class);
+ buildInTypes.add(OptionalDouble.class);
+ buildInTypes.add(OptionalInt.class);
+ buildInTypes.add(OptionalLong.class);
+ buildInTypes.add(Path.class);
+ buildInTypes.add(Period.class);
+ buildInTypes.add(Short.class);
+ buildInTypes.add(Short.TYPE);
+ buildInTypes.add(String.class);
+ buildInTypes.add(TimeZone.class);
+ buildInTypes.add(URI.class);
+ buildInTypes.add(URL.class);
+ buildInTypes.add(UUID.class);
+ if (isClassAvailable("javax.xml.datatype.XMLGregorianCalendar")) {
+ buildInTypes.add(XMLGregorianCalendar.class);
+ }
+ buildInTypes.add(ZonedDateTime.class);
+ buildInTypes.add(ZoneId.class);
+ buildInTypes.add(ZoneOffset.class);
+ if (isClassAvailable("java.sql.Date")) {
+ buildInTypes.add(java.sql.Date.class);
+ buildInTypes.add(java.sql.Timestamp.class);
+ }
+ BUILD_IN_SUPPORT = Set.copyOf(buildInTypes);
+ }
+
+ private BuiltInTypes() {
+ throw new IllegalStateException("Util class cannot be instantiated");
+ }
+
+ /**
+ * Check whether the class is available.
+ *
+ * @param className name of the checked class
+ * @return true if available, otherwise false
+ */
+ public static boolean isClassAvailable(String className) {
+ try {
+ Class.forName(className);
+ return true;
+ } catch (ClassNotFoundException | LinkageError e) {
+ return false;
+ }
+ }
+
+ /**
+ * Whether the type is a supported type by default.
+ *
+ * @param clazz type to check
+ * @return whether is supported
+ */
+ public static boolean isKnownType(Class> clazz) {
+ boolean knownContainerValueType = Collection.class.isAssignableFrom(clazz)
+ || Map.class.isAssignableFrom(clazz)
+ || JsonValue.class.isAssignableFrom(clazz)
+ || Optional.class.isAssignableFrom(clazz)
+ || clazz.isArray();
+
+ return knownContainerValueType || findIfClassIsSupported(clazz);
+ }
+
+ private static boolean findIfClassIsSupported(Class> clazz) {
+ Class> current = clazz;
+ do {
+ if (BUILD_IN_SUPPORT.contains(current)) {
+ return true;
+ }
+ current = current.getSuperclass();
+ } while (current != null);
+ return false;
+ }
+}
diff --git a/src/main/java/org/eclipse/yasson/internal/ClassParser.java b/src/main/java/org/eclipse/yasson/internal/ClassParser.java
index d332832e5..4adce6581 100644
--- a/src/main/java/org/eclipse/yasson/internal/ClassParser.java
+++ b/src/main/java/org/eclipse/yasson/internal/ClassParser.java
@@ -170,8 +170,8 @@ private void parseIfaceMethodAnnotations(Class> ifc,
? property.getGetterElement() : property.getSetterElement();
//Only push iface annotations if not overridden on impl classes
for (Annotation ann : method.getDeclaredAnnotations()) {
- if (methodElement.getAnnotation(ann.annotationType()) == null) {
- methodElement.putAnnotation(ann);
+ if (methodElement.getAnnotation(ann.annotationType()).isEmpty()) {
+ methodElement.putAnnotation(ann, true, null);
}
}
}
@@ -322,8 +322,9 @@ private List getSortedParentProperties(ClassModel classModel,
} else {
//merge
final Property merged = mergeProperty(current, parentProp, classElement);
- PropertyVisibilityStrategy propertyVisibilityStrategy = classModel.getClassCustomization().getPropertyVisibilityStrategy();
-
+ PropertyVisibilityStrategy propertyVisibilityStrategy = classModel.getClassCustomization()
+ .getPropertyVisibilityStrategy();
+
if (PropertyModel.isPropertyReadable(current.getField(), current.getGetter(), propertyVisibilityStrategy)) {
classProperties.replace(current.getName(), merged);
} else {
@@ -364,7 +365,9 @@ private static Method selectMostSpecificNonDefaultMethod(Method current, Method
&& !parent.isDefault() ? parent : current) : parent);
}
- private static Property mergeProperty(Property current, PropertyModel parentProp, JsonbAnnotatedElement> classElement) {
+ private static Property mergeProperty(Property current,
+ PropertyModel parentProp,
+ JsonbAnnotatedElement> classElement) {
Field field = current.getField() != null
? current.getField() : parentProp.getField();
Method getter = selectMostSpecificNonDefaultMethod(current.getGetter(),
diff --git a/src/main/java/org/eclipse/yasson/internal/ComponentMatcher.java b/src/main/java/org/eclipse/yasson/internal/ComponentMatcher.java
index 3457ef27a..b4a2cf831 100644
--- a/src/main/java/org/eclipse/yasson/internal/ComponentMatcher.java
+++ b/src/main/java/org/eclipse/yasson/internal/ComponentMatcher.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, 2021 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2022 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
@@ -15,6 +15,7 @@
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
+import java.util.LinkedList;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
@@ -65,14 +66,14 @@ public class ComponentMatcher {
void init() {
final JsonbSerializer>[] serializers = (JsonbSerializer>[]) jsonbContext.getConfig()
.getProperty(JsonbConfig.SERIALIZERS).orElseGet(() -> new JsonbSerializer>[] {});
- for (JsonbSerializer serializer : serializers) {
- SerializerBinding serializerBinding = introspectSerializerBinding(serializer.getClass(), serializer);
+ for (JsonbSerializer> serializer : serializers) {
+ SerializerBinding> serializerBinding = introspectSerializerBinding(serializer.getClass(), serializer);
addSerializer(serializerBinding.getBindingType(), serializerBinding);
}
final JsonbDeserializer>[] deserializers = (JsonbDeserializer>[]) jsonbContext.getConfig()
.getProperty(JsonbConfig.DESERIALIZERS).orElseGet(() -> new JsonbDeserializer>[] {});
- for (JsonbDeserializer deserializer : deserializers) {
- DeserializerBinding deserializerBinding = introspectDeserializerBinding(deserializer.getClass(), deserializer);
+ for (JsonbDeserializer> deserializer : deserializers) {
+ DeserializerBinding> deserializerBinding = introspectDeserializerBinding(deserializer.getClass(), deserializer);
addDeserializer(deserializerBinding.getBindingType(), deserializerBinding);
}
@@ -89,7 +90,7 @@ private ComponentBindings getBindingInfo(Type type) {
.compute(type, (type1, bindingInfo) -> bindingInfo != null ? bindingInfo : new ComponentBindings(type1));
}
- private void addSerializer(Type bindingType, SerializerBinding serializer) {
+ private void addSerializer(Type bindingType, SerializerBinding> serializer) {
userComponents.computeIfPresent(bindingType, (type, bindings) -> {
if (bindings.getSerializer() != null) {
return bindings;
@@ -99,7 +100,7 @@ private void addSerializer(Type bindingType, SerializerBinding serializer) {
});
}
- private void addDeserializer(Type bindingType, DeserializerBinding deserializer) {
+ private void addDeserializer(Type bindingType, DeserializerBinding> deserializer) {
userComponents.computeIfPresent(bindingType, (type, bindings) -> {
if (bindings.getDeserializer() != null) {
return bindings;
@@ -243,7 +244,7 @@ private boolean matches(Type runtimeType, Type componentBindingType) {
}
if (componentBindingType instanceof Class && runtimeType instanceof Class) {
- return ((Class>) componentBindingType).isAssignableFrom((Class) runtimeType);
+ return ((Class>) componentBindingType).isAssignableFrom((Class>) runtimeType);
}
//don't try to runtime generic scan if not needed
@@ -350,8 +351,9 @@ private Type resolveTypeArg(Type adapterTypeArg, Type adapterType) {
if (adapterTypeArg instanceof ParameterizedType) {
return ReflectionUtils.resolveTypeArguments((ParameterizedType) adapterTypeArg, adapterType);
} else if (adapterTypeArg instanceof TypeVariable) {
- return ReflectionUtils
- .resolveItemVariableType(new RuntimeTypeHolder(null, adapterType), (TypeVariable>) adapterTypeArg, true);
+ LinkedList chain = new LinkedList<>();
+ chain.add(adapterType);
+ return ReflectionUtils.resolveItemVariableType(chain, (TypeVariable>) adapterTypeArg, true);
} else {
return adapterTypeArg;
}
diff --git a/src/main/java/org/eclipse/yasson/internal/ConstructorPropertiesAnnotationIntrospector.java b/src/main/java/org/eclipse/yasson/internal/ConstructorPropertiesAnnotationIntrospector.java
index c3da9062a..7d3fe87db 100644
--- a/src/main/java/org/eclipse/yasson/internal/ConstructorPropertiesAnnotationIntrospector.java
+++ b/src/main/java/org/eclipse/yasson/internal/ConstructorPropertiesAnnotationIntrospector.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, 2022 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
@@ -31,7 +31,7 @@ class ConstructorPropertiesAnnotationIntrospector {
private final JsonbContext jsonbContext;
private final AnnotationFinder constructorProperties;
- public static final ConstructorPropertiesAnnotationIntrospector forContext(JsonbContext jsonbContext) {
+ public static ConstructorPropertiesAnnotationIntrospector forContext(JsonbContext jsonbContext) {
return new ConstructorPropertiesAnnotationIntrospector(jsonbContext, AnnotationFinder.findConstructorProperties());
}
@@ -83,7 +83,7 @@ private JsonbCreator createJsonbCreator(Executable executable, String[] properti
CreatorModel[] creatorModels = new CreatorModel[parameters.length];
for (int i = 0; i < parameters.length; i++) {
final Parameter parameter = parameters[i];
- creatorModels[i] = new CreatorModel(properties[i], parameter, jsonbContext);
+ creatorModels[i] = new CreatorModel(properties[i], parameter, executable, jsonbContext);
}
return new JsonbCreator(executable, creatorModels);
}
diff --git a/src/main/java/org/eclipse/yasson/internal/DeserializationContextImpl.java b/src/main/java/org/eclipse/yasson/internal/DeserializationContextImpl.java
new file mode 100644
index 000000000..6ca0a8398
--- /dev/null
+++ b/src/main/java/org/eclipse/yasson/internal/DeserializationContextImpl.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2021, 2022 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0,
+ * or the Eclipse Distribution License v. 1.0 which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
+ */
+
+package org.eclipse.yasson.internal;
+
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Logger;
+
+import jakarta.json.bind.JsonbException;
+import jakarta.json.bind.serializer.DeserializationContext;
+import jakarta.json.stream.JsonParser;
+
+import org.eclipse.yasson.internal.deserializer.ModelDeserializer;
+import org.eclipse.yasson.internal.model.customization.ClassCustomization;
+import org.eclipse.yasson.internal.model.customization.Customization;
+import org.eclipse.yasson.internal.properties.MessageKeys;
+import org.eclipse.yasson.internal.properties.Messages;
+
+/**
+ * Deserialization context implementation.
+ */
+public class DeserializationContextImpl extends ProcessingContext implements DeserializationContext {
+
+ private static final Logger LOGGER = Logger.getLogger(DeserializationContextImpl.class.getName());
+
+ private final List delayedSetters = new ArrayList<>();
+ private JsonParser.Event lastValueEvent;
+ private Customization customization = ClassCustomization.empty();
+ private Object instance;
+
+ /**
+ * Parent instance for marshaller and unmarshaller.
+ *
+ * @param jsonbContext context of Jsonb
+ */
+ public DeserializationContextImpl(JsonbContext jsonbContext) {
+ super(jsonbContext);
+ }
+
+ /**
+ * Create new instance based on previous context.
+ *
+ * @param context previous deserialization context
+ */
+ public DeserializationContextImpl(DeserializationContextImpl context) {
+ super(context.getJsonbContext());
+ this.lastValueEvent = context.lastValueEvent;
+ }
+
+ /**
+ * Return instance of currently deserialized type.
+ *
+ * @return null if instance has not been created yet
+ */
+ public Object getInstance() {
+ return instance;
+ }
+
+ /**
+ * Set currently deserialized type instance.
+ *
+ * @param instance deserialized type instance
+ */
+ public void setInstance(Object instance) {
+ this.instance = instance;
+ }
+
+ /**
+ * Return the list of deferred deserializers.
+ *
+ * @return list of deferred deserializers
+ */
+ public List getDeferredDeserializers() {
+ return delayedSetters;
+ }
+
+ /**
+ * Return last obtained {@link JsonParser.Event} event.
+ *
+ * @return last obtained event
+ */
+ public JsonParser.Event getLastValueEvent() {
+ return lastValueEvent;
+ }
+
+ /**
+ * Set last obtained {@link JsonParser.Event} event.
+ *
+ * @param lastValueEvent last obtained event
+ */
+ public void setLastValueEvent(JsonParser.Event lastValueEvent) {
+ this.lastValueEvent = lastValueEvent;
+ }
+
+ /**
+ * Return customization used by currently processed user defined deserializer.
+ *
+ * @return currently used customization
+ */
+ public Customization getCustomization() {
+ return customization;
+ }
+
+ /**
+ * Set customization used by currently processed user defined deserializer.
+ *
+ * @param customization currently used customization
+ */
+ public void setCustomization(Customization customization) {
+ this.customization = customization;
+ }
+
+ @Override
+ public T deserialize(Class clazz, JsonParser parser) {
+ return deserializeItem(clazz, parser);
+ }
+
+ @Override
+ public T deserialize(Type type, JsonParser parser) {
+ return deserializeItem(type, parser);
+ }
+
+ @SuppressWarnings("unchecked")
+ private T deserializeItem(Type type, JsonParser parser) {
+ try {
+ if (lastValueEvent == null) {
+ lastValueEvent = parser.next();
+ checkState();
+ }
+ ModelDeserializer modelDeserializer = getJsonbContext().getChainModelCreator().deserializerChain(type);
+ return (T) modelDeserializer.deserialize(parser, this);
+ } catch (JsonbException e) {
+ LOGGER.severe(e.getMessage());
+ throw e;
+ } catch (Exception e) {
+ LOGGER.severe(e.getMessage());
+ throw new JsonbException(Messages.getMessage(MessageKeys.INTERNAL_ERROR, e.getMessage()), e);
+ }
+ }
+
+ private void checkState() {
+ if (lastValueEvent == JsonParser.Event.KEY_NAME) {
+ throw new JsonbException("JsonParser has incorrect position as the first event: KEY_NAME");
+ }
+ }
+
+}
diff --git a/src/main/java/org/eclipse/yasson/internal/InstanceCreator.java b/src/main/java/org/eclipse/yasson/internal/InstanceCreator.java
index 58f177cbb..11173bd70 100644
--- a/src/main/java/org/eclipse/yasson/internal/InstanceCreator.java
+++ b/src/main/java/org/eclipse/yasson/internal/InstanceCreator.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, 2022 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
@@ -28,13 +28,7 @@
*/
public class InstanceCreator {
- private static final InstanceCreator INSTANCE = new InstanceCreator();
-
- static InstanceCreator getSingleton() {
- return INSTANCE;
- }
-
- private static final Map CREATORS = new HashMap<>();
+ private static final Map, Supplier>> CREATORS = new HashMap<>();
static {
CREATORS.put(ArrayList.class, ArrayList::new);
@@ -46,9 +40,7 @@ static InstanceCreator getSingleton() {
}
private InstanceCreator() {
- if (INSTANCE != null) {
- throw new IllegalStateException("This class should never be instantiated");
- }
+ throw new IllegalStateException("This class should never be instantiated");
}
/**
@@ -60,7 +52,7 @@ private InstanceCreator() {
*/
@SuppressWarnings("unchecked")
public static T createInstance(Class tClass) {
- Supplier creator = CREATORS.get(tClass);
+ Supplier creator = (Supplier) CREATORS.get(tClass);
//No worries for race conditions here, instance may be replaced during first attempt.
if (creator == null) {
Constructor constructor = ReflectionUtils.getDefaultConstructor(tClass, true);
diff --git a/src/main/java/org/eclipse/yasson/internal/JsonBinding.java b/src/main/java/org/eclipse/yasson/internal/JsonBinding.java
index 531ebf1e7..c15b7ebbf 100644
--- a/src/main/java/org/eclipse/yasson/internal/JsonBinding.java
+++ b/src/main/java/org/eclipse/yasson/internal/JsonBinding.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2022 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
@@ -20,9 +20,7 @@
import java.io.Writer;
import java.lang.reflect.Type;
import java.nio.charset.Charset;
-import java.util.HashMap;
import java.util.Map;
-import java.util.Optional;
import java.util.Set;
import jakarta.json.JsonStructure;
@@ -35,8 +33,6 @@
import org.eclipse.yasson.YassonJsonb;
import org.eclipse.yasson.internal.jsonstructure.JsonGeneratorToStructureAdapter;
import org.eclipse.yasson.internal.jsonstructure.JsonStructureToParserAdapter;
-import org.eclipse.yasson.internal.properties.MessageKeys;
-import org.eclipse.yasson.internal.properties.Messages;
/**
* Implementation of Jsonb interface.
@@ -50,80 +46,79 @@ public class JsonBinding implements YassonJsonb {
Set> eagerInitClasses = this.jsonbContext.getConfigProperties().getEagerInitClasses();
for (Class> eagerInitClass : eagerInitClasses) {
// Eagerly initialize requested ClassModels and Serializers
- jsonbContext.getMappingContext().getOrCreateClassModel(eagerInitClass);
- new Marshaller(jsonbContext).getRootSerializer(eagerInitClass);
+ jsonbContext.getChainModelCreator().deserializerChain(eagerInitClass);
+ jsonbContext.getSerializationModelCreator().serializerChain(eagerInitClass, true, true);
}
}
- private T deserialize(final Type type, final JsonParser parser, final Unmarshaller unmarshaller) {
+ private T deserialize(final Type type, final JsonParser parser, final DeserializationContextImpl unmarshaller) {
return unmarshaller.deserialize(type, parser);
}
@Override
public T fromJson(String str, Class type) throws JsonbException {
- final JsonParser parser = new JsonbRiParser(jsonbContext.getJsonProvider().createParser(new StringReader(str)));
- final Unmarshaller unmarshaller = new Unmarshaller(jsonbContext);
+ final JsonParser parser = jsonbContext.getJsonProvider().createParser(new StringReader(str));
+ final DeserializationContextImpl unmarshaller = new DeserializationContextImpl(jsonbContext);
return deserialize(type, parser, unmarshaller);
}
@Override
public T fromJson(String str, Type type) throws JsonbException {
- JsonParser parser = new JsonbRiParser(jsonbContext.getJsonProvider().createParser(new StringReader(str)));
- Unmarshaller unmarshaller = new Unmarshaller(jsonbContext);
+ JsonParser parser = jsonbContext.getJsonProvider().createParser(new StringReader(str));
+ DeserializationContextImpl unmarshaller = new DeserializationContextImpl(jsonbContext);
return deserialize(type, parser, unmarshaller);
}
@Override
public T fromJson(Reader reader, Class type) throws JsonbException {
- JsonParser parser = new JsonbRiParser(jsonbContext.getJsonProvider().createParser(reader));
- Unmarshaller unmarshaller = new Unmarshaller(jsonbContext);
+ JsonParser parser = jsonbContext.getJsonProvider().createParser(reader);
+ DeserializationContextImpl unmarshaller = new DeserializationContextImpl(jsonbContext);
return deserialize(type, parser, unmarshaller);
}
@Override
public T fromJson(Reader reader, Type type) throws JsonbException {
- JsonParser parser = new JsonbRiParser(jsonbContext.getJsonProvider().createParser(reader));
- Unmarshaller unmarshaller = new Unmarshaller(jsonbContext);
+ JsonParser parser = jsonbContext.getJsonProvider().createParser(reader);
+ DeserializationContextImpl unmarshaller = new DeserializationContextImpl(jsonbContext);
return deserialize(type, parser, unmarshaller);
}
@Override
public T fromJson(InputStream stream, Class clazz) throws JsonbException {
- Unmarshaller unmarshaller = new Unmarshaller(jsonbContext);
+ DeserializationContextImpl unmarshaller = new DeserializationContextImpl(jsonbContext);
return deserialize(clazz, inputStreamParser(stream), unmarshaller);
}
@Override
public T fromJson(InputStream stream, Type type) throws JsonbException {
- Unmarshaller unmarshaller = new Unmarshaller(jsonbContext);
+ DeserializationContextImpl unmarshaller = new DeserializationContextImpl(jsonbContext);
return deserialize(type, inputStreamParser(stream), unmarshaller);
}
@Override
public T fromJsonStructure(JsonStructure jsonStructure, Class type) throws JsonbException {
- JsonParser parser = new JsonbRiParser(new JsonStructureToParserAdapter(jsonStructure));
- return deserialize(type, parser, new Unmarshaller(jsonbContext));
+ JsonParser parser = new JsonStructureToParserAdapter(jsonStructure);
+ return deserialize(type, parser, new DeserializationContextImpl(jsonbContext));
}
@Override
public T fromJsonStructure(JsonStructure jsonStructure, Type runtimeType) throws JsonbException {
- JsonParser parser = new JsonbRiParser(new JsonStructureToParserAdapter(jsonStructure));
- return deserialize(runtimeType, parser, new Unmarshaller(jsonbContext));
+ JsonParser parser = new JsonStructureToParserAdapter(jsonStructure);
+ return deserialize(runtimeType, parser, new DeserializationContextImpl(jsonbContext));
}
private JsonParser inputStreamParser(InputStream stream) {
- return new JsonbRiParser(jsonbContext.getJsonProvider()
- .createParserFactory(createJsonpProperties(jsonbContext.getConfig()))
- .createParser(stream,
- Charset.forName((String) jsonbContext.getConfig()
- .getProperty(JsonbConfig.ENCODING).orElse("UTF-8"))));
+ return jsonbContext.getJsonParserFactory()
+ .createParser(stream,
+ Charset.forName((String) jsonbContext.getConfig()
+ .getProperty(JsonbConfig.ENCODING).orElse("UTF-8")));
}
@Override
public String toJson(Object object) throws JsonbException {
StringWriter writer = new StringWriter();
final JsonGenerator generator = writerGenerator(writer);
- new Marshaller(jsonbContext).marshall(object, generator);
+ new SerializationContextImpl(jsonbContext).marshall(object, generator);
return writer.toString();
}
@@ -131,24 +126,24 @@ public String toJson(Object object) throws JsonbException {
public String toJson(Object object, Type type) throws JsonbException {
StringWriter writer = new StringWriter();
final JsonGenerator generator = writerGenerator(writer);
- new Marshaller(jsonbContext, type).marshall(object, generator);
+ new SerializationContextImpl(jsonbContext, type).marshall(object, generator);
return writer.toString();
}
@Override
public void toJson(Object object, Writer writer) throws JsonbException {
- final Marshaller marshaller = new Marshaller(jsonbContext);
+ final SerializationContextImpl marshaller = new SerializationContextImpl(jsonbContext);
marshaller.marshallWithoutClose(object, writerGenerator(writer));
}
@Override
public void toJson(Object object, Type type, Writer writer) throws JsonbException {
- final Marshaller marshaller = new Marshaller(jsonbContext, type);
+ final SerializationContextImpl marshaller = new SerializationContextImpl(jsonbContext, type);
marshaller.marshallWithoutClose(object, writerGenerator(writer));
}
private JsonGenerator writerGenerator(Writer writer) {
- Map factoryProperties = createJsonpProperties(jsonbContext.getConfig());
+ Map factoryProperties = jsonbContext.createJsonpProperties(jsonbContext.getConfig());
if (factoryProperties.isEmpty()) {
return jsonbContext.getJsonProvider().createGenerator(writer);
}
@@ -157,44 +152,44 @@ private JsonGenerator writerGenerator(Writer writer) {
@Override
public void toJson(Object object, OutputStream stream) throws JsonbException {
- final Marshaller marshaller = new Marshaller(jsonbContext);
+ final SerializationContextImpl marshaller = new SerializationContextImpl(jsonbContext);
marshaller.marshall(object, streamGenerator(stream));
}
@Override
public void toJson(Object object, Type type, OutputStream stream) throws JsonbException {
- final Marshaller marshaller = new Marshaller(jsonbContext, type);
+ final SerializationContextImpl marshaller = new SerializationContextImpl(jsonbContext, type);
marshaller.marshall(object, streamGenerator(stream));
}
@Override
public T fromJson(JsonParser jsonParser, Class type) throws JsonbException {
- Unmarshaller unmarshaller = new Unmarshaller(jsonbContext);
- return unmarshaller.deserialize(type, new JsonbRiParser(jsonParser));
+ DeserializationContextImpl unmarshaller = new DeserializationContextImpl(jsonbContext);
+ return unmarshaller.deserialize(type, jsonParser);
}
@Override
public T fromJson(JsonParser jsonParser, Type runtimeType) throws JsonbException {
- Unmarshaller unmarshaller = new Unmarshaller(jsonbContext);
- return unmarshaller.deserialize(runtimeType, new JsonbRiParser(jsonParser));
+ DeserializationContextImpl unmarshaller = new DeserializationContextImpl(jsonbContext);
+ return unmarshaller.deserialize(runtimeType, jsonParser);
}
@Override
public void toJson(Object object, JsonGenerator jsonGenerator) throws JsonbException {
- final Marshaller marshaller = new Marshaller(jsonbContext);
+ final SerializationContextImpl marshaller = new SerializationContextImpl(jsonbContext);
marshaller.marshallWithoutClose(object, jsonGenerator);
}
@Override
public void toJson(Object object, Type runtimeType, JsonGenerator jsonGenerator) throws JsonbException {
- final Marshaller marshaller = new Marshaller(jsonbContext, runtimeType);
+ final SerializationContextImpl marshaller = new SerializationContextImpl(jsonbContext, runtimeType);
marshaller.marshallWithoutClose(object, jsonGenerator);
}
@Override
public JsonStructure toJsonStructure(Object object) throws JsonbException {
JsonGeneratorToStructureAdapter structureGenerator = new JsonGeneratorToStructureAdapter(jsonbContext.getJsonProvider());
- final Marshaller marshaller = new Marshaller(jsonbContext);
+ final SerializationContextImpl marshaller = new SerializationContextImpl(jsonbContext);
marshaller.marshall(object, structureGenerator);
return structureGenerator.getRootStructure();
}
@@ -202,13 +197,13 @@ public JsonStructure toJsonStructure(Object object) throws JsonbException {
@Override
public JsonStructure toJsonStructure(Object object, Type runtimeType) throws JsonbException {
JsonGeneratorToStructureAdapter structureGenerator = new JsonGeneratorToStructureAdapter(jsonbContext.getJsonProvider());
- final Marshaller marshaller = new Marshaller(jsonbContext, runtimeType);
+ final SerializationContextImpl marshaller = new SerializationContextImpl(jsonbContext, runtimeType);
marshaller.marshall(object, structureGenerator);
return structureGenerator.getRootStructure();
}
private JsonGenerator streamGenerator(OutputStream stream) {
- Map factoryProperties = createJsonpProperties(jsonbContext.getConfig());
+ Map factoryProperties = jsonbContext.createJsonpProperties(jsonbContext.getConfig());
final String encoding = (String) jsonbContext.getConfig().getProperty(JsonbConfig.ENCODING).orElse("UTF-8");
return jsonbContext.getJsonProvider().createGeneratorFactory(factoryProperties)
.createGenerator(stream, Charset.forName(encoding));
@@ -219,26 +214,4 @@ public void close() throws Exception {
jsonbContext.getComponentInstanceCreator().close();
}
- /**
- * Propagates properties from JsonbConfig to JSONP generator / parser factories.
- *
- * @param jsonbConfig jsonb config
- * @return properties for JSONP generator / parser
- */
- protected Map createJsonpProperties(JsonbConfig jsonbConfig) {
- //JSONP 1.0 actually ignores the value, just checks the key is present. Only set if JsonbConfig.FORMATTING is true.
- final Optional