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 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 property = jsonbConfig.getProperty(JsonbConfig.FORMATTING); - final Map factoryProperties = new HashMap<>(); - if (property.isPresent()) { - final Object value = property.get(); - if (!(value instanceof Boolean)) { - throw new JsonbException(Messages.getMessage(MessageKeys.JSONB_CONFIG_FORMATTING_ILLEGAL_VALUE)); - } - if ((Boolean) value) { - factoryProperties.put(JsonGenerator.PRETTY_PRINTING, Boolean.TRUE); - } - return factoryProperties; - } - return factoryProperties; - } } diff --git a/src/main/java/org/eclipse/yasson/internal/JsonBindingBuilder.java b/src/main/java/org/eclipse/yasson/internal/JsonBindingBuilder.java index e5481c2c4..33725e9b4 100644 --- a/src/main/java/org/eclipse/yasson/internal/JsonBindingBuilder.java +++ b/src/main/java/org/eclipse/yasson/internal/JsonBindingBuilder.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 diff --git a/src/main/java/org/eclipse/yasson/internal/JsonbConfigProperties.java b/src/main/java/org/eclipse/yasson/internal/JsonbConfigProperties.java index 3e2f79c43..5e5e09a3e 100644 --- a/src/main/java/org/eclipse/yasson/internal/JsonbConfigProperties.java +++ b/src/main/java/org/eclipse/yasson/internal/JsonbConfigProperties.java @@ -1,6 +1,6 @@ /* - * Copyright (c) 2017, 2021 Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2019, 2021 Payara Foundation and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2020 Payara Foundation 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 @@ -13,7 +13,6 @@ package org.eclipse.yasson.internal; -import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatterBuilder; import java.time.temporal.ChronoField; import java.util.Arrays; @@ -23,6 +22,7 @@ import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.TreeMap; @@ -42,46 +42,37 @@ import org.eclipse.yasson.internal.model.ReverseTreeMap; import org.eclipse.yasson.internal.model.customization.PropertyOrdering; import org.eclipse.yasson.internal.model.customization.StrategiesProvider; +import org.eclipse.yasson.internal.model.customization.VisibilityStrategiesProvider; import org.eclipse.yasson.internal.properties.MessageKeys; import org.eclipse.yasson.internal.properties.Messages; -import org.eclipse.yasson.internal.serializer.JsonbDateFormatter; -import org.eclipse.yasson.internal.serializer.NullSerializer; /** * Resolved properties from JSONB config. */ +@SuppressWarnings("rawtypes") public class JsonbConfigProperties { - private final JsonbConfig jsonbConfig; + private static final Map> PROPERTY_ORDER_STRATEGY_MAPS = + Map.of(PropertyOrderStrategy.LEXICOGRAPHICAL, TreeMap.class, + PropertyOrderStrategy.REVERSE, ReverseTreeMap.class, + PropertyOrderStrategy.ANY, HashMap.class); + private final JsonbConfig jsonbConfig; private final PropertyVisibilityStrategy propertyVisibilityStrategy; - private final PropertyNamingStrategy propertyNamingStrategy; - private final PropertyOrdering propertyOrdering; - private final JsonbDateFormatter dateFormatter; - private final Locale locale; - private final String binaryDataStrategy; - private final boolean nullable; - private final boolean failOnUnknownProperties; - private final boolean strictIJson; - private final boolean zeroTimeDefaulting; - + private final boolean requiredCreatorParameters; private final Map, Class> userTypeMapping; - private final Class defaultMapImplType; - private final JsonbSerializer nullSerializer; - private final Set> eagerInitClasses; - private final boolean forceMapArraySerializerForNullKeys; /** @@ -105,41 +96,24 @@ public JsonbConfigProperties(JsonbConfig jsonbConfig) { this.defaultMapImplType = initDefaultMapImplType(); this.nullSerializer = initNullSerializer(); this.eagerInitClasses = initEagerInitClasses(); + this.requiredCreatorParameters = initRequiredCreatorParameters(); this.forceMapArraySerializerForNullKeys = initForceMapArraySerializerForNullKeys(); } - private Class initDefaultMapImplType() { - Optional os = getPropertyOrderStrategy(); - if (os.isPresent()) { - switch (os.get()) { - case PropertyOrderStrategy.LEXICOGRAPHICAL: - return TreeMap.class; - case PropertyOrderStrategy.REVERSE: - return ReverseTreeMap.class; - default: - return HashMap.class; - } - } - return HashMap.class; + private Class initDefaultMapImplType() { + //We need to get PropertyOrderStrategy again. This time, if was not set, use ANY to get proper map implementation. + //This is intentional! + String propertyOrder = getConfigProperty(JsonbConfig.PROPERTY_ORDER_STRATEGY, String.class, PropertyOrderStrategy.ANY); + return PROPERTY_ORDER_STRATEGY_MAPS.getOrDefault(propertyOrder, HashMap.class); } private boolean initZeroTimeDefaultingForJavaTime() { - return getBooleanConfigProperty(YassonConfig.ZERO_TIME_PARSE_DEFAULTING, false); + return getConfigProperty(YassonConfig.ZERO_TIME_PARSE_DEFAULTING, Boolean.class, false); } @SuppressWarnings("unchecked") private Map, Class> initUserTypeMapping() { - Optional property = jsonbConfig.getProperty(YassonConfig.USER_TYPE_MAPPING); - if (!property.isPresent()) { - return Collections.emptyMap(); - } - Object result = property.get(); - if (!(result instanceof Map)) { - throw new JsonbException(Messages.getMessage(MessageKeys.JSONB_CONFIG_PROPERTY_INVALID_TYPE, - YassonConfig.USER_TYPE_MAPPING, - Map.class.getSimpleName())); - } - return (Map, Class>) result; + return getConfigProperty(YassonConfig.USER_TYPE_MAPPING, Map.class, Collections.emptyMap()); } private JsonbDateFormatter initDateFormatter(Locale locale) { @@ -147,66 +121,36 @@ private JsonbDateFormatter initDateFormatter(Locale locale) { if (JsonbDateFormat.DEFAULT_FORMAT.equals(dateFormat) || JsonbDateFormat.TIME_IN_MILLIS.equals(dateFormat)) { return new JsonbDateFormatter(dateFormat, locale.toLanguageTag()); } - DateTimeFormatterBuilder builder = new DateTimeFormatterBuilder(); - builder.appendPattern(dateFormat); + DateTimeFormatterBuilder builder = new DateTimeFormatterBuilder().appendPattern(dateFormat); if (isZeroTimeDefaulting()) { builder.parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0); builder.parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0); builder.parseDefaulting(ChronoField.HOUR_OF_DAY, 0); } - DateTimeFormatter dateTimeFormatter = builder.toFormatter(locale); - return new JsonbDateFormatter(dateTimeFormatter, dateFormat, locale.toLanguageTag()); + return new JsonbDateFormatter(builder.toFormatter(locale), dateFormat, locale.toLanguageTag()); } private String getGlobalConfigJsonbDateFormat() { - final Optional formatProperty = jsonbConfig.getProperty(JsonbConfig.DATE_FORMAT); - return formatProperty.map(f -> { - if (!(f instanceof String)) { - throw new JsonbException(Messages.getMessage(MessageKeys.JSONB_CONFIG_PROPERTY_INVALID_TYPE, - JsonbConfig.DATE_FORMAT, - String.class.getSimpleName())); - } - return (String) f; - }).orElse(JsonbDateFormat.DEFAULT_FORMAT); + return getConfigProperty(JsonbConfig.DATE_FORMAT, String.class, JsonbDateFormat.DEFAULT_FORMAT); } private Consumer> initOrderStrategy() { - Optional strategy = getPropertyOrderStrategy(); - - return strategy.map(StrategiesProvider::getOrderingFunction) - .orElseGet(() -> StrategiesProvider - .getOrderingFunction(PropertyOrderStrategy.LEXICOGRAPHICAL)); //default by spec - } - - private Optional getPropertyOrderStrategy() { - final Optional property = jsonbConfig.getProperty(JsonbConfig.PROPERTY_ORDER_STRATEGY); - if (property.isPresent()) { - final Object strategy = property.get(); - if (!(strategy instanceof String)) { - throw new JsonbException(Messages.getMessage(MessageKeys.PROPERTY_ORDER, strategy)); - } - switch ((String) strategy) { - case PropertyOrderStrategy.LEXICOGRAPHICAL: - case PropertyOrderStrategy.REVERSE: - case PropertyOrderStrategy.ANY: - return Optional.of((String) strategy); - default: - throw new JsonbException(Messages.getMessage(MessageKeys.PROPERTY_ORDER, strategy)); - } - } - return Optional.empty(); + return StrategiesProvider.getOrderingFunction(getPropertyOrderStrategy()); + } + + private String getPropertyOrderStrategy() { + return getConfigProperty(JsonbConfig.PROPERTY_ORDER_STRATEGY, String.class, PropertyOrderStrategy.LEXICOGRAPHICAL); } private PropertyNamingStrategy initPropertyNamingStrategy() { final Optional property = jsonbConfig.getProperty(JsonbConfig.PROPERTY_NAMING_STRATEGY); - if (!property.isPresent()) { + if (property.isEmpty()) { return StrategiesProvider.getPropertyNamingStrategy(PropertyNamingStrategy.IDENTITY); } Object propertyNamingStrategy = property.get(); if (propertyNamingStrategy instanceof String) { return StrategiesProvider.getPropertyNamingStrategy((String) propertyNamingStrategy); - } - if (!(propertyNamingStrategy instanceof PropertyNamingStrategy)) { + } else if (!(propertyNamingStrategy instanceof PropertyNamingStrategy)) { throw new JsonbException(Messages.getMessage(MessageKeys.PROPERTY_NAMING_STRATEGY_INVALID)); } return (PropertyNamingStrategy) property.get(); @@ -214,61 +158,66 @@ private PropertyNamingStrategy initPropertyNamingStrategy() { private PropertyVisibilityStrategy initPropertyVisibilityStrategy() { final Optional property = jsonbConfig.getProperty(JsonbConfig.PROPERTY_VISIBILITY_STRATEGY); - if (!property.isPresent()) { + if (property.isEmpty()) { return null; } final Object propertyVisibilityStrategy = property.get(); - if (!(propertyVisibilityStrategy instanceof PropertyVisibilityStrategy)) { + if (propertyVisibilityStrategy instanceof String) { + return VisibilityStrategiesProvider.getStrategy((String) propertyVisibilityStrategy); + } else if (!(propertyVisibilityStrategy instanceof PropertyVisibilityStrategy)) { throw new JsonbException("JsonbConfig.PROPERTY_VISIBILITY_STRATEGY must be instance of " + PropertyVisibilityStrategy.class); } return (PropertyVisibilityStrategy) propertyVisibilityStrategy; } private String initBinaryDataStrategy() { - final Optional iJson = jsonbConfig.getProperty(JsonbConfig.STRICT_IJSON).map((obj -> (Boolean) obj)); - if (iJson.isPresent() && iJson.get()) { + if (getConfigProperty(JsonbConfig.STRICT_IJSON, Boolean.class, false)) { return BinaryDataStrategy.BASE_64_URL; } - final Optional strategy = jsonbConfig.getProperty(JsonbConfig.BINARY_DATA_STRATEGY).map((obj) -> (String) obj); - return strategy.orElse(BinaryDataStrategy.BYTE); + return getConfigProperty(JsonbConfig.BINARY_DATA_STRATEGY, String.class, BinaryDataStrategy.BYTE); } private boolean initConfigNullable() { - return getBooleanConfigProperty(JsonbConfig.NULL_VALUES, false); + return getConfigProperty(JsonbConfig.NULL_VALUES, Boolean.class, false); } private boolean initConfigFailOnUnknownProperties() { - return getBooleanConfigProperty(YassonConfig.FAIL_ON_UNKNOWN_PROPERTIES, false); + return getConfigProperty(YassonConfig.FAIL_ON_UNKNOWN_PROPERTIES, Boolean.class, false); + } + + private boolean initRequiredCreatorParameters() { + if (System.getProperty(JsonbConfig.CREATOR_PARAMETERS_REQUIRED) != null) { + return Boolean.parseBoolean(System.getProperty(YassonConfig.CREATOR_PARAMETERS_REQUIRED)); + } + return getConfigProperty(YassonConfig.CREATOR_PARAMETERS_REQUIRED, Boolean.class, false); } @SuppressWarnings("unchecked") private JsonbSerializer initNullSerializer() { - Optional property = jsonbConfig.getProperty(YassonConfig.NULL_ROOT_SERIALIZER); - if (!property.isPresent()) { - return new NullSerializer(); - } - Object nullSerializer = property.get(); - if (!(nullSerializer instanceof JsonbSerializer)) { - throw new JsonbException("YassonConfig.NULL_ROOT_SERIALIZER must be instance of " + JsonbSerializer.class - + ""); - } - return (JsonbSerializer) nullSerializer; + return jsonbConfig.getProperty(YassonConfig.NULL_ROOT_SERIALIZER) + .map(o -> { + if (!(o instanceof JsonbSerializer)) { + throw new JsonbException("YassonConfig.NULL_ROOT_SERIALIZER must be instance of " + JsonbSerializer.class + + ""); + } + return (JsonbSerializer) o; + }).orElse(null); } - + private Set> initEagerInitClasses() { Optional property = jsonbConfig.getProperty(YassonConfig.EAGER_PARSE_CLASSES); - if (!property.isPresent()) { + if (property.isEmpty()) { return Collections.emptySet(); } Object eagerInitClasses = property.get(); if (!(eagerInitClasses instanceof Class[])) { throw new JsonbException("YassonConfig.EAGER_PARSE_CLASSES must be instance of Class[]"); } - return new HashSet>(Arrays.asList((Class[]) eagerInitClasses)); + return new HashSet<>(Arrays.asList((Class[]) eagerInitClasses)); } private boolean initForceMapArraySerializerForNullKeys() { - return getBooleanConfigProperty(YassonConfig.FORCE_MAP_ARRAY_SERIALIZER_FOR_NULL_KEYS, false); + return getConfigProperty(YassonConfig.FORCE_MAP_ARRAY_SERIALIZER_FOR_NULL_KEYS, Boolean.class, false); } /** @@ -293,18 +242,15 @@ public boolean getConfigFailOnUnknownProperties() { return failOnUnknownProperties; } - private boolean getBooleanConfigProperty(String propertyName, boolean defaultValue) { - final Optional property = jsonbConfig.getProperty(propertyName); - if (property.isPresent()) { - final Object result = property.get(); - if (!(result instanceof Boolean)) { - throw new JsonbException(Messages.getMessage(MessageKeys.JSONB_CONFIG_PROPERTY_INVALID_TYPE, - propertyName, - Boolean.class.getSimpleName())); - } - return (boolean) result; - } - return defaultValue; + private T getConfigProperty(String propertyName, Class propertyType, T defaultValue) { + Objects.requireNonNull(defaultValue, "Default value cannot be null"); + return jsonbConfig.getProperty(propertyName) + .or(() -> Optional.of(defaultValue)) + .filter(propertyType::isInstance) + .map(propertyType::cast) + .orElseThrow(() -> new JsonbException(Messages.getMessage(MessageKeys.JSONB_CONFIG_PROPERTY_INVALID_TYPE, + propertyName, + propertyType.getSimpleName()))); } /** @@ -335,19 +281,11 @@ public Locale getLocale(String locale) { * @return Configured locale. */ private Locale initConfigLocale() { - final Optional localeProperty = jsonbConfig.getProperty(JsonbConfig.LOCALE); - return localeProperty.map(loc -> { - if (!(loc instanceof Locale)) { - throw new JsonbException(Messages.getMessage(MessageKeys.JSONB_CONFIG_PROPERTY_INVALID_TYPE, - JsonbConfig.LOCALE, - Locale.class.getSimpleName())); - } - return (Locale) loc; - }).orElseGet(Locale::getDefault); + return getConfigProperty(JsonbConfig.LOCALE, Locale.class, Locale.getDefault()); } private boolean initStrictJson() { - return getBooleanConfigProperty(JsonbConfig.STRICT_IJSON, false); + return getConfigProperty(JsonbConfig.STRICT_IJSON, Boolean.class, false); } /** @@ -431,7 +369,11 @@ public Class getDefaultMapImplType() { public JsonbSerializer getNullSerializer() { return nullSerializer; } - + + public boolean hasRequiredCreatorParameters() { + return requiredCreatorParameters; + } + public Set> getEagerInitClasses() { return eagerInitClasses; } @@ -439,7 +381,8 @@ public Set> getEagerInitClasses() { /** * Whether the MapToEntriesArraySerializer is selected when a null key * is detected in a map. - * @return false or true + * + * @return false or true */ public boolean isForceMapArraySerializerForNullKeys() { return forceMapArraySerializerForNullKeys; diff --git a/src/main/java/org/eclipse/yasson/internal/JsonbContext.java b/src/main/java/org/eclipse/yasson/internal/JsonbContext.java index 09b4f4b0a..721e67e72 100644 --- a/src/main/java/org/eclipse/yasson/internal/JsonbContext.java +++ b/src/main/java/org/eclipse/yasson/internal/JsonbContext.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 @@ -16,15 +16,25 @@ import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.Comparator; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.ServiceLoader; import java.util.logging.Logger; import jakarta.json.bind.JsonbConfig; +import jakarta.json.bind.JsonbException; import jakarta.json.spi.JsonProvider; +import jakarta.json.stream.JsonGenerator; +import jakarta.json.stream.JsonParserFactory; import org.eclipse.yasson.internal.components.JsonbComponentInstanceCreatorFactory; +import org.eclipse.yasson.internal.deserializer.DeserializationModelCreator; +import org.eclipse.yasson.internal.properties.MessageKeys; +import org.eclipse.yasson.internal.properties.Messages; +import org.eclipse.yasson.internal.serializer.SerializationModelCreator; import org.eclipse.yasson.spi.JsonbComponentInstanceCreator; /** @@ -38,18 +48,22 @@ public class JsonbContext { private final MappingContext mappingContext; + private final DeserializationModelCreator deserializationModelCreator; + + private final SerializationModelCreator serializationModelCreator; + private final JsonbComponentInstanceCreator componentInstanceCreator; private final JsonProvider jsonProvider; + private final JsonParserFactory jsonParserFactory; + private final ComponentMatcher componentMatcher; private final AnnotationIntrospector annotationIntrospector; private final JsonbConfigProperties configProperties; - private final InstanceCreator instanceCreator; - /** * Creates and initialize context. * @@ -60,12 +74,14 @@ public JsonbContext(JsonbConfig jsonbConfig, JsonProvider jsonProvider) { Objects.requireNonNull(jsonbConfig); this.jsonbConfig = jsonbConfig; this.mappingContext = new MappingContext(this); - this.instanceCreator = InstanceCreator.getSingleton(); - this.componentInstanceCreator = initComponentInstanceCreator(instanceCreator); + this.componentInstanceCreator = initComponentInstanceCreator(); this.componentMatcher = new ComponentMatcher(this); this.annotationIntrospector = new AnnotationIntrospector(this); this.jsonProvider = jsonProvider; + this.jsonParserFactory = initJsonParserFactory(); this.configProperties = new JsonbConfigProperties(jsonbConfig); + this.deserializationModelCreator = new DeserializationModelCreator(this); + this.serializationModelCreator = new SerializationModelCreator(this); } /** @@ -86,6 +102,24 @@ public MappingContext getMappingContext() { return mappingContext; } + /** + * Get chain model creator. + * + * @return chain model creator + */ + public DeserializationModelCreator getChainModelCreator() { + return deserializationModelCreator; + } + + /** + * Get serialization model creator. + * + * @return serialization model creator + */ + public SerializationModelCreator getSerializationModelCreator() { + return serializationModelCreator; + } + /** * Gets JSONP provider. * @@ -126,16 +160,38 @@ public JsonbConfigProperties getConfigProperties() { return configProperties; } + public JsonParserFactory getJsonParserFactory() { + return jsonParserFactory; + } + + private JsonParserFactory initJsonParserFactory() { + return jsonProvider.createParserFactory(createJsonpProperties(jsonbConfig)); + } + /** - * Returns component for creating instances of non-parsed types. + * Propagates properties from JsonbConfig to JSONP generator / parser factories. * - * @return InstanceCreator + * @param jsonbConfig jsonb config + * @return properties for JSONP generator / parser */ - public InstanceCreator getInstanceCreator() { - return instanceCreator; + 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 property = jsonbConfig.getProperty(JsonbConfig.FORMATTING); + final Map factoryProperties = new HashMap<>(); + if (property.isPresent()) { + final Object value = property.get(); + if (!(value instanceof Boolean)) { + throw new JsonbException(Messages.getMessage(MessageKeys.JSONB_CONFIG_FORMATTING_ILLEGAL_VALUE)); + } + if ((Boolean) value) { + factoryProperties.put(JsonGenerator.PRETTY_PRINTING, Boolean.TRUE); + } + return factoryProperties; + } + return factoryProperties; } - private JsonbComponentInstanceCreator initComponentInstanceCreator(InstanceCreator instanceCreator) { + private JsonbComponentInstanceCreator initComponentInstanceCreator() { ServiceLoader loader = AccessController .doPrivileged((PrivilegedAction>) () -> ServiceLoader .load(JsonbComponentInstanceCreator.class)); @@ -145,7 +201,7 @@ private JsonbComponentInstanceCreator initComponentInstanceCreator(InstanceCreat } if (creators.isEmpty()) { // No service provider found - use the defaults - return JsonbComponentInstanceCreatorFactory.getComponentInstanceCreator(instanceCreator); + return JsonbComponentInstanceCreatorFactory.getComponentInstanceCreator(); } creators.sort(Comparator.comparingInt(JsonbComponentInstanceCreator::getPriority).reversed()); JsonbComponentInstanceCreator creator = creators.get(0); diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/JsonbDateFormatter.java b/src/main/java/org/eclipse/yasson/internal/JsonbDateFormatter.java similarity index 78% rename from src/main/java/org/eclipse/yasson/internal/serializer/JsonbDateFormatter.java rename to src/main/java/org/eclipse/yasson/internal/JsonbDateFormatter.java index 79bf26a24..9887640fa 100644 --- a/src/main/java/org/eclipse/yasson/internal/serializer/JsonbDateFormatter.java +++ b/src/main/java/org/eclipse/yasson/internal/JsonbDateFormatter.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 @@ -10,11 +10,12 @@ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ -package org.eclipse.yasson.internal.serializer; +package org.eclipse.yasson.internal; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatterBuilder; import java.util.Locale; +import java.util.Objects; import jakarta.json.bind.annotation.JsonbDateFormat; @@ -47,9 +48,7 @@ public class JsonbDateFormatter { .toFormatter(); private final DateTimeFormatter dateTimeFormatter; - private final String format; - private final String locale; /** @@ -114,4 +113,32 @@ public static JsonbDateFormatter getDefault() { public boolean isDefault() { return JsonbDateFormat.DEFAULT_FORMAT.equals(format); } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + JsonbDateFormatter that = (JsonbDateFormatter) o; + return Objects.equals(format, that.format) + && Objects.equals(locale, that.locale) + && Objects.equals(dateTimeFormatter, that.dateTimeFormatter); + } + + @Override + public int hashCode() { + return Objects.hash(dateTimeFormatter, format, locale); + } + + @Override + public String toString() { + return "JsonbDateFormatter{" + + "dateTimeFormatter=" + dateTimeFormatter + + ", format='" + format + '\'' + + ", locale='" + locale + '\'' + + '}'; + } } diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/JsonbNumberFormatter.java b/src/main/java/org/eclipse/yasson/internal/JsonbNumberFormatter.java similarity index 57% rename from src/main/java/org/eclipse/yasson/internal/serializer/JsonbNumberFormatter.java rename to src/main/java/org/eclipse/yasson/internal/JsonbNumberFormatter.java index c55be1bc0..ee97d8621 100644 --- a/src/main/java/org/eclipse/yasson/internal/serializer/JsonbNumberFormatter.java +++ b/src/main/java/org/eclipse/yasson/internal/JsonbNumberFormatter.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 @@ -10,7 +10,9 @@ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ -package org.eclipse.yasson.internal.serializer; +package org.eclipse.yasson.internal; + +import java.util.Objects; /** * Formatter for numbers. @@ -50,4 +52,29 @@ public String getLocale() { return locale; } + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + JsonbNumberFormatter that = (JsonbNumberFormatter) o; + return Objects.equals(format, that.format) + && Objects.equals(locale, that.locale); + } + + @Override + public int hashCode() { + return Objects.hash(format, locale); + } + + @Override + public String toString() { + return "JsonbNumberFormatter{" + + "format='" + format + '\'' + + ", locale='" + locale + '\'' + + '}'; + } } diff --git a/src/main/java/org/eclipse/yasson/internal/JsonbParser.java b/src/main/java/org/eclipse/yasson/internal/JsonbParser.java deleted file mode 100644 index 83ed327de..000000000 --- a/src/main/java/org/eclipse/yasson/internal/JsonbParser.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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 jakarta.json.stream.JsonParser; - -/** - * Jsonb parsing helper methods on top of JSON-P parser. - */ -public interface JsonbParser extends JsonParser { - - /** - * Moves parser to required event, if current event is equal to required does nothing. - * - * @param event Required event. - */ - void moveTo(JsonParser.Event event); - - /** - * Moves parser cursor to any JSON value. - * - * @return Event. - */ - Event moveToValue(); - - /** - * Moves parser cursor to START_OBJECT or START_ARRAY. - * - * @return Event. - */ - Event moveToStartStructure(); - - /** - * Current level of JsonbRiParser. - * - * @return Current level. - */ - JsonbRiParser.LevelContext getCurrentLevel(); - - /** - * Skips a value or a structure. - * If current event is START_ARRAY or START_OBJECT, whole structure is skipped to end. - */ - void skipJsonStructure(); -} diff --git a/src/main/java/org/eclipse/yasson/internal/JsonbRiParser.java b/src/main/java/org/eclipse/yasson/internal/JsonbRiParser.java deleted file mode 100644 index 06783a676..000000000 --- a/src/main/java/org/eclipse/yasson/internal/JsonbRiParser.java +++ /dev/null @@ -1,324 +0,0 @@ -/* - * Copyright (c) 2016, 2021 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.util.ArrayDeque; -import java.util.Arrays; -import java.util.Deque; -import java.util.Map; -import java.util.Objects; -import java.util.stream.Stream; - -import jakarta.json.JsonArray; -import jakarta.json.JsonObject; -import jakarta.json.JsonValue; -import jakarta.json.bind.JsonbException; -import jakarta.json.stream.JsonLocation; -import jakarta.json.stream.JsonParser; - -import org.eclipse.yasson.internal.properties.MessageKeys; -import org.eclipse.yasson.internal.properties.Messages; - -/** - * Decorator for JSONP parser used by JSONB. - */ -public class JsonbRiParser implements JsonParser, JsonbParser { - - /** - * State holder for current json structure level. - */ - public static class LevelContext { - private final LevelContext parent; - private JsonParser.Event lastEvent; - private String lastKeyName; - private boolean parsed; - - /** - * Creates an instance. - * - * @param parent Parent context. - */ - public LevelContext(LevelContext parent) { - this.parent = parent; - } - - /** - * Gets last event. - * - * @return Last event. - */ - public JsonParser.Event getLastEvent() { - return lastEvent; - } - - private void setLastEvent(JsonParser.Event lastEvent) { - this.lastEvent = lastEvent; - } - - /** - * Gets last key name. - * - * @return Last key name. - */ - public String getLastKeyName() { - return lastKeyName; - } - - private void setLastKeyName(String lastKeyName) { - Objects.requireNonNull(lastKeyName); - this.lastKeyName = lastKeyName; - } - - /** - * Get parent. - * - * @return Parent. - */ - public LevelContext getParent() { - return parent; - } - - /** - * Getter for parsed property. - * - * @return True or false. - */ - public boolean isParsed() { - return parsed; - } - - private void finish() { - if (parsed) { - throw new IllegalStateException("Level already parsed"); - } - parsed = true; - } - } - - private final JsonParser jsonParser; - - private final Deque level = new ArrayDeque<>(); - - /** - * Creates a parser. - * - * @param jsonParser JSON-P parser to decorate. - */ - public JsonbRiParser(JsonParser jsonParser) { - this.jsonParser = jsonParser; - //root level - this.level.push(new LevelContext(null)); - } - - @Override - public boolean hasNext() { - return jsonParser.hasNext(); - } - - @Override - public long getLong() { - return jsonParser.getLong(); - } - - @Override - public int getInt() { - return jsonParser.getInt(); - } - - @Override - public JsonParser.Event next() { - final JsonParser.Event next = jsonParser.next(); - level.peek().setLastEvent(next); - switch (next) { - case START_ARRAY: - case START_OBJECT: - final LevelContext newLevel = new LevelContext(level.peek()); - newLevel.setLastEvent(next); - level.push(newLevel); - break; - case END_ARRAY: - case END_OBJECT: - level.pop().finish(); - break; - case KEY_NAME: - getCurrentLevel().setLastKeyName(jsonParser.getString()); - break; - default: - break; - } - return next; - } - - @Override - public boolean isIntegralNumber() { - return jsonParser.isIntegralNumber(); - } - - @Override - public BigDecimal getBigDecimal() { - return jsonParser.getBigDecimal(); - } - - @Override - public JsonLocation getLocation() { - return jsonParser.getLocation(); - } - - @Override - public void close() { - jsonParser.close(); - } - - @Override - public String getString() { - return jsonParser.getString(); - } - - @Override - public void moveTo(JsonParser.Event required) { - if (!level.isEmpty() && level.peek().getLastEvent() == required) { - return; - } - - final Event next = next(); - if (next == required) { - return; - } - - throw new JsonbException(Messages.getMessage(MessageKeys.INTERNAL_ERROR, - "Event " + required + " not found." + getLastDataMsg())); - } - - @Override - public Event moveToValue() { - return moveTo(Event.VALUE_STRING, Event.VALUE_NUMBER, Event.VALUE_FALSE, Event.VALUE_TRUE, Event.VALUE_NULL); - } - - @Override - public Event moveToStartStructure() { - return moveTo(Event.START_OBJECT, Event.START_ARRAY); - } - - private Event moveTo(Event... events) { - if (!level.isEmpty() && contains(events, level.peek().getLastEvent())) { - return level.peek().getLastEvent(); - } - - final Event next = next(); - if (contains(events, next)) { - return next; - } - - throw new JsonbException(Messages.getMessage(MessageKeys.INTERNAL_ERROR, - "Parser event [" + Arrays - .toString(events) + "] not found." + getLastDataMsg())); - } - - private boolean contains(Event[] events, Event candidate) { - for (Event event : events) { - if (event == candidate) { - return true; - } - } - return false; - } - - private String getLastDataMsg() { - StringBuilder builder = new StringBuilder(); - final LevelContext currentLevel = getCurrentLevel(); - builder.append(" Last data: [").append("EVENT: ").append(currentLevel.getLastEvent()).append(" KEY_NAME: ") - .append(currentLevel.getLastKeyName()).append("]"); - return builder.toString(); - } - - @Override - public LevelContext getCurrentLevel() { - return level.peek(); - } - - @Override - public void skipJsonStructure() { - final LevelContext currentLevel = level.peek(); - switch (currentLevel.getLastEvent()) { - case START_ARRAY: - case START_OBJECT: - while (!currentLevel.isParsed()) { - next(); - } - return; - default: - return; - } - } - - @Override - public JsonObject getObject() { - JsonObject object = jsonParser.getObject(); - level.pop(); - return object; - } - - @Override - public JsonValue getValue() { - if (level.isEmpty() || getLastEvent() == null) { - return jsonParser.getValue(); - } - switch (getLastEvent()) { - case START_ARRAY: - return getArray(); - case START_OBJECT: - return getObject(); - default: - return jsonParser.getValue(); - } - } - - @Override - public JsonArray getArray() { - JsonArray result = jsonParser.getArray(); - level.pop(); - return result; - } - - @Override - public Stream getArrayStream() { - return jsonParser.getArrayStream(); - } - - @Override - public Stream> getObjectStream() { - return jsonParser.getObjectStream(); - } - - @Override - public Stream getValueStream() { - return jsonParser.getValueStream(); - } - - @Override - public void skipArray() { - jsonParser.skipArray(); - level.pop(); - } - - @Override - public void skipObject() { - jsonParser.skipObject(); - level.pop(); - } - - public JsonParser.Event getLastEvent() { - return level.peek().getLastEvent(); - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/MappingContext.java b/src/main/java/org/eclipse/yasson/internal/MappingContext.java index 53f11e676..a480aca77 100644 --- a/src/main/java/org/eclipse/yasson/internal/MappingContext.java +++ b/src/main/java/org/eclipse/yasson/internal/MappingContext.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 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 @@ -21,8 +21,6 @@ import org.eclipse.yasson.internal.model.ClassModel; import org.eclipse.yasson.internal.model.JsonbAnnotatedElement; import org.eclipse.yasson.internal.model.customization.ClassCustomization; -import org.eclipse.yasson.internal.serializer.ContainerSerializerProvider; -import org.eclipse.yasson.internal.serializer.DefaultSerializers; /** * JSONB mappingContext. Created once per {@link jakarta.json.bind.Jsonb} instance. Represents a global scope. @@ -35,8 +33,6 @@ public class MappingContext { private final ConcurrentHashMap, ClassModel> classes = new ConcurrentHashMap<>(); - private final ConcurrentHashMap, ContainerSerializerProvider> serializers = new ConcurrentHashMap<>(); - private final ClassParser classParser; /** @@ -71,7 +67,7 @@ public ClassModel getOrCreateClassModel(Class clazz) { newClassModels.push(classToParse); } if (clazz == Object.class) { - return classes.computeIfAbsent(clazz, (c) -> new ClassModel(c, null, null, null)); + return classes.computeIfAbsent(clazz, (c) -> new ClassModel(c, ClassCustomization.empty(), null, null)); } ClassModel parentClassModel = null; @@ -88,18 +84,63 @@ private static Function, ClassModel> createParseClassModelFunction(Clas JsonbContext jsonbContext) { return aClass -> { JsonbAnnotatedElement> clsElement = jsonbContext.getAnnotationIntrospector().collectAnnotations(aClass); - ClassCustomization customization = jsonbContext.getAnnotationIntrospector().introspectCustomization(clsElement); + ClassCustomization customization = jsonbContext.getAnnotationIntrospector() + .introspectCustomization(clsElement, + parentClassModel == null + ? ClassCustomization.empty() + : parentClassModel.getClassCustomization()); + // PolymorphismSupport configPolymorphism = jsonbContext.getConfigProperties().getPolymorphismSupport(); +// if (configPolymorphism != null) { +// customization = mergeConfigAndAnnotationPolymorphism(configPolymorphism, +// configPolymorphism.getClassPolymorphism(aClass), +// customization, +// aClass); +// } ClassModel newClassModel = new ClassModel(aClass, customization, parentClassModel, jsonbContext.getConfigProperties().getPropertyNamingStrategy()); - if (!DefaultSerializers.isKnownType(aClass)) { + if (!BuiltInTypes.isKnownType(aClass)) { classParser.parseProperties(newClassModel, clsElement); } return newClassModel; }; } +// private static ClassCustomization mergeConfigAndAnnotationPolymorphism(PolymorphismSupport generalPolymorphism, +// Optional maybeClassPolymorphism, +// ClassCustomization customization, +// Class aClass) { +// PolymorphismConfig polymorphismConfig = customization.getPolymorphismConfig(); +// PolymorphismConfig.Builder polyConfigBuilder; +// if (polymorphismConfig != null) { +// polyConfigBuilder = PolymorphismConfig.builder().of(polymorphismConfig); +// } else { +// polyConfigBuilder = PolymorphismConfig.builder(); +// maybeClassPolymorphism.ifPresent(classPolymorphism -> polyConfigBuilder +// .inherited(!classPolymorphism.getBoundClass().equals(aClass))); +// } +// generalPolymorphism.getKeyName().filter(s -> !s.isEmpty()).ifPresent(polyConfigBuilder::fieldName); +// generalPolymorphism.useClassNames().ifPresent(polyConfigBuilder::useClassNames); +// polyConfigBuilder.whitelistedPackages(generalPolymorphism.getWhitelistedPackages()); +// +// maybeClassPolymorphism.ifPresent(classPolymorphism -> { +// classPolymorphism.getKeyName().filter(s -> !s.isEmpty()).ifPresent(polyConfigBuilder::fieldName); +// classPolymorphism.useClassNames().ifPresent(polyConfigBuilder::useClassNames); +// classPolymorphism.getFormat().ifPresent(polyConfigBuilder::format); +// classPolymorphism.getAliases().forEach(polyConfigBuilder::alias); +// polyConfigBuilder.whitelistedPackages(classPolymorphism.getWhitelistedPackages()); +// }); +// PolymorphismConfig polyConfigMerged = polyConfigBuilder.build(); +// if (polyConfigMerged.getFieldName() == null || polyConfigMerged.getFieldName().isEmpty()) { +// throw new JsonbException("Polymorphism type field name cannot be null or empty: " + aClass); +// } +// return ClassCustomization.builder() +// .of(customization) +// .polymorphismConfig(polyConfigMerged) +// .build(); +// } + /** * Search for class model, without parsing if not found. * @@ -110,23 +151,4 @@ public ClassModel getClassModel(Class clazz) { return classes.get(clazz); } - /** - * Gets serializer provider for given class. - * - * @param clazz Class to get serializer provider for. - * @return Serializer provider. - */ - public ContainerSerializerProvider getSerializerProvider(Class clazz) { - return serializers.get(clazz); - } - - /** - * Adds given serializer provider for given class. - * - * @param clazz Class to add serializer provider for. - * @param serializerProvider Serializer provider to add. - */ - public void addSerializerProvider(Class clazz, ContainerSerializerProvider serializerProvider) { - serializers.putIfAbsent(clazz, serializerProvider); - } } diff --git a/src/main/java/org/eclipse/yasson/internal/ProcessingContext.java b/src/main/java/org/eclipse/yasson/internal/ProcessingContext.java index ba60ee392..17d2b6cd3 100644 --- a/src/main/java/org/eclipse/yasson/internal/ProcessingContext.java +++ b/src/main/java/org/eclipse/yasson/internal/ProcessingContext.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 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 @@ -25,12 +25,12 @@ public abstract class ProcessingContext { /** * Used to avoid StackOverflowError, when adapted / serialized object - * contains contains instance of its type inside it or when object has recursive reference. + * contains instance of its type inside it or when object has recursive reference. */ private final Set currentlyProcessedObjects = new HashSet<>(); /** - * Parent instance for marshaller and unmarshaller. + * Parent for marshaller and unmarshaller. * * @param jsonbContext context of Jsonb */ diff --git a/src/main/java/org/eclipse/yasson/internal/ReflectionUtils.java b/src/main/java/org/eclipse/yasson/internal/ReflectionUtils.java index 7d06cce9d..724783972 100644 --- a/src/main/java/org/eclipse/yasson/internal/ReflectionUtils.java +++ b/src/main/java/org/eclipse/yasson/internal/ReflectionUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 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 @@ -23,6 +23,7 @@ import java.security.AccessController; import java.security.PrivilegedAction; import java.util.Arrays; +import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.logging.Logger; @@ -31,9 +32,6 @@ import org.eclipse.yasson.internal.properties.MessageKeys; import org.eclipse.yasson.internal.properties.Messages; -import org.eclipse.yasson.internal.serializer.AbstractItem; -import org.eclipse.yasson.internal.serializer.EmbeddedItem; -import org.eclipse.yasson.internal.serializer.ResolvedParameterizedType; /** * Utility class for resolution of generics during unmarshalling. @@ -96,45 +94,51 @@ public static Class getRawType(Type type) { /** * Get a raw type of any type. - * If type is a {@link TypeVariable} recursively search {@link AbstractItem} for resolution of typevar. + * If type is a {@link TypeVariable} recursively search type chain for resolution of typevar. * If type is a {@link WildcardType} find most specific upper / lower bound, which can be used. If most specific * bound is a {@link TypeVariable}, perform typevar resolution. * - * @param item item containing wrapper class of a type field, not null. - * @param type type to resolve, typically field type or generic bound, not null. + * @param chain hierarchy of all wrapping types. + * @param type type to resolve, typically field type or generic bound, not null. * @return resolved raw class */ - public static Class resolveRawType(RuntimeTypeInfo item, Type type) { + public static Class resolveRawType(List chain, Type type) { if (type instanceof Class) { return (Class) type; } else if (type instanceof ParameterizedType) { return (Class) ((ParameterizedType) type).getRawType(); } else { - return getRawType(resolveType(item, type)); + return getRawType(resolveType(chain, type)); } } - + /** - * Resolve a type by item. - * If type is a {@link TypeVariable} recursively search {@link AbstractItem} for resolution of typevar. + * Resolve a type by chain. + * If type is a {@link TypeVariable} recursively search type chain for resolution of typevar. * If type is a {@link WildcardType} find most specific upper / lower bound, which can be used. If most specific * bound is a {@link TypeVariable}, perform typevar resolution. * - * @param item item containing wrapper class of a type field, not null. - * @param type type to resolve, typically field type or generic bound, not null. + * @param chain hierarchy of all wrapping types. + * @param type type to resolve, typically field type or generic bound, not null. * @return resolved type */ - public static Type resolveType(RuntimeTypeInfo item, Type type) { - return resolveType(item, type, true); + public static Type resolveType(List chain, Type type) { + return resolveType(chain, type, true); } - private static Type resolveType(RuntimeTypeInfo item, Type type, boolean warn) { - if (type instanceof WildcardType) { - return resolveMostSpecificBound(item, (WildcardType) type, warn); - } else if (type instanceof TypeVariable) { - return resolveItemVariableType(item, (TypeVariable) type, warn); - } else if (type instanceof ParameterizedType && item != null) { - return resolveTypeArguments((ParameterizedType) type, item.getRuntimeType()); + private static Type resolveType(List chain, Type type, boolean warn) { + Type toResolve = type; + if (type instanceof GenericArrayType) { + toResolve = ((GenericArrayType) type).getGenericComponentType(); + Type resolved = resolveType(chain, toResolve); + return new GenericArrayTypeImpl(resolved); + } + if (toResolve instanceof WildcardType) { + return resolveMostSpecificBound(chain, (WildcardType) toResolve, warn); + } else if (toResolve instanceof TypeVariable) { + return resolveItemVariableType(chain, (TypeVariable) toResolve, warn); + } else if (toResolve instanceof ParameterizedType) { + return resolveTypeArguments((ParameterizedType) toResolve, chain.get(chain.size() - 1)); } return type; } @@ -142,61 +146,77 @@ private static Type resolveType(RuntimeTypeInfo item, Type type, boolean warn) { /** * Resolves type by item information and wraps it with {@link Optional}. * - * @param info item information - * @param type type + * @param chain hierarchy of all wrapping types. + * @param type type * @return resolved type wrapped with Optional */ - public static Optional resolveOptionalType(RuntimeTypeInfo info, Type type) { + public static Optional resolveOptionalType(List chain, Type type) { try { - return Optional.of(resolveType(info, type, false)); + return Optional.of(resolveType(chain, type, false)); } catch (RuntimeException e) { return Optional.empty(); } } - + /** * Resolve a bounded type variable type by its wrapper types. * Resolution could be done only if a compile time generic information is provided, either: * by generic field or subclass of a generic class. * - * @param whether or not to log a warning message when bounds are not found - * @param item item to search "runtime" generic type of a TypeVariable. - * @param typeVariable type to search in item for, not null. + * @param chain chain to search "runtime" generic type of a TypeVariable. + * @param typeVariable type to search in chain for, not null. + * @param warn whether or not to log a warning message when bounds are not found * @return Type of a generic "runtime" bound, not null. */ - static Type resolveItemVariableType(RuntimeTypeInfo item, TypeVariable typeVariable, boolean warn) { - if (item == null) { - Optional> optionalRawType = getOptionalRawType(typeVariable); - if (optionalRawType.isPresent()) { - return optionalRawType.get(); + public static Type resolveItemVariableType(List chain, TypeVariable typeVariable, boolean warn) { +// if (chain == null) { +// Optional> optionalRawType = getOptionalRawType(typeVariable); +// if (optionalRawType.isPresent()) { +// return optionalRawType.get(); +// } + + // //Bound not found, treat it as an Object.class +// if (warn) { +// LOGGER.warning(Messages.getMessage(MessageKeys.GENERIC_BOUND_NOT_FOUND, +// typeVariable, +// typeVariable.getGenericDeclaration())); +// } +// return Object.class; +// } + Type returnType = typeVariable; + for (int i = chain.size() - 1; i >= 0; i--) { + Type type = chain.get(i); + Type tmp = new VariableTypeInheritanceSearch().searchParametrizedType(type, (TypeVariable) returnType); + if (tmp != null) { + returnType = tmp; } - - //Bound not found, treat it as an Object.class - if (warn) { - LOGGER.warning(Messages.getMessage(MessageKeys.GENERIC_BOUND_NOT_FOUND, - typeVariable, - typeVariable.getGenericDeclaration())); + if (!(returnType instanceof TypeVariable)) { + break; } - return Object.class; - } - - //Embedded items doesn't hold information about variable types - if (item instanceof EmbeddedItem) { - return resolveItemVariableType(item.getWrapper(), typeVariable, warn); } - - ParameterizedType wrapperParameterizedType = findParameterizedSuperclass(item.getRuntimeType()); - - VariableTypeInheritanceSearch search = new VariableTypeInheritanceSearch(); - Type foundType = search.searchParametrizedType(wrapperParameterizedType, typeVariable); - if (foundType != null) { - if (foundType instanceof TypeVariable) { - return resolveItemVariableType(item.getWrapper(), (TypeVariable) foundType, warn); - } - return foundType; + if (returnType instanceof TypeVariable) { + // throw new JsonbException("Could not resolve: " + unresolvedType); + return Object.class; } + return returnType; - return resolveItemVariableType(item.getWrapper(), typeVariable, warn); +// //Embedded items doesn't hold information about variable types +// if (chain instanceof EmbeddedItem) { +// return resolveItemVariableType(chain.getWrapper(), typeVariable, warn); +// } +// +// ParameterizedType wrapperParameterizedType = findParameterizedSuperclass(chain.getRuntimeType()); +// +// VariableTypeInheritanceSearch search = new VariableTypeInheritanceSearch(); +// Type foundType = search.searchParametrizedType(wrapperParameterizedType, typeVariable); +// if (foundType != null) { +// if (foundType instanceof TypeVariable) { +// return resolveItemVariableType(chain.getWrapper(), (TypeVariable) foundType, warn); +// } +// return foundType; +// } +// +// return resolveItemVariableType(chain.getWrapper(), typeVariable, warn); } /** @@ -210,20 +230,30 @@ public static Type resolveTypeArguments(ParameterizedType typeToResolve, Type ty final Type[] unresolvedArgs = typeToResolve.getActualTypeArguments(); Type[] resolvedArgs = new Type[unresolvedArgs.length]; for (int i = 0; i < unresolvedArgs.length; i++) { - if (!(unresolvedArgs[i] instanceof TypeVariable)) { - resolvedArgs[i] = unresolvedArgs[i]; + Type unresolvedArg = unresolvedArgs[i]; + if (!(unresolvedArg instanceof TypeVariable) && !(unresolvedArg instanceof GenericArrayType)) { + resolvedArgs[i] = unresolvedArg; } else { + Type variableType = unresolvedArg; + if (variableType instanceof GenericArrayType) { + variableType = ((GenericArrayType) variableType).getGenericComponentType(); + } resolvedArgs[i] = new VariableTypeInheritanceSearch() - .searchParametrizedType(typeToSearch, (TypeVariable) unresolvedArgs[i]); + .searchParametrizedType(typeToSearch, (TypeVariable) variableType); if (resolvedArgs[i] == null) { + if (typeToSearch instanceof Class) { + return Object.class; + } //No generic information available throw new IllegalStateException(Messages.getMessage(MessageKeys.GENERIC_BOUND_NOT_FOUND, - unresolvedArgs[i], + variableType, typeToSearch)); } } if (resolvedArgs[i] instanceof ParameterizedType) { resolvedArgs[i] = resolveTypeArguments((ParameterizedType) resolvedArgs[i], typeToSearch); + } else if (unresolvedArg instanceof GenericArrayType) { + resolvedArgs[i] = new GenericArrayTypeImpl(resolvedArgs[i]); } } return Arrays.equals(resolvedArgs, unresolvedArgs) @@ -336,27 +366,27 @@ private static ParameterizedType findParameterizedSuperclass(Type type) { /** * Resolves a wildcard most specific upper or lower bound. * - * @param item Type. + * @param chain Type. * @param wildcardType Wildcard type. * @return The most specific type. */ - private static Type resolveMostSpecificBound(RuntimeTypeInfo item, WildcardType wildcardType, boolean warn) { + private static Type resolveMostSpecificBound(List chain, WildcardType wildcardType, boolean warn) { Class result = Object.class; for (Type upperBound : wildcardType.getUpperBounds()) { - result = getMostSpecificBound(item, result, upperBound, warn); + result = getMostSpecificBound(chain, result, upperBound, warn); } for (Type lowerBound : wildcardType.getLowerBounds()) { - result = getMostSpecificBound(item, result, lowerBound, warn); + result = getMostSpecificBound(chain, result, lowerBound, warn); } return result; } - private static Class getMostSpecificBound(RuntimeTypeInfo item, Class result, Type bound, boolean warn) { + private static Class getMostSpecificBound(List chain, Class result, Type bound, boolean warn) { if (bound == Object.class) { return result; } //if bound is type variable search recursively for wrapper generic expansion - Type resolvedBoundType = bound instanceof TypeVariable ? resolveType(item, bound, warn) : bound; + Type resolvedBoundType = bound instanceof TypeVariable ? resolveType(chain, bound, warn) : bound; Class boundRawType = getRawType(resolvedBoundType); //resolved class is a subclass of a result candidate if (result.isAssignableFrom(boundRawType)) { @@ -364,4 +394,45 @@ private static Class getMostSpecificBound(RuntimeTypeInfo item, Class resu } return result; } + + public static final class GenericArrayTypeImpl implements GenericArrayType { + private final Type genericComponentType; + + // private constructor enforces use of static factory + private GenericArrayTypeImpl(Type ct) { + genericComponentType = ct; + } + + /** + * Returns a {@code Type} object representing the component type + * of this array. + * + * @return a {@code Type} object representing the component type + * of this array + * @since 1.5 + */ + public Type getGenericComponentType() { + return genericComponentType; // return cached component type + } + + public String toString() { + return getGenericComponentType().getTypeName() + "[]"; + } + + @Override + public boolean equals(Object o) { + if (o instanceof GenericArrayType) { + GenericArrayType that = (GenericArrayType) o; + + return Objects.equals(genericComponentType, that.getGenericComponentType()); + } else { + return false; + } + } + + @Override + public int hashCode() { + return Objects.hashCode(genericComponentType); + } + } } diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/ResolvedParameterizedType.java b/src/main/java/org/eclipse/yasson/internal/ResolvedParameterizedType.java similarity index 88% rename from src/main/java/org/eclipse/yasson/internal/serializer/ResolvedParameterizedType.java rename to src/main/java/org/eclipse/yasson/internal/ResolvedParameterizedType.java index 8d5d976ae..5be419edf 100644 --- a/src/main/java/org/eclipse/yasson/internal/serializer/ResolvedParameterizedType.java +++ b/src/main/java/org/eclipse/yasson/internal/ResolvedParameterizedType.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 @@ -10,7 +10,7 @@ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ -package org.eclipse.yasson.internal.serializer; +package org.eclipse.yasson.internal; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; @@ -20,7 +20,7 @@ /** * {@link ParameterizedType} implementation containing array of resolved TypeVariable type args. */ -public class ResolvedParameterizedType implements ParameterizedType { +class ResolvedParameterizedType implements ParameterizedType { /** * Original parameterized type. @@ -38,7 +38,7 @@ public class ResolvedParameterizedType implements ParameterizedType { * @param original Original type. * @param resolvedTypeArgs Resolved type arguments. */ - public ResolvedParameterizedType(ParameterizedType original, Type[] resolvedTypeArgs) { + ResolvedParameterizedType(ParameterizedType original, Type[] resolvedTypeArgs) { this.original = original; this.resolvedTypeArgs = resolvedTypeArgs; } @@ -70,7 +70,7 @@ public String toString() { if (resolvedTypeArgs != null && resolvedTypeArgs.length > 0) { sb.append(" resolved arguments: ["); for (Type typeArg : resolvedTypeArgs) { - sb.append(String.valueOf(typeArg)); + sb.append(typeArg); } sb.append("]"); } diff --git a/src/main/java/org/eclipse/yasson/internal/RuntimeTypeHolder.java b/src/main/java/org/eclipse/yasson/internal/RuntimeTypeHolder.java deleted file mode 100644 index 1f3a63814..000000000 --- a/src/main/java/org/eclipse/yasson/internal/RuntimeTypeHolder.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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; - -/** - * Holds runtime type and wrapper runtime type info if any. - */ -public class RuntimeTypeHolder implements RuntimeTypeInfo { - - private final RuntimeTypeInfo wrapper; - - private final Type runtimeType; - - /** - * Creates a new instance. - * - * @param wrapper runtime info about class - * @param runtimeType class type - */ - public RuntimeTypeHolder(RuntimeTypeInfo wrapper, Type runtimeType) { - this.wrapper = wrapper; - this.runtimeType = runtimeType; - } - - /** - * Wrapper containing property of this type. - * - * @return wrapper - */ - @Override - public RuntimeTypeInfo getWrapper() { - return wrapper; - } - - /** - * Runtime type of this item. - * - * @return runtime type - */ - @Override - public Type getRuntimeType() { - return runtimeType; - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/RuntimeTypeInfo.java b/src/main/java/org/eclipse/yasson/internal/RuntimeTypeInfo.java deleted file mode 100644 index ce6d625cc..000000000 --- a/src/main/java/org/eclipse/yasson/internal/RuntimeTypeInfo.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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; - -/** - * Holds runtime type info of the class. Used for generic type resolution, especially during unmarshalling. - */ -public interface RuntimeTypeInfo { - - /** - * Runtime type holder of a wrapper class of this runtime type. - * - * @return Runtime type info - */ - RuntimeTypeInfo getWrapper(); - - /** - * Returns a runtime type. It can be a class, {@link java.lang.reflect.ParameterizedType} or - * {@link java.lang.reflect.TypeVariable}. - * - * @return Runtime type or null if not defined. - */ - Type getRuntimeType(); -} diff --git a/src/main/java/org/eclipse/yasson/internal/Marshaller.java b/src/main/java/org/eclipse/yasson/internal/SerializationContextImpl.java similarity index 52% rename from src/main/java/org/eclipse/yasson/internal/Marshaller.java rename to src/main/java/org/eclipse/yasson/internal/SerializationContextImpl.java index ac99f0799..ea8111f48 100644 --- a/src/main/java/org/eclipse/yasson/internal/Marshaller.java +++ b/src/main/java/org/eclipse/yasson/internal/SerializationContextImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2022 Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2019, 2020 Payara Foundation and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the @@ -14,31 +14,37 @@ package org.eclipse.yasson.internal; import java.lang.reflect.Type; +import java.util.HashSet; import java.util.Objects; +import java.util.Set; import java.util.logging.Logger; import jakarta.json.bind.JsonbException; -import jakarta.json.bind.serializer.JsonbSerializer; import jakarta.json.bind.serializer.SerializationContext; import jakarta.json.stream.JsonGenerationException; import jakarta.json.stream.JsonGenerator; -import org.eclipse.yasson.internal.model.ClassModel; -import org.eclipse.yasson.internal.model.JsonbPropertyInfo; import org.eclipse.yasson.internal.properties.MessageKeys; import org.eclipse.yasson.internal.properties.Messages; -import org.eclipse.yasson.internal.serializer.AbstractValueTypeSerializer; -import org.eclipse.yasson.internal.serializer.ContainerSerializerProvider; -import org.eclipse.yasson.internal.serializer.SerializerBuilder; +import org.eclipse.yasson.internal.serializer.ModelSerializer; /** * JSONB marshaller. Created each time marshalling operation called. */ -public class Marshaller extends ProcessingContext implements SerializationContext { +public class SerializationContextImpl extends ProcessingContext implements SerializationContext { - private static final Logger LOGGER = Logger.getLogger(Marshaller.class.getName()); + private static final Logger LOGGER = Logger.getLogger(SerializationContextImpl.class.getName()); + + /** + * Used to avoid StackOverflowError, when adapted / serialized object + * contains instance of its type inside it or when object has recursive reference. + */ + private final Set currentlyProcessedObjects = new HashSet<>(); private final Type runtimeType; + private String key = null; + private boolean containerWithNulls = true; + private boolean root = true; /** * Creates Marshaller for generation to String. @@ -46,7 +52,7 @@ public class Marshaller extends ProcessingContext implements SerializationContex * @param jsonbContext Current context. * @param rootRuntimeType Type of root object. */ - public Marshaller(JsonbContext jsonbContext, Type rootRuntimeType) { + public SerializationContextImpl(JsonbContext jsonbContext, Type rootRuntimeType) { super(jsonbContext); this.runtimeType = rootRuntimeType; } @@ -56,9 +62,63 @@ public Marshaller(JsonbContext jsonbContext, Type rootRuntimeType) { * * @param jsonbContext Current context. */ - public Marshaller(JsonbContext jsonbContext) { - super(jsonbContext); - this.runtimeType = null; + public SerializationContextImpl(JsonbContext jsonbContext) { + this(jsonbContext, null); + } + + /** + * Set new current property key name. + * + * @param key key name + */ + public void setKey(String key) { + this.key = key; + } + + /** + * Current property key name. + * + * @return current property key name + */ + public String getKey() { + return key; + } + + /** + * Serialized value is a root value. + * + * @return is root value + */ + public boolean isRoot() { + return root; + } + + /** + * Set whether serialized value is root value. + * + * @param root is root value + */ + public void setRoot(boolean root) { + this.root = root; + } + + /** + * Value from this property is only used in {@link org.eclipse.yasson.internal.serializer.NullSerializer}. + * It should not be used anywhere else. + * + * @return if container supports nulls + */ + public boolean isContainerWithNulls() { + return containerWithNulls; + } + + /** + * Set if container supports null values. + * + * @param writeNulls should write nulls in container + */ + public void setContainerWithNulls(boolean writeNulls) { + this.containerWithNulls = writeNulls; } /** @@ -70,7 +130,7 @@ public Marshaller(JsonbContext jsonbContext) { */ public void marshall(Object object, JsonGenerator jsonGenerator, boolean close) { try { - serializeRoot(object, jsonGenerator); + serializeObject(object, jsonGenerator); } catch (JsonbException e) { LOGGER.severe(e.getMessage()); throw e; @@ -116,14 +176,14 @@ public void marshallWithoutClose(Object object, JsonGenerator jsonGenerator) { public void serialize(String key, T object, JsonGenerator generator) { Objects.requireNonNull(key); Objects.requireNonNull(object); - generator.writeKey(key); - serializeRoot(object, generator); + setKey(key); + serializeObject(object, generator); } @Override public void serialize(T object, JsonGenerator generator) { Objects.requireNonNull(object); - serializeRoot(object, generator); + serializeObject(object, generator); } /** @@ -133,34 +193,35 @@ public void serialize(T object, JsonGenerator generator) { * @param root Root. * @param generator JSON generator. */ - @SuppressWarnings("unchecked") - public void serializeRoot(T root, JsonGenerator generator) { - if (root == null) { - getJsonbContext().getConfigProperties().getNullSerializer().serialize(null, generator, this); - return; - } - final JsonbSerializer rootSerializer = (JsonbSerializer) getRootSerializer(root.getClass()); - if (getJsonbContext().getConfigProperties().isStrictIJson() - && rootSerializer instanceof AbstractValueTypeSerializer) { - throw new JsonbException(Messages.getMessage(MessageKeys.IJSON_ENABLED_SINGLE_VALUE)); - } + public void serializeObject(T root, JsonGenerator generator) { + Type type = runtimeType == null ? (root == null ? Object.class : root.getClass()) : runtimeType; + final ModelSerializer rootSerializer = getRootSerializer(type); rootSerializer.serialize(root, generator, this); } - JsonbSerializer getRootSerializer(Class rootClazz) { - final ContainerSerializerProvider serializerProvider = getMappingContext().getSerializerProvider(rootClazz); - if (serializerProvider != null) { - return serializerProvider - .provideSerializer(new JsonbPropertyInfo() - .withRuntimeType(runtimeType)); - } - SerializerBuilder serializerBuilder = new SerializerBuilder(getJsonbContext()) - .withObjectClass(rootClazz) - .withType(runtimeType); + public ModelSerializer getRootSerializer(Type type) { + return getJsonbContext().getSerializationModelCreator().serializerChain(type, true, true); + } + + /** + * Adds currently processed object to the {@link Set}. + * + * @param object processed object + * @return if object was added + */ + public boolean addProcessedObject(Object object) { + return this.currentlyProcessedObjects.add(object); + } - ClassModel classModel = getMappingContext().getOrCreateClassModel(rootClazz); - serializerBuilder.withCustomization(classModel.getClassCustomization()); - return serializerBuilder.build(); + /** + * Removes processed object from the {@link Set}. + * + * @param object processed object + * @return if object was removed + */ + public boolean removeProcessedObject(Object object) { + return currentlyProcessedObjects.remove(object); } - + + } diff --git a/src/main/java/org/eclipse/yasson/internal/Unmarshaller.java b/src/main/java/org/eclipse/yasson/internal/Unmarshaller.java deleted file mode 100644 index 7e1ee31ce..000000000 --- a/src/main/java/org/eclipse/yasson/internal/Unmarshaller.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.logging.Logger; - -import jakarta.json.bind.JsonbException; -import jakarta.json.bind.serializer.DeserializationContext; -import jakarta.json.stream.JsonParser; - -import org.eclipse.yasson.internal.model.ClassModel; -import org.eclipse.yasson.internal.properties.MessageKeys; -import org.eclipse.yasson.internal.properties.Messages; -import org.eclipse.yasson.internal.serializer.DeserializerBuilder; - -/** - * JSONB unmarshaller. - * Uses {@link JsonParser} to navigate through json string. - */ -public class Unmarshaller extends ProcessingContext implements DeserializationContext { - - private static final Logger LOGGER = Logger.getLogger(Unmarshaller.class.getName()); - - /** - * Creates instance of unmarshaller. - * - * @param jsonbContext context to use - */ - public Unmarshaller(JsonbContext jsonbContext) { - super(jsonbContext); - } - - @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 { - DeserializerBuilder deserializerBuilder = new DeserializerBuilder(getJsonbContext()) - .withType(type).withJsonValueType(getRootEvent(parser)); - Class rawType = ReflectionUtils.getRawType(type); - ClassModel classModel = getMappingContext().getOrCreateClassModel(rawType); - deserializerBuilder.withCustomization(classModel.getClassCustomization()); - return (T) deserializerBuilder.build().deserialize(parser, this, type); - } 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); - } - } - - /** - * Get root value event, either for new deserialization process, or deserialization sub-process invoked from - * custom user deserializer. - */ - private JsonParser.Event getRootEvent(JsonParser parser) { - JsonbRiParser.LevelContext currentLevel = ((JsonbParser) parser).getCurrentLevel(); - //Wrapper parser is at start - if (currentLevel.getParent() == null) { - return parser.next(); - } - final JsonParser.Event lastEvent = currentLevel.getLastEvent(); - return lastEvent == JsonParser.Event.KEY_NAME ? parser.next() : lastEvent; - } - -} diff --git a/src/main/java/org/eclipse/yasson/internal/UserDeserializerParser.java b/src/main/java/org/eclipse/yasson/internal/UserDeserializerParser.java deleted file mode 100644 index b7f4bbc94..000000000 --- a/src/main/java/org/eclipse/yasson/internal/UserDeserializerParser.java +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.util.Map; -import java.util.stream.Stream; - -import jakarta.json.JsonArray; -import jakarta.json.JsonObject; -import jakarta.json.JsonValue; -import jakarta.json.stream.JsonLocation; - -/** - * Decorator for JSONP parser. Adds some checks for parser cursor manipulation methods. - */ -public class UserDeserializerParser implements JsonbParser { - - private final JsonbParser jsonbParser; - - /** - * Remembered parser level, which is applied to user deserializer structure. - */ - private final JsonbRiParser.LevelContext level; - - /** - * Constructs an instance with parser and context. - * - * @param parser jsonb parser to decorate - */ - public UserDeserializerParser(JsonbParser parser) { - this.jsonbParser = parser; - level = jsonbParser.getCurrentLevel(); - } - - /** - * JsonParser in JSONB runtime is shared with user components, if user lefts cursor half way in progress - * it must be advanced artificially to the end of JSON structure representing deserialized object. - */ - public void advanceParserToEnd() { - while (!level.isParsed() && jsonbParser.hasNext()) { - next(); - } - } - - @Override - public boolean hasNext() { - return !level.isParsed() && jsonbParser.hasNext(); - } - - @Override - public Event next() { - if (level.isParsed()) { - throw new IllegalStateException("Parser level data inconsistent."); - } - return jsonbParser.next(); - } - - @Override - public String getString() { - return jsonbParser.getString(); - } - - @Override - public boolean isIntegralNumber() { - return jsonbParser.isIntegralNumber(); - } - - @Override - public int getInt() { - return jsonbParser.getInt(); - } - - @Override - public long getLong() { - return jsonbParser.getLong(); - } - - @Override - public BigDecimal getBigDecimal() { - return jsonbParser.getBigDecimal(); - } - - @Override - public JsonLocation getLocation() { - return jsonbParser.getLocation(); - } - - @Override - public void close() { - throw new UnsupportedOperationException(); - } - - /** - * Moves parser to required event, if current event is equal to required does nothing. - * - * @param event required event - */ - @Override - public void moveTo(Event event) { - jsonbParser.moveTo(event); - } - - /** - * Moves parser cursor to any JSON value. - */ - @Override - public Event moveToValue() { - return jsonbParser.moveToValue(); - } - - /** - * Moves parser cursor to START_OBJECT or START_ARRAY. - */ - @Override - public Event moveToStartStructure() { - return jsonbParser.moveToStartStructure(); - } - - /** - * Current level of JsonbRiParser. - * - * @return current level - */ - @Override - public JsonbRiParser.LevelContext getCurrentLevel() { - return jsonbParser.getCurrentLevel(); - } - - /** - * Skips a value or a structure. - * If current event is START_ARRAY or START_OBJECT, whole structure is skipped to end. - */ - @Override - public void skipJsonStructure() { - jsonbParser.skipJsonStructure(); - } - - @Override - public JsonObject getObject() { - return jsonbParser.getObject(); - } - - @Override - public JsonValue getValue() { - return jsonbParser.getValue(); - } - - @Override - public JsonArray getArray() { - return jsonbParser.getArray(); - } - - @Override - public Stream getArrayStream() { - return jsonbParser.getArrayStream(); - } - - @Override - public Stream> getObjectStream() { - return jsonbParser.getObjectStream(); - } - - @Override - public Stream getValueStream() { - return jsonbParser.getValueStream(); - } - - @Override - public void skipArray() { - jsonbParser.skipArray(); - } - - @Override - public void skipObject() { - jsonbParser.skipObject(); - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/VariableTypeInheritanceSearch.java b/src/main/java/org/eclipse/yasson/internal/VariableTypeInheritanceSearch.java index bcffc307b..263cc4e21 100644 --- a/src/main/java/org/eclipse/yasson/internal/VariableTypeInheritanceSearch.java +++ b/src/main/java/org/eclipse/yasson/internal/VariableTypeInheritanceSearch.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 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 @@ -26,7 +26,7 @@ /** * Search for type variable in inheritance hierarchy and resolve if possible. */ -public class VariableTypeInheritanceSearch { +class VariableTypeInheritanceSearch { private final Deque parameterizedSubclasses = new ArrayDeque<>(); @@ -73,7 +73,7 @@ public class VariableTypeInheritanceSearch { * @param typeVar type variable to resolve, not null * @return resolved runtime type, or type variable */ - public Type searchParametrizedType(Type typeToSearch, TypeVariable typeVar) { + Type searchParametrizedType(Type typeToSearch, TypeVariable typeVar) { ParameterizedType parameterizedType = findParameterizedSuperclass(typeToSearch); if (parameterizedType == null) { return null; diff --git a/src/main/java/org/eclipse/yasson/internal/components/BeanManagerInstanceCreator.java b/src/main/java/org/eclipse/yasson/internal/components/BeanManagerInstanceCreator.java index 0c55d62a0..456015a06 100644 --- a/src/main/java/org/eclipse/yasson/internal/components/BeanManagerInstanceCreator.java +++ b/src/main/java/org/eclipse/yasson/internal/components/BeanManagerInstanceCreator.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 @@ -65,7 +65,8 @@ public BeanManagerInstanceCreator(Object beanManager) { public T getOrCreateComponent(Class componentClass) { return (T) injectionTargets.computeIfAbsent(componentClass, clazz -> { final AnnotatedType aType = beanManager.createAnnotatedType(componentClass); - final InjectionTarget injectionTarget = beanManager.createInjectionTarget(aType); + final InjectionTarget injectionTarget = beanManager.getInjectionTargetFactory(aType) + .createInjectionTarget(null); CreationalContext creationalContext = beanManager.createCreationalContext(null); final T beanInstance = injectionTarget.produce(creationalContext); injectionTarget.inject(beanInstance, creationalContext); @@ -75,7 +76,6 @@ public T getOrCreateComponent(Class componentClass) { } @Override - @SuppressWarnings("unchecked") public void close() throws IOException { injectionTargets.forEach((clazz, target) -> cleanupBean(target)); injectionTargets.clear(); diff --git a/src/main/java/org/eclipse/yasson/internal/components/DefaultConstructorCreator.java b/src/main/java/org/eclipse/yasson/internal/components/DefaultConstructorCreator.java index e6d55a4de..ff949c030 100644 --- a/src/main/java/org/eclipse/yasson/internal/components/DefaultConstructorCreator.java +++ b/src/main/java/org/eclipse/yasson/internal/components/DefaultConstructorCreator.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 @@ -22,20 +22,9 @@ */ public class DefaultConstructorCreator implements JsonbComponentInstanceCreator { - private final InstanceCreator creator; - - /** - * Constructs default constructor creator. - * - * @param creator instance creator - */ - DefaultConstructorCreator(InstanceCreator creator) { - this.creator = creator; - } - @Override public T getOrCreateComponent(Class componentClass) { - return creator.createInstance(componentClass); + return InstanceCreator.createInstance(componentClass); } @Override diff --git a/src/main/java/org/eclipse/yasson/internal/components/JsonbComponentInstanceCreatorFactory.java b/src/main/java/org/eclipse/yasson/internal/components/JsonbComponentInstanceCreatorFactory.java index c1ede9baf..92e667139 100644 --- a/src/main/java/org/eclipse/yasson/internal/components/JsonbComponentInstanceCreatorFactory.java +++ b/src/main/java/org/eclipse/yasson/internal/components/JsonbComponentInstanceCreatorFactory.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 @@ -21,7 +21,6 @@ import jakarta.json.bind.JsonbException; -import org.eclipse.yasson.internal.InstanceCreator; import org.eclipse.yasson.internal.properties.MessageKeys; import org.eclipse.yasson.internal.properties.Messages; import org.eclipse.yasson.spi.JsonbComponentInstanceCreator; @@ -54,17 +53,16 @@ private JsonbComponentInstanceCreatorFactory() { * If one of the above is found {@link BeanManagerInstanceCreator} is returned, * or {@link DefaultConstructorCreator} otherwise. * - * @param creator Instance creator * @return Component instance creator, either CDI or default constructor. */ - public static JsonbComponentInstanceCreator getComponentInstanceCreator(InstanceCreator creator) { + public static JsonbComponentInstanceCreator getComponentInstanceCreator() { Object beanManager = getCdiBeanManager(); if (beanManager == null) { beanManager = getJndiBeanManager(); } if (beanManager == null) { LOGGER.finest(Messages.getMessage(MessageKeys.BEAN_MANAGER_NOT_FOUND_USING_DEFAULT)); - return new DefaultConstructorCreator(creator); + return new DefaultConstructorCreator(); } return new BeanManagerInstanceCreator(beanManager); } diff --git a/src/main/java/org/eclipse/yasson/internal/deserializer/AdapterDeserializer.java b/src/main/java/org/eclipse/yasson/internal/deserializer/AdapterDeserializer.java new file mode 100644 index 000000000..b54e72ab7 --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/AdapterDeserializer.java @@ -0,0 +1,52 @@ +/* + * 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.deserializer; + +import jakarta.json.bind.JsonbException; +import jakarta.json.bind.adapter.JsonbAdapter; + +import org.eclipse.yasson.internal.DeserializationContextImpl; +import org.eclipse.yasson.internal.components.AdapterBinding; +import org.eclipse.yasson.internal.properties.MessageKeys; +import org.eclipse.yasson.internal.properties.Messages; + +/** + * User defined type adapter executor. + */ +class AdapterDeserializer implements ModelDeserializer { + + private final JsonbAdapter adapter; + private final AdapterBinding adapterBinding; + private final ModelDeserializer delegate; + + @SuppressWarnings("unchecked") + AdapterDeserializer(AdapterBinding adapterBinding, + ModelDeserializer delegate) { + this.adapterBinding = adapterBinding; + this.adapter = (JsonbAdapter) adapterBinding.getAdapter(); + this.delegate = delegate; + } + + @Override + public Object deserialize(Object value, DeserializationContextImpl context) { + try { + return delegate.deserialize(adapter.adaptFromJson(value), context); + } catch (Exception e) { + throw new JsonbException(Messages.getMessage(MessageKeys.ADAPTER_EXCEPTION, + adapterBinding.getBindingType(), + adapterBinding.getToType(), + adapterBinding.getAdapter().getClass()), e); + } + } + +} diff --git a/src/main/java/org/eclipse/yasson/internal/deserializer/ArrayDeserializer.java b/src/main/java/org/eclipse/yasson/internal/deserializer/ArrayDeserializer.java new file mode 100644 index 000000000..2a85c97f4 --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/ArrayDeserializer.java @@ -0,0 +1,60 @@ +/* + * 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.deserializer; + +import java.util.ArrayList; +import java.util.Collection; + +import jakarta.json.bind.JsonbException; +import jakarta.json.stream.JsonParser; + +import org.eclipse.yasson.internal.DeserializationContextImpl; + +/** + * Array container deserializer. + */ +class ArrayDeserializer implements ModelDeserializer { + + private final ModelDeserializer delegate; + + ArrayDeserializer(ModelDeserializer delegate) { + this.delegate = delegate; + } + + @Override + public Object deserialize(JsonParser parser, DeserializationContextImpl context) { + Collection collection = new ArrayList<>(); + while (parser.hasNext()) { + final JsonParser.Event next = parser.next(); + context.setLastValueEvent(next); + switch (next) { + case START_OBJECT: + case START_ARRAY: + case VALUE_STRING: + case VALUE_TRUE: + case VALUE_FALSE: + case VALUE_NUMBER: + case VALUE_NULL: + DeserializationContextImpl newContext = new DeserializationContextImpl(context); + collection.add(delegate.deserialize(parser, newContext)); + break; + case END_ARRAY: + return collection; + default: + throw new JsonbException("Unexpected state: " + next); + } + } + return collection; + } + +} diff --git a/src/main/java/org/eclipse/yasson/internal/deserializer/ArrayInstanceCreator.java b/src/main/java/org/eclipse/yasson/internal/deserializer/ArrayInstanceCreator.java new file mode 100644 index 000000000..578f32fd1 --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/ArrayInstanceCreator.java @@ -0,0 +1,275 @@ +/* + * 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.deserializer; + +import java.lang.reflect.Array; +import java.util.Base64; +import java.util.Collection; +import java.util.Map; +import java.util.function.Function; + +import jakarta.json.bind.JsonbException; +import jakarta.json.bind.config.BinaryDataStrategy; +import jakarta.json.stream.JsonParser; + +import org.eclipse.yasson.internal.DeserializationContextImpl; +import org.eclipse.yasson.internal.properties.MessageKeys; +import org.eclipse.yasson.internal.properties.Messages; + +/** + * Creator of the array instance based upon the array type. + */ +abstract class ArrayInstanceCreator implements ModelDeserializer { + + private static final Map, Function, ArrayInstanceCreator>> CACHE; + + static { + CACHE = Map.of(boolean[].class, BooleanArrayCreator::new, + byte[].class, ByteArrayCreator::new, + char[].class, CharArrayCreator::new, + double[].class, DoubleArrayCreator::new, + float[].class, FloatArrayCreator::new, + int[].class, IntegerArrayCreator::new, + long[].class, LongArrayCreator::new, + short[].class, ShortArrayCreator::new); + } + + private final ModelDeserializer delegate; + + private ArrayInstanceCreator(ModelDeserializer delegate) { + this.delegate = delegate; + } + + static ArrayInstanceCreator create(Class arrayType, Class componentClass, ModelDeserializer delegate) { + if (CACHE.containsKey(arrayType)) { + return CACHE.get(arrayType).apply(delegate); + } + return new ObjectArrayCreator(delegate, componentClass); + } + + static ModelDeserializer createBase64Deserializer(String strategy, + ModelDeserializer delegate) { + return new Base64ByteArray(strategy, delegate); + } + + @SuppressWarnings("unchecked") + @Override + public Object deserialize(JsonParser value, DeserializationContextImpl context) { + Collection collection = (Collection) delegate.deserialize(value, context); + return resolveArrayInstance(collection); + } + + protected abstract Object resolveArrayInstance(Collection collection); + + private static final class IntegerArrayCreator extends ArrayInstanceCreator { + + private IntegerArrayCreator(ModelDeserializer delegate) { + super(delegate); + } + + @Override + protected Object resolveArrayInstance(Collection collection) { + int[] intArray = new int[collection.size()]; + int i = 0; + for (Object obj : collection) { + intArray[i] = (int) obj; + i++; + } + return intArray; + } + + } + + private static final class ByteArrayCreator extends ArrayInstanceCreator { + + private ByteArrayCreator(ModelDeserializer delegate) { + super(delegate); + } + + @Override + protected Object resolveArrayInstance(Collection collection) { + byte[] byteArray = new byte[collection.size()]; + int i = 0; + for (Object obj : collection) { + byteArray[i] = (byte) obj; + i++; + } + return byteArray; + } + + } + + private static final class ShortArrayCreator extends ArrayInstanceCreator { + + private ShortArrayCreator(ModelDeserializer delegate) { + super(delegate); + } + + @Override + protected Object resolveArrayInstance(Collection collection) { + short[] shortArray = new short[collection.size()]; + int i = 0; + for (Object obj : collection) { + shortArray[i] = (short) obj; + i++; + } + return shortArray; + } + + } + + private static final class LongArrayCreator extends ArrayInstanceCreator { + + private LongArrayCreator(ModelDeserializer delegate) { + super(delegate); + } + + @Override + protected Object resolveArrayInstance(Collection collection) { + long[] longArray = new long[collection.size()]; + int i = 0; + for (Object obj : collection) { + longArray[i] = (long) obj; + i++; + } + return longArray; + } + + } + + private static final class FloatArrayCreator extends ArrayInstanceCreator { + + private FloatArrayCreator(ModelDeserializer delegate) { + super(delegate); + } + + @Override + protected Object resolveArrayInstance(Collection collection) { + float[] floatArray = new float[collection.size()]; + int i = 0; + for (Object obj : collection) { + floatArray[i] = (float) obj; + i++; + } + return floatArray; + } + + } + + private static final class DoubleArrayCreator extends ArrayInstanceCreator { + + private DoubleArrayCreator(ModelDeserializer delegate) { + super(delegate); + } + + @Override + protected Object resolveArrayInstance(Collection collection) { + double[] doubleArray = new double[collection.size()]; + int i = 0; + for (Object obj : collection) { + doubleArray[i] = (double) obj; + i++; + } + return doubleArray; + } + + } + + private static final class BooleanArrayCreator extends ArrayInstanceCreator { + + private BooleanArrayCreator(ModelDeserializer delegate) { + super(delegate); + } + + @Override + protected Object resolveArrayInstance(Collection collection) { + boolean[] booleanArray = new boolean[collection.size()]; + int i = 0; + for (Object obj : collection) { + booleanArray[i] = (boolean) obj; + i++; + } + return booleanArray; + } + + } + + private static final class CharArrayCreator extends ArrayInstanceCreator { + + private CharArrayCreator(ModelDeserializer delegate) { + super(delegate); + } + + @Override + protected Object resolveArrayInstance(Collection collection) { + char[] charArray = new char[collection.size()]; + int i = 0; + for (Object obj : collection) { + charArray[i] = (char) obj; + i++; + } + return charArray; + } + + } + + private static final class ObjectArrayCreator extends ArrayInstanceCreator { + + private final Class componentClass; + + private ObjectArrayCreator(ModelDeserializer delegate, Class componentClass) { + super(delegate); + this.componentClass = componentClass; + } + + @Override + protected Object resolveArrayInstance(Collection collection) { + Object[] objectArray = (Object[]) Array.newInstance(componentClass, collection.size()); + int i = 0; + for (Object obj : collection) { + objectArray[i] = obj; + i++; + } + return objectArray; + } + + } + + private static final class Base64ByteArray implements ModelDeserializer { + + private final Base64.Decoder decoder; + private final ModelDeserializer delegate; + + private Base64ByteArray(String strategy, + ModelDeserializer delegate) { + this.decoder = getDecoder(strategy); + this.delegate = delegate; + } + + public Base64.Decoder getDecoder(String strategy) { + switch (strategy) { + case BinaryDataStrategy.BASE_64: + return Base64.getDecoder(); + case BinaryDataStrategy.BASE_64_URL: + return Base64.getUrlDecoder(); + default: + throw new JsonbException(Messages.getMessage(MessageKeys.INTERNAL_ERROR, "Invalid strategy: " + strategy)); + } + } + + @Override + public Object deserialize(JsonParser value, DeserializationContextImpl context) { + return decoder.decode((String) delegate.deserialize(value, context)); + } + } +} diff --git a/src/main/java/org/eclipse/yasson/internal/deserializer/CollectionDeserializer.java b/src/main/java/org/eclipse/yasson/internal/deserializer/CollectionDeserializer.java new file mode 100644 index 000000000..53a0dcb8f --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/CollectionDeserializer.java @@ -0,0 +1,60 @@ +/* + * 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.deserializer; + +import java.util.Collection; + +import jakarta.json.bind.JsonbException; +import jakarta.json.stream.JsonParser; + +import org.eclipse.yasson.internal.DeserializationContextImpl; + +/** + * Collection container deserializer. + */ +class CollectionDeserializer implements ModelDeserializer { + + private final ModelDeserializer delegate; + + CollectionDeserializer(ModelDeserializer delegate) { + this.delegate = delegate; + } + + @SuppressWarnings("unchecked") + @Override + public Object deserialize(JsonParser parser, DeserializationContextImpl context) { + Collection collection = (Collection) context.getInstance(); + while (parser.hasNext()) { + final JsonParser.Event next = parser.next(); + context.setLastValueEvent(next); + switch (next) { + case VALUE_NULL: + case START_OBJECT: + case START_ARRAY: + case VALUE_STRING: + case VALUE_TRUE: + case VALUE_FALSE: + case VALUE_NUMBER: + DeserializationContextImpl newContext = new DeserializationContextImpl(context); + collection.add(delegate.deserialize(parser, newContext)); + break; + case END_ARRAY: + return collection; + default: + throw new JsonbException("Unexpected state: " + next); + } + } + return collection; + } + +} diff --git a/src/main/java/org/eclipse/yasson/internal/deserializer/CollectionInstanceCreator.java b/src/main/java/org/eclipse/yasson/internal/deserializer/CollectionInstanceCreator.java new file mode 100644 index 000000000..50d82b975 --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/CollectionInstanceCreator.java @@ -0,0 +1,89 @@ +/* + * 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.deserializer; + +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Collection; +import java.util.EnumSet; +import java.util.HashSet; +import java.util.List; +import java.util.Queue; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; + +import jakarta.json.stream.JsonParser; + +import org.eclipse.yasson.internal.DeserializationContextImpl; +import org.eclipse.yasson.internal.InstanceCreator; +import org.eclipse.yasson.internal.ReflectionUtils; + +/** + * Collection instance creator. + */ +class CollectionInstanceCreator implements ModelDeserializer { + + private final CollectionDeserializer delegate; + private final Type type; + private final Class clazz; + private final boolean isEnumSet; + + CollectionInstanceCreator(CollectionDeserializer delegate, Type type) { + this.delegate = delegate; + this.clazz = implementationClass(ReflectionUtils.getRawType(type)); + this.isEnumSet = EnumSet.class.isAssignableFrom(clazz); + this.type = isEnumSet ? ((ParameterizedType) type).getActualTypeArguments()[0] : type; + } + + @SuppressWarnings("unchecked") + @Override + public Object deserialize(JsonParser value, DeserializationContextImpl context) { + Object instance; + if (isEnumSet) { + instance = EnumSet.noneOf((Class) type); + } else { + instance = InstanceCreator.createInstance(clazz); + } + context.setInstance(instance); + return delegate.deserialize(value, context); + } + + private Class implementationClass(Class type) { + if (type.isInterface()) { + return createInterfaceInstance(type); + } + return type; + } + + private Class createInterfaceInstance(Class ifcType) { + if (List.class.isAssignableFrom(ifcType)) { + return ArrayList.class; + } + if (Set.class.isAssignableFrom(ifcType)) { + if (SortedSet.class.isAssignableFrom(ifcType)) { + return TreeSet.class; + } + return HashSet.class; + } + if (Queue.class.isAssignableFrom(ifcType)) { + return ArrayDeque.class; + } + if (Collection.class == ifcType) { + return ArrayList.class; + } + return ifcType; + } +} diff --git a/src/main/java/org/eclipse/yasson/internal/deserializer/ContextSwitcher.java b/src/main/java/org/eclipse/yasson/internal/deserializer/ContextSwitcher.java new file mode 100644 index 000000000..462da5702 --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/ContextSwitcher.java @@ -0,0 +1,40 @@ +/* + * 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.deserializer; + +import jakarta.json.stream.JsonParser; + +import org.eclipse.yasson.internal.DeserializationContextImpl; + +/** + * Deserializer which creates new deserialization context and invokes delegate with it. + */ +class ContextSwitcher implements ModelDeserializer { + + private final ModelDeserializer delegate; + private final ModelDeserializer modelDeserializer; + + ContextSwitcher(ModelDeserializer delegate, + ModelDeserializer modelDeserializer) { + this.delegate = delegate; + this.modelDeserializer = modelDeserializer; + } + + @Override + public Object deserialize(JsonParser value, DeserializationContextImpl context) { + DeserializationContextImpl ctx = new DeserializationContextImpl(context); + Object returnedValue = delegate.deserialize(modelDeserializer.deserialize(value, ctx), context); + context.setLastValueEvent(ctx.getLastValueEvent()); + return returnedValue; + } +} diff --git a/src/main/java/org/eclipse/yasson/internal/deserializer/CyclicReferenceDeserializer.java b/src/main/java/org/eclipse/yasson/internal/deserializer/CyclicReferenceDeserializer.java new file mode 100644 index 000000000..f8ce5b40b --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/CyclicReferenceDeserializer.java @@ -0,0 +1,40 @@ +/* + * 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.deserializer; + +import java.lang.reflect.Type; + +import jakarta.json.stream.JsonParser; + +import org.eclipse.yasson.internal.DeserializationContextImpl; + +/** + * Deserialization solution for cyclic references. + */ +class CyclicReferenceDeserializer implements ModelDeserializer { + + private final Type type; + private ModelDeserializer delegate; + + CyclicReferenceDeserializer(Type type) { + this.type = type; + } + + @Override + public Object deserialize(JsonParser value, DeserializationContextImpl context) { + if (delegate == null) { + delegate = context.getJsonbContext().getChainModelCreator().deserializerChain(type); + } + return delegate.deserialize(value, context); + } +} diff --git a/src/main/java/org/eclipse/yasson/internal/deserializer/DefaultObjectInstanceCreator.java b/src/main/java/org/eclipse/yasson/internal/deserializer/DefaultObjectInstanceCreator.java new file mode 100644 index 000000000..822da1831 --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/DefaultObjectInstanceCreator.java @@ -0,0 +1,59 @@ +/* + * 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.deserializer; + +import java.lang.reflect.Constructor; + +import jakarta.json.bind.JsonbException; +import jakarta.json.stream.JsonParser; + +import org.eclipse.yasson.internal.ClassMultiReleaseExtension; +import org.eclipse.yasson.internal.DeserializationContextImpl; +import org.eclipse.yasson.internal.ReflectionUtils; +import org.eclipse.yasson.internal.properties.MessageKeys; +import org.eclipse.yasson.internal.properties.Messages; + +/** + * Creator of the class instance with the default constructor. + */ +class DefaultObjectInstanceCreator implements ModelDeserializer { + + private final ModelDeserializer delegate; + private final Constructor defaultConstructor; + private final JsonbException exception; + + DefaultObjectInstanceCreator(ModelDeserializer delegate, + Class clazz, + Constructor defaultConstructor) { + this.delegate = delegate; + this.defaultConstructor = defaultConstructor; + if (clazz.isInterface()) { + this.exception = new JsonbException(Messages.getMessage(MessageKeys.INFER_TYPE_FOR_UNMARSHALL, clazz.getName())); + } else if (defaultConstructor == null) { + this.exception = ClassMultiReleaseExtension.exceptionToThrow(clazz) + .orElse(new JsonbException(Messages.getMessage(MessageKeys.NO_DEFAULT_CONSTRUCTOR, clazz))); + } else { + this.exception = null; + } + } + + @Override + public Object deserialize(JsonParser value, DeserializationContextImpl context) { + if (exception != null) { + throw exception; + } + Object instance = ReflectionUtils.createNoArgConstructorInstance(defaultConstructor); + context.setInstance(instance); + return delegate.deserialize(value, context); + } +} diff --git a/src/main/java/org/eclipse/yasson/internal/deserializer/DeferredDeserializer.java b/src/main/java/org/eclipse/yasson/internal/deserializer/DeferredDeserializer.java new file mode 100644 index 000000000..9d87bfd44 --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/DeferredDeserializer.java @@ -0,0 +1,35 @@ +/* + * 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.deserializer; + +import org.eclipse.yasson.internal.DeserializationContextImpl; + +/** + * Deferred deserializer used for postponed value setting. Such as when {@link jakarta.json.bind.annotation.JsonbCreator} + * is used. + */ +class DeferredDeserializer implements ModelDeserializer { + + private final ModelDeserializer delegate; + + DeferredDeserializer(ModelDeserializer delegate) { + this.delegate = delegate; + } + + @Override + public Object deserialize(Object value, DeserializationContextImpl context) { + context.getDeferredDeserializers().add(() -> delegate.deserialize(value, context)); + return value; + } + +} diff --git a/src/main/java/org/eclipse/yasson/internal/deserializer/DeserializationModelCreator.java b/src/main/java/org/eclipse/yasson/internal/deserializer/DeserializationModelCreator.java new file mode 100644 index 000000000..e582a7412 --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/DeserializationModelCreator.java @@ -0,0 +1,573 @@ +/* + * 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.deserializer; + +import java.lang.reflect.GenericArrayType; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.OptionalDouble; +import java.util.OptionalInt; +import java.util.OptionalLong; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Function; +import java.util.stream.Collectors; + +import jakarta.json.bind.JsonbException; +import jakarta.json.bind.config.BinaryDataStrategy; +import jakarta.json.bind.config.PropertyNamingStrategy; +import jakarta.json.stream.JsonParser; + +import org.eclipse.yasson.internal.DeserializationContextImpl; +import org.eclipse.yasson.internal.JsonbConfigProperties; +import org.eclipse.yasson.internal.JsonbContext; +import org.eclipse.yasson.internal.JsonbDateFormatter; +import org.eclipse.yasson.internal.JsonbNumberFormatter; +import org.eclipse.yasson.internal.ReflectionUtils; +import org.eclipse.yasson.internal.components.AdapterBinding; +import org.eclipse.yasson.internal.components.DeserializerBinding; +import org.eclipse.yasson.internal.deserializer.types.TypeDeserializers; +import org.eclipse.yasson.internal.model.ClassModel; +import org.eclipse.yasson.internal.model.CreatorModel; +import org.eclipse.yasson.internal.model.JsonbCreator; +import org.eclipse.yasson.internal.model.PropertyModel; +import org.eclipse.yasson.internal.model.customization.ClassCustomization; +import org.eclipse.yasson.internal.model.customization.ComponentBoundCustomization; +import org.eclipse.yasson.internal.model.customization.Customization; +import org.eclipse.yasson.internal.model.customization.PropertyCustomization; +import org.eclipse.yasson.internal.model.customization.TypeInheritanceConfiguration; +import org.eclipse.yasson.internal.properties.MessageKeys; +import org.eclipse.yasson.internal.properties.Messages; + +import static jakarta.json.bind.JsonbConfig.PROPERTY_NAMING_STRATEGY; +import static jakarta.json.stream.JsonParser.Event; + +/** + * Creator of the deserialization models for deserialized types. + *
+ * This class servers also as a cache for all previously created model deserializers. + */ +public class DeserializationModelCreator { + + private static final ModelDeserializer NULL_PROVIDER = (value, context) -> null; + private static final Map, ModelDeserializer> DEFAULT_CREATOR_VALUES; + private static final Set MAP_KEY_EVENTS = new HashSet<>(); + + static { + MAP_KEY_EVENTS.add(Event.KEY_NAME); + MAP_KEY_EVENTS.addAll(PositionChecker.Checker.VALUES.getEvents()); + + Map, ModelDeserializer> tmpValuesMap = new HashMap<>(); + + tmpValuesMap.put(byte.class, (value, context) -> (byte) 0); + tmpValuesMap.put(short.class, (value, context) -> (short) 0); + tmpValuesMap.put(int.class, (value, context) -> 0); + tmpValuesMap.put(long.class, (value, context) -> 0L); + tmpValuesMap.put(float.class, (value, context) -> 0.0F); + tmpValuesMap.put(double.class, (value, context) -> 0.0); + tmpValuesMap.put(char.class, (value, context) -> '\u0000'); + tmpValuesMap.put(boolean.class, (value, context) -> false); + tmpValuesMap.put(Optional.class, (value, context) -> Optional.empty()); + tmpValuesMap.put(OptionalInt.class, (value, context) -> OptionalInt.empty()); + tmpValuesMap.put(OptionalLong.class, (value, context) -> OptionalLong.empty()); + tmpValuesMap.put(OptionalDouble.class, (value, context) -> OptionalDouble.empty()); + + DEFAULT_CREATOR_VALUES = Map.copyOf(tmpValuesMap); + } + + private final Map> models = new ConcurrentHashMap<>(); + + private final JsonbContext jsonbContext; + private final Map, Class> userTypeMapping; + + /** + * Create new instance. + * + * @param jsonbContext jsonb context + */ + public DeserializationModelCreator(JsonbContext jsonbContext) { + this.jsonbContext = jsonbContext; + this.userTypeMapping = jsonbContext.getConfigProperties().getUserTypeMapping(); + } + + /** + * Starts deserializer creation process. + * + * @param type type the deserializer is created for + * @return created deserializer + */ + public ModelDeserializer deserializerChain(Type type) { + LinkedList chain = new LinkedList<>(); + ClassModel classModel = jsonbContext.getMappingContext().getOrCreateClassModel(ReflectionUtils.getRawType(type)); + return deserializerChain(chain, type, classModel.getClassCustomization(), classModel); + } + + private ModelDeserializer deserializerChain(LinkedList chain, + Type type, + Customization propertyCustomization, + ClassModel classModel) { + if (chain.contains(type)) { + return new CyclicReferenceDeserializer(type); + } + try { + chain.add(type); + return deserializerChainInternal(chain, type, propertyCustomization, classModel); + } finally { + chain.removeLast(); + } + } + + private ModelDeserializer deserializerChainInternal(LinkedList chain, + Type type, + Customization propertyCustomization, + ClassModel classModel) { + Class rawType = classModel.getType(); + CachedItem cachedItem = createCachedItem(type, propertyCustomization); + if (models.containsKey(cachedItem)) { + return models.get(cachedItem); + } else if (userTypeMapping.containsKey(rawType)) { + Class userTypeRaw = userTypeMapping.get(rawType); + ModelDeserializer deserializer = deserializerChain(userTypeRaw); + models.put(cachedItem, deserializer); + return deserializer; + } + Optional adapterBinding = adapterBinding(type, (ComponentBoundCustomization) propertyCustomization); + if (adapterBinding.isPresent()) { + AdapterBinding adapter = adapterBinding.get(); + Class toType = ReflectionUtils.getRawType(adapter.getToType()); + ClassModel targetModel = jsonbContext.getMappingContext().getOrCreateClassModel(toType); + ModelDeserializer typeDeserializer = typeDeserializer(toType, + targetModel.getClassCustomization(), + JustReturn.instance()); + if (typeDeserializer == null) { + typeDeserializer = deserializerChain(adapter.getToType()); + } + ModelDeserializer targetAdapterModel = typeDeserializer; + AdapterDeserializer adapterDeserializer = new AdapterDeserializer(adapter, JustReturn.instance()); + ModelDeserializer adapterDeser = (parser, context) -> { + Object fromJson = targetAdapterModel.deserialize(parser, context); + return adapterDeserializer.deserialize(fromJson, context); + }; + models.put(cachedItem, adapterDeser); + return adapterDeser; + } + ModelDeserializer typeDeserializer = typeDeserializer(rawType, + propertyCustomization, + JustReturn.instance()); + if (typeDeserializer != null) { + models.put(cachedItem, typeDeserializer); + return typeDeserializer; + } + if (Collection.class.isAssignableFrom(rawType)) { + return createCollectionDeserializer(cachedItem, rawType, chain, propertyCustomization); + } else if (Map.class.isAssignableFrom(rawType)) { + return createMapDeserializer(cachedItem, rawType, chain, propertyCustomization); + } else if (rawType.isArray()) { + return createArrayDeserializer(cachedItem, rawType, chain, propertyCustomization); + } else if (type instanceof GenericArrayType) { + return createGenericArray(cachedItem, rawType, chain, propertyCustomization); + } else if (Optional.class.isAssignableFrom(rawType)) { + return createOptionalDeserializer(chain, type, propertyCustomization, cachedItem); + } else { + return createObjectDeserializer(chain, type, propertyCustomization, classModel, rawType, cachedItem); + } + } + + private ModelDeserializer createObjectDeserializer(LinkedList chain, + Type type, + Customization propertyCustomization, + ClassModel classModel, + Class rawType, + CachedItem cachedItem) { + ClassCustomization classCustomization = classModel.getClassCustomization(); + Optional> deserializerBinding = userDeserializer(type, + (ComponentBoundCustomization) propertyCustomization); + if (deserializerBinding.isPresent()) { + UserDefinedDeserializer user = new UserDefinedDeserializer(deserializerBinding.get().getJsonbDeserializer(), + JustReturn.instance(), type, classCustomization); + models.put(cachedItem, user); + return user; + } + JsonbCreator creator = classCustomization.getCreator(); + boolean hasCreator = creator != null; + List params = hasCreator ? creatorParamsList(creator) : Collections.emptyList(); + Function renamer = propertyRenamer(); + Map> processors = new LinkedHashMap<>(); + Map> defaultCreatorValues = new HashMap<>(); + for (PropertyModel propertyModel : classModel.getSortedProperties()) { + if (!propertyModel.isWritable() || params.contains(propertyModel.getReadName())) { + continue; + } + ModelDeserializer modelDeserializer = memberTypeProcessor(chain, propertyModel, hasCreator); + processors.put(renamer.apply(propertyModel.getReadName()), modelDeserializer); + } + for (String s : params) { + CreatorModel creatorModel = creator.findByName(s); + ModelDeserializer modelDeserializer = typeProcessor(chain, + creatorModel.getType(), + creatorModel.getCustomization(), + JustReturn.instance()); + String parameterName = renamer.apply(creatorModel.getName()); + processors.put(parameterName, modelDeserializer); + if (creatorModel.getCustomization().isRequired()) { + defaultCreatorValues.put(parameterName, new RequiredCreatorParameter(parameterName)); + } else { + Class rawParamType = ReflectionUtils.getRawType(creatorModel.getType()); + defaultCreatorValues.put(parameterName, DEFAULT_CREATOR_VALUES.getOrDefault(rawParamType, NULL_PROVIDER)); + } + } + ModelDeserializer instanceCreator; + TypeInheritanceConfiguration typeInheritanceConfiguration = classCustomization.getPolymorphismConfig(); + Set ignoredProperties = collectIgnoredProperties(typeInheritanceConfiguration); + boolean failOnUnknownProperties = jsonbContext.getConfigProperties().getConfigFailOnUnknownProperties(); + if (hasCreator) { + instanceCreator = new JsonbCreatorDeserializer(processors, defaultCreatorValues, creator, rawType, renamer, + failOnUnknownProperties, ignoredProperties); + } else { + ModelDeserializer typeWrapper = new ObjectDeserializer(processors, renamer, rawType, + failOnUnknownProperties, ignoredProperties); + instanceCreator = new DefaultObjectInstanceCreator(typeWrapper, rawType, + classModel.getDefaultConstructor()); + } + PositionChecker positionChecker = new PositionChecker(instanceCreator, rawType, Event.START_OBJECT); + if (typeInheritanceConfiguration != null && !typeInheritanceConfiguration.isInherited()) { + instanceCreator = new InheritanceInstanceCreator(rawType, this, typeInheritanceConfiguration, positionChecker); + positionChecker = new PositionChecker(instanceCreator, rawType, Event.START_OBJECT); + } + ModelDeserializer nullChecker = new NullCheckDeserializer(positionChecker, JustReturn.instance()); + models.put(cachedItem, nullChecker); + return nullChecker; + } + + private ModelDeserializer createCollectionDeserializer(CachedItem cachedItem, + Class rawType, + LinkedList chain, + Customization propertyCustomization) { + Type type = cachedItem.type; + Type colType = type instanceof ParameterizedType + ? ((ParameterizedType) type).getActualTypeArguments()[0] + : Object.class; + colType = ReflectionUtils.resolveType(chain, colType); + ModelDeserializer typeProcessor = typeProcessor(chain, + colType, + propertyCustomization, + JustReturn.instance()); + CollectionDeserializer collectionDeserializer = new CollectionDeserializer(typeProcessor); + CollectionInstanceCreator instanceDeserializer = new CollectionInstanceCreator(collectionDeserializer, type); + PositionChecker positionChecker = new PositionChecker(instanceDeserializer, rawType, Event.START_ARRAY); + NullCheckDeserializer nullChecker = new NullCheckDeserializer(positionChecker, JustReturn.instance()); + models.put(cachedItem, nullChecker); + return nullChecker; + } + + private ModelDeserializer createMapDeserializer(CachedItem cachedItem, + Class rawType, + LinkedList chain, + Customization propertyCustomization) { + Type type = cachedItem.type; + Type keyType = type instanceof ParameterizedType + ? ((ParameterizedType) type).getActualTypeArguments()[0] + : Object.class; + Type valueType = type instanceof ParameterizedType + ? ((ParameterizedType) type).getActualTypeArguments()[1] + : Object.class; + ModelDeserializer keyProcessor = typeProcessor(chain, + keyType, + ClassCustomization.empty(), + JustReturn.instance(), + MAP_KEY_EVENTS); + ModelDeserializer valueProcessor = typeProcessor(chain, + valueType, + propertyCustomization, + JustReturn.instance()); + + MapDeserializer mapDeserializer = new MapDeserializer(keyProcessor, valueProcessor); + MapInstanceCreator mapInstanceCreator = new MapInstanceCreator(mapDeserializer, + jsonbContext.getConfigProperties(), + rawType); + PositionChecker positionChecker = new PositionChecker(mapInstanceCreator, rawType, PositionChecker.Checker.CONTAINER); + NullCheckDeserializer nullChecker = new NullCheckDeserializer(positionChecker, JustReturn.instance()); + models.put(cachedItem, nullChecker); + return nullChecker; + } + + private ModelDeserializer createArrayDeserializer(CachedItem cachedItem, + Class rawType, + LinkedList chain, + Customization propertyCustomization) { + JsonbConfigProperties configProperties = jsonbContext.getConfigProperties(); + if (rawType.equals(byte[].class) && !configProperties.getBinaryDataStrategy().equals(BinaryDataStrategy.BYTE)) { + String strategy = configProperties.getBinaryDataStrategy(); + ModelDeserializer typeProcessor = typeProcessor(chain, + String.class, + propertyCustomization, + JustReturn.instance()); + ModelDeserializer base64Deserializer = ArrayInstanceCreator.createBase64Deserializer(strategy, + typeProcessor); + NullCheckDeserializer nullChecker = new NullCheckDeserializer(base64Deserializer, JustReturn.instance()); + models.put(cachedItem, nullChecker); + return nullChecker; + } + Class arrayType = rawType.getComponentType(); + ModelDeserializer typeProcessor = typeProcessor(chain, + arrayType, + propertyCustomization, + JustReturn.instance()); + return createArrayCommonDeserializer(cachedItem, rawType, arrayType, typeProcessor); + } + + private ModelDeserializer createGenericArray(CachedItem cachedItem, + Class rawType, + LinkedList chain, + Customization propertyCustomization) { + GenericArrayType type = (GenericArrayType) cachedItem.type; + Class component = ReflectionUtils.getRawType(type.getGenericComponentType()); + ModelDeserializer typeProcessor = typeProcessor(chain, + type.getGenericComponentType(), + propertyCustomization, + JustReturn.instance()); + return createArrayCommonDeserializer(cachedItem, rawType, component, typeProcessor); + } + + private ModelDeserializer createArrayCommonDeserializer(CachedItem cachedItem, + Class rawType, + Class component, + ModelDeserializer typeProcessor) { + ArrayDeserializer arrayDeserializer = new ArrayDeserializer(typeProcessor); + ArrayInstanceCreator arrayInstanceCreator = ArrayInstanceCreator.create(rawType, component, arrayDeserializer); + PositionChecker positionChecker = new PositionChecker(arrayInstanceCreator, rawType, Event.START_ARRAY); + NullCheckDeserializer nullChecker = new NullCheckDeserializer(positionChecker, JustReturn.instance()); + models.put(cachedItem, nullChecker); + return nullChecker; + } + + private OptionalDeserializer createOptionalDeserializer(LinkedList chain, + Type type, + Customization propertyCustomization, + CachedItem cachedItem) { + Type colType = type instanceof ParameterizedType + ? ((ParameterizedType) type).getActualTypeArguments()[0] + : Object.class; + ModelDeserializer typeProcessor = typeProcessor(chain, colType, propertyCustomization, JustReturn.instance()); + OptionalDeserializer optionalDeserializer = new OptionalDeserializer(typeProcessor, JustReturn.instance()); + models.put(cachedItem, optionalDeserializer); + return optionalDeserializer; + } + + private Set collectIgnoredProperties(TypeInheritanceConfiguration typeInheritanceConfiguration) { + Set ignoredProperties = new HashSet<>(); + if (typeInheritanceConfiguration != null) { + TypeInheritanceConfiguration current = typeInheritanceConfiguration; + while (current != null) { + ignoredProperties.add(current.getFieldName()); + current = current.getParentConfig(); + } + } + return ignoredProperties; + } + + private Function propertyRenamer() { + boolean isCaseInsensitive = jsonbContext.getConfig() + .getProperty(PROPERTY_NAMING_STRATEGY) + .filter(prop -> prop.equals(PropertyNamingStrategy.CASE_INSENSITIVE)) + .isPresent(); + + return isCaseInsensitive + ? String::toLowerCase + : value -> value; + } + + private Optional adapterBinding(Type type, ComponentBoundCustomization classCustomization) { + return jsonbContext.getComponentMatcher().getDeserializeAdapterBinding(type, classCustomization); + } + + private Optional> userDeserializer(Type type, ComponentBoundCustomization classCustomization) { + return jsonbContext.getComponentMatcher().getDeserializerBinding(type, classCustomization); + } + + private List creatorParamsList(JsonbCreator creator) { + return Arrays.stream(creator.getParams()).map(CreatorModel::getName).collect(Collectors.toList()); + } + + private ModelDeserializer memberTypeProcessor(LinkedList chain, + PropertyModel propertyModel, + boolean hasCreator) { + ModelDeserializer memberDeserializer; + Type type = propertyModel.getPropertyDeserializationType(); + memberDeserializer = new ValueSetterDeserializer(propertyModel.getSetValueHandle()); + if (hasCreator) { + memberDeserializer = new DeferredDeserializer(memberDeserializer); + } + return typeProcessor(chain, type, propertyModel.getCustomization(), memberDeserializer); + } + + private ModelDeserializer typeProcessor(LinkedList chain, + Type type, + Customization customization, + ModelDeserializer memberDeserializer) { + return typeProcessor(chain, type, customization, memberDeserializer, PositionChecker.Checker.VALUES.getEvents()); + } + + private ModelDeserializer typeProcessor(LinkedList chain, + Type type, + Customization customization, + ModelDeserializer memberDeserializer, + Set events) { + Type resolved = ReflectionUtils.resolveType(chain, type); + Class rawType = ReflectionUtils.getRawType(resolved); + Optional> deserializerBinding = userDeserializer(resolved, + (ComponentBoundCustomization) customization); + if (deserializerBinding.isPresent()) { + //TODO remove or not? fix for deserializer cycle + // ModelDeserializer exactType = createNewChain(chain, memberDeserializer, rawType, + // resolved, customization); + // return new UserDefinedDeserializer(deserializerBinding.get().getJsonbDeserializer(), + // exactType, + // memberDeserializer, + // resolved, + // customization); + return new UserDefinedDeserializer(deserializerBinding.get().getJsonbDeserializer(), + memberDeserializer, + resolved, + customization); + } + Optional adapterBinding = adapterBinding(resolved, (ComponentBoundCustomization) customization); + if (adapterBinding.isPresent()) { + AdapterBinding adapter = adapterBinding.get(); + ModelDeserializer typeDeserializer = typeDeserializer(ReflectionUtils.getRawType(adapter.getToType()), + customization, + JustReturn.instance(), events); + if (typeDeserializer == null) { + typeDeserializer = deserializerChain(adapter.getToType()); + } + ModelDeserializer targetAdapterModel = typeDeserializer; + + AdapterDeserializer adapterDeserializer = new AdapterDeserializer(adapter, memberDeserializer); + return (parser, context) -> { + DeserializationContextImpl newContext = new DeserializationContextImpl(context); + Object fromJson = targetAdapterModel.deserialize(parser, newContext); + return adapterDeserializer.deserialize(fromJson, context); + }; + } + ModelDeserializer typeDeserializer = typeDeserializer(rawType, customization, memberDeserializer, events); + if (typeDeserializer == null) { + Class implClass = resolveImplClass(rawType, customization); + return createNewChain(chain, memberDeserializer, implClass, resolved, customization); + } + return typeDeserializer; + } + + private ModelDeserializer createNewChain(LinkedList chain, + ModelDeserializer memberDeserializer, + Class rawType, + Type type, + Customization propertyCustomization) { + ClassModel classModel = jsonbContext.getMappingContext().getOrCreateClassModel(rawType); + ModelDeserializer modelDeserializer = deserializerChain(chain, type, propertyCustomization, classModel); + return new ContextSwitcher(memberDeserializer, modelDeserializer); + } + + private ModelDeserializer typeDeserializer(Class rawType, + Customization customization, + ModelDeserializer delegate) { + return typeDeserializer(rawType, customization, delegate, PositionChecker.Checker.VALUES.getEvents()); + } + + private ModelDeserializer typeDeserializer(Class rawType, + Customization customization, + ModelDeserializer delegate, + Set events) { + return TypeDeserializers + .getTypeDeserializer(rawType, customization, jsonbContext.getConfigProperties(), delegate, events); + } + + private Class resolveImplClass(Class rawType, Customization customization) { + if (rawType.isInterface()) { + Class implementationClass = null; + //annotation + if (customization instanceof PropertyCustomization) { + implementationClass = ((PropertyCustomization) customization).getImplementationClass(); + } + //JsonbConfig + if (implementationClass == null) { + implementationClass = jsonbContext.getConfigProperties().getUserTypeMapping().get(rawType); + } + if (implementationClass != null) { + if (!rawType.isAssignableFrom(implementationClass)) { + throw new JsonbException(Messages.getMessage(MessageKeys.IMPL_CLASS_INCOMPATIBLE, + implementationClass, + rawType)); + } + return implementationClass; + } + } + return rawType; + } + + private CachedItem createCachedItem(Type type, Customization customization) { + return new CachedItem(type, customization.getDeserializeNumberFormatter(), customization.getDeserializeDateFormatter()); + } + + private static final class CachedItem { + + private final Type type; + private final JsonbNumberFormatter numberFormatter; + private final JsonbDateFormatter dateFormatter; + + CachedItem(Type type, JsonbNumberFormatter numberFormatter, JsonbDateFormatter dateFormatter) { + this.type = type; + this.numberFormatter = numberFormatter; + this.dateFormatter = dateFormatter; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + CachedItem that = (CachedItem) o; + return Objects.equals(type, that.type) + && Objects.equals(numberFormatter, that.numberFormatter) + && Objects.equals(dateFormatter, that.dateFormatter); + } + + @Override + public int hashCode() { + return Objects.hash(type, numberFormatter, dateFormatter); + } + + @Override + public String toString() { + return "CachedItem{" + + "type=" + type + + ", numberFormatter=" + numberFormatter + + ", dateFormatter=" + dateFormatter + + '}'; + } + } + +} diff --git a/src/main/java/org/eclipse/yasson/internal/deserializer/InheritanceInstanceCreator.java b/src/main/java/org/eclipse/yasson/internal/deserializer/InheritanceInstanceCreator.java new file mode 100644 index 000000000..4360f57e6 --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/InheritanceInstanceCreator.java @@ -0,0 +1,94 @@ +/* + * 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.deserializer; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import jakarta.json.JsonObject; +import jakarta.json.bind.JsonbException; +import jakarta.json.stream.JsonParser; + +import org.eclipse.yasson.internal.DeserializationContextImpl; +import org.eclipse.yasson.internal.jsonstructure.JsonStructureToParserAdapter; +import org.eclipse.yasson.internal.model.customization.TypeInheritanceConfiguration; + +import static jakarta.json.stream.JsonParser.Event; + +/** + * Instance creator following the inheritance structure defined by {@link jakarta.json.bind.annotation.JsonbTypeInfo}. + */ +class InheritanceInstanceCreator implements ModelDeserializer { + + private final Class processedType; + private final Map> resolvedClasses = new ConcurrentHashMap<>(); + private final DeserializationModelCreator deserializationModelCreator; + private final TypeInheritanceConfiguration typeInheritanceConfiguration; + private final ModelDeserializer defaultProcessor; + + InheritanceInstanceCreator(Class processedType, + DeserializationModelCreator deserializationModelCreator, + TypeInheritanceConfiguration typeInheritanceConfiguration, + ModelDeserializer defaultProcessor) { + this.processedType = processedType; + this.deserializationModelCreator = deserializationModelCreator; + this.typeInheritanceConfiguration = typeInheritanceConfiguration; + this.defaultProcessor = defaultProcessor; + } + + @Override + public Object deserialize(JsonParser parser, DeserializationContextImpl context) { + String alias; + JsonParser jsonParser; + String polymorphismKeyName = typeInheritanceConfiguration.getFieldName(); + JsonObject object = parser.getObject(); + alias = object.getString(polymorphismKeyName, null); + JsonObject newJsonObject = context.getJsonbContext().getJsonProvider().createObjectBuilder(object) + .remove(polymorphismKeyName) + .build(); + jsonParser = new JsonStructureToParserAdapter(newJsonObject); + //To get to the first event + Event event = jsonParser.next(); + context.setLastValueEvent(event); + Class polymorphicTypeClass; + if (alias == null) { + return defaultProcessor.deserialize(jsonParser, context); + } + polymorphicTypeClass = getPolymorphicTypeClass(alias); + if (polymorphicTypeClass.equals(processedType)) { + return defaultProcessor.deserialize(jsonParser, context); + } + ModelDeserializer deserializer = deserializationModelCreator.deserializerChain(polymorphicTypeClass); + return deserializer.deserialize(jsonParser, context); + } + + @Override + public String toString() { + return "Property " + typeInheritanceConfiguration.getFieldName() + " polymorphic information handler"; + } + + private Class getPolymorphicTypeClass(String alias) { + if (resolvedClasses.containsKey(alias)) { + return resolvedClasses.get(alias); + } + for (Map.Entry, String> entry : typeInheritanceConfiguration.getAliases().entrySet()) { + if (entry.getValue().equals(alias)) { + resolvedClasses.put(alias, entry.getKey()); + return entry.getKey(); + } + } + throw new JsonbException("Unknown alias \"" + alias + "\" known aliases: " + + typeInheritanceConfiguration.getAliases().values()); + } + +} diff --git a/src/main/java/org/eclipse/yasson/internal/deserializer/JsonbCreatorDeserializer.java b/src/main/java/org/eclipse/yasson/internal/deserializer/JsonbCreatorDeserializer.java new file mode 100644 index 000000000..4dea87aea --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/JsonbCreatorDeserializer.java @@ -0,0 +1,122 @@ +/* + * 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.deserializer; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; + +import jakarta.json.bind.JsonbException; +import jakarta.json.stream.JsonParser; + +import org.eclipse.yasson.internal.DeserializationContextImpl; +import org.eclipse.yasson.internal.model.CreatorModel; +import org.eclipse.yasson.internal.model.JsonbCreator; +import org.eclipse.yasson.internal.properties.MessageKeys; +import org.eclipse.yasson.internal.properties.Messages; + +/** + * Creator of the Object instance with the usage of the {@link JsonbCreator}. + */ +class JsonbCreatorDeserializer implements ModelDeserializer { + + private final Map> propertyDeserializerChains; + private final Map> defaultCreatorValues; + private final List creatorParams; + private final Set ignoredProperties; + private final JsonbCreator creator; + private final Class clazz; + private final Function renamer; + private final boolean failOnUnknownProperties; + + JsonbCreatorDeserializer(Map> propertyDeserializerChains, + Map> defaultCreatorValues, + JsonbCreator creator, + Class clazz, + Function renamer, + boolean failOnUnknownProperties, + Set ignoredProperties) { + this.propertyDeserializerChains = propertyDeserializerChains; + this.defaultCreatorValues = defaultCreatorValues; + this.creatorParams = Arrays.stream(creator.getParams()).map(CreatorModel::getName).collect(Collectors.toList()); + this.ignoredProperties = Set.copyOf(ignoredProperties); + this.creator = creator; + this.clazz = clazz; + this.renamer = renamer; + this.failOnUnknownProperties = failOnUnknownProperties; + } + + @Override + public Object deserialize(JsonParser parser, DeserializationContextImpl context) { + String key = null; + Map paramValues = new HashMap<>(); + while (parser.hasNext()) { + final JsonParser.Event next = parser.next(); + context.setLastValueEvent(next); + switch (next) { + case KEY_NAME: + key = renamer.apply(parser.getString()); + break; + case VALUE_NULL: + case START_OBJECT: + case START_ARRAY: + case VALUE_STRING: + case VALUE_NUMBER: + case VALUE_FALSE: + case VALUE_TRUE: + if (propertyDeserializerChains.containsKey(key)) { + try { + Object o = propertyDeserializerChains.get(key).deserialize(parser, context); + if (creatorParams.contains(key)) { + paramValues.put(key, o); + } + } catch (JsonbException e) { + throw new JsonbException("Unable to deserialize property '" + key + "' because of: " + e.getMessage(), e); + } + } else if (failOnUnknownProperties && !ignoredProperties.contains(key)) { + throw new JsonbException(Messages.getMessage(MessageKeys.UNKNOWN_JSON_PROPERTY, key, clazz)); + } + break; + case END_OBJECT: + Object[] params = new Object[creatorParams.size()]; + for (int i = 0; i < creatorParams.size(); i++) { + String param = creatorParams.get(i); + if (paramValues.containsKey(param)) { + params[i] = paramValues.get(param); + } else { + params[i] = defaultCreatorValues.get(param).deserialize(null, context); + } + } + context.setInstance(creator.call(params, clazz)); + context.getDeferredDeserializers().forEach(Runnable::run); + context.getDeferredDeserializers().clear(); + return context.getInstance(); + default: + throw new JsonbException("Unexpected state: " + next); + } + } + return context.getInstance(); + } + + @Override + public String toString() { + return "ObjectInstanceCreator{" + + "parameters=" + creatorParams + + ", clazz=" + clazz + + '}'; + } +} diff --git a/src/main/java/org/eclipse/yasson/internal/deserializer/JustReturn.java b/src/main/java/org/eclipse/yasson/internal/deserializer/JustReturn.java new file mode 100644 index 000000000..6fcc10cdd --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/JustReturn.java @@ -0,0 +1,45 @@ +/* + * 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.deserializer; + +import org.eclipse.yasson.internal.DeserializationContextImpl; + +/** + * Return passed in object value. + */ +public final class JustReturn implements ModelDeserializer { + + private static final JustReturn INSTANCE = new JustReturn(); + + private JustReturn() { + } + + /** + * Return instance. + * + * @return instance of the class + */ + public static JustReturn instance() { + return INSTANCE; + } + + @Override + public Object deserialize(Object value, DeserializationContextImpl context) { + return value; + } + + @Override + public String toString() { + return "No other operations will be performed"; + } +} diff --git a/src/main/java/org/eclipse/yasson/internal/deserializer/MapDeserializer.java b/src/main/java/org/eclipse/yasson/internal/deserializer/MapDeserializer.java new file mode 100644 index 000000000..d366fc8fb --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/MapDeserializer.java @@ -0,0 +1,130 @@ +/* + * 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.deserializer; + +import java.util.Map; + +import jakarta.json.bind.JsonbException; +import jakarta.json.stream.JsonParser; + +import org.eclipse.yasson.internal.DeserializationContextImpl; + +/** + * Map container deserializer. + */ +class MapDeserializer implements ModelDeserializer { + + private final ModelDeserializer keyDelegate; + private final ModelDeserializer valueDelegate; + + MapDeserializer(ModelDeserializer keyDelegate, + ModelDeserializer valueDelegate) { + this.keyDelegate = keyDelegate; + this.valueDelegate = valueDelegate; + } + + @SuppressWarnings("unchecked") + @Override + public Object deserialize(JsonParser parser, DeserializationContextImpl context) { + Map map = (Map) context.getInstance(); + Object key = null; + Object keyValue = null; + String keyName = null; + Mode mode = Mode.NONE; + State state = State.NEXT; + while (parser.hasNext()) { + final JsonParser.Event next = parser.next(); + context.setLastValueEvent(next); + switch (next) { + case KEY_NAME: + mode = mode == Mode.NONE ? Mode.NORMAL : mode; + if (mode == Mode.NORMAL) { + keyValue = deserializeValue(parser, context, keyDelegate); + } + keyName = parser.getString(); + break; + case START_OBJECT: + mode = mode == Mode.NONE ? Mode.OBJECT : mode; + case START_ARRAY: + case VALUE_STRING: + case VALUE_TRUE: + case VALUE_FALSE: + case VALUE_NUMBER: + case VALUE_NULL: + if (mode == Mode.OBJECT) { + if (state == State.NEXT) { + state = State.KEY; + } else if (state == State.KEY) { + validateKeyName(keyName, state); + key = deserializeValue(parser, context, keyDelegate); + state = State.VALUE; + } else if (state == State.VALUE) { + validateKeyName(keyName, state); + Object value = deserializeValue(parser, context, valueDelegate); + map.put(key, value); + state = State.DONE; + } else { + throw new JsonbException("Only attributes 'key' and 'value' allowed!"); + } + } else { + Object value = deserializeValue(parser, context, valueDelegate); + map.put(keyValue, value); + } + break; + case END_OBJECT: + state = State.NEXT; + if (mode == Mode.OBJECT) { + break; + } + case END_ARRAY: + return map; + default: + throw new JsonbException("Unexpected state: " + next); + } + } + return map; + } + + private void validateKeyName(String keyName, State state) { + if (state == State.KEY && !keyName.equals("key")) { + throw new JsonbException("Attribute name has to be 'key' when representing map entry key. Got: " + keyName); + } else if (state == State.VALUE && !keyName.equals("value")) { + throw new JsonbException("Attribute name has to be 'value' when representing map entry value. Got: " + keyName); + } + } + + private Object deserializeValue(JsonParser parser, + DeserializationContextImpl context, + ModelDeserializer deserializer) { + DeserializationContextImpl keyContext = new DeserializationContextImpl(context); + return deserializer.deserialize(parser, keyContext); + } + + private enum Mode { + + NONE, + NORMAL, + OBJECT + + } + + private enum State { + + NEXT, + VALUE, + KEY, + DONE + + } + +} diff --git a/src/main/java/org/eclipse/yasson/internal/deserializer/MapInstanceCreator.java b/src/main/java/org/eclipse/yasson/internal/deserializer/MapInstanceCreator.java new file mode 100644 index 000000000..580c17ce8 --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/MapInstanceCreator.java @@ -0,0 +1,78 @@ +/* + * 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.deserializer; + +import java.util.HashMap; +import java.util.Map; +import java.util.NavigableMap; +import java.util.SortedMap; +import java.util.TreeMap; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.ConcurrentSkipListMap; + +import jakarta.json.stream.JsonParser; + +import org.eclipse.yasson.internal.DeserializationContextImpl; +import org.eclipse.yasson.internal.InstanceCreator; +import org.eclipse.yasson.internal.JsonbConfigProperties; + +/** + * Map instance creator. + */ +class MapInstanceCreator implements ModelDeserializer { + + private final MapDeserializer delegate; + private final JsonbConfigProperties configProperties; + private final Class clazz; + + MapInstanceCreator(MapDeserializer delegate, + JsonbConfigProperties configProperties, + Class clazz) { + this.delegate = delegate; + this.configProperties = configProperties; + this.clazz = clazz; + } + + @Override + public Object deserialize(JsonParser value, DeserializationContextImpl context) { + Map map = createInstance(clazz); + context.setInstance(map); + return delegate.deserialize(value, context); + } + + private Map createInstance(Class clazz) { + return clazz.isInterface() + ? getMapImpl(clazz) + : (Map) InstanceCreator.createInstance(clazz); + } + + private Map getMapImpl(Class ifcType) { + if (ConcurrentMap.class.isAssignableFrom(ifcType)) { + if (SortedMap.class.isAssignableFrom(ifcType) || NavigableMap.class.isAssignableFrom(ifcType)) { + return new ConcurrentSkipListMap<>(); + } else { + return new ConcurrentHashMap<>(); + } + } + // SortedMap, NavigableMap + if (SortedMap.class.isAssignableFrom(ifcType)) { + Class defaultMapImplType = configProperties.getDefaultMapImplType(); + return SortedMap.class.isAssignableFrom(defaultMapImplType) + ? (Map) InstanceCreator.createInstance(defaultMapImplType) + : new TreeMap<>(); + } + return new HashMap<>(); + } + +} diff --git a/src/main/java/org/eclipse/yasson/internal/deserializer/ModelDeserializer.java b/src/main/java/org/eclipse/yasson/internal/deserializer/ModelDeserializer.java new file mode 100644 index 000000000..2275e3c82 --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/ModelDeserializer.java @@ -0,0 +1,36 @@ +/* + * 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.deserializer; + +import org.eclipse.yasson.internal.DeserializationContextImpl; + +/** + * Type deserializer. + *
+ * All the instances are required to be reusable and without any states + * stored in the class fields. + * + * @param represents the content value this deserializer is using + */ +public interface ModelDeserializer { + + /** + * Deserialize provided value or delegate deserialization to the next deserializer. + * + * @param value value to be deserialized + * @param context deserialization context + * @return deserialized value + */ + Object deserialize(T value, DeserializationContextImpl context); + +} diff --git a/src/main/java/org/eclipse/yasson/internal/deserializer/NullCheckDeserializer.java b/src/main/java/org/eclipse/yasson/internal/deserializer/NullCheckDeserializer.java new file mode 100644 index 000000000..c6310ce15 --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/NullCheckDeserializer.java @@ -0,0 +1,55 @@ +/* + * 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.deserializer; + +import jakarta.json.stream.JsonParser; + +import org.eclipse.yasson.internal.DeserializationContextImpl; + +/** + * Json null value checker. + *
+ * Simple delegate which checks whether the obtained parser value event was + * {@link JsonParser.Event#VALUE_NULL} or not. If the event has been {@link JsonParser.Event#VALUE_NULL}, null value + * deserializer will be called. In all other cases non-null deserializer is called. + */ +public class NullCheckDeserializer implements ModelDeserializer { + + private final ModelDeserializer nonNullDeserializer; + private final ModelDeserializer nullDeserializer; + + /** + * Create new instance. + * + * @param nonNullDeserializer deserializer called when value is not null + * @param nullDeserializer deserializer called when value is null + */ + public NullCheckDeserializer(ModelDeserializer nonNullDeserializer, + ModelDeserializer nullDeserializer) { + this.nonNullDeserializer = nonNullDeserializer; + this.nullDeserializer = nullDeserializer; + } + + @Override + public Object deserialize(JsonParser value, DeserializationContextImpl context) { + if (context.getLastValueEvent() != JsonParser.Event.VALUE_NULL) { + return nonNullDeserializer.deserialize(value, context); + } + return nullDeserializer.deserialize(null, context); + } + + @Override + public String toString() { + return "Null value check"; + } +} diff --git a/src/main/java/org/eclipse/yasson/internal/deserializer/ObjectDeserializer.java b/src/main/java/org/eclipse/yasson/internal/deserializer/ObjectDeserializer.java new file mode 100644 index 000000000..112b10075 --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/ObjectDeserializer.java @@ -0,0 +1,86 @@ +/* + * 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.deserializer; + +import java.util.Map; +import java.util.Set; +import java.util.function.Function; + +import jakarta.json.bind.JsonbException; +import jakarta.json.stream.JsonParser; + +import org.eclipse.yasson.internal.DeserializationContextImpl; +import org.eclipse.yasson.internal.properties.MessageKeys; +import org.eclipse.yasson.internal.properties.Messages; + +/** + * Object container deserializer. + */ +class ObjectDeserializer implements ModelDeserializer { + + private final Map> propertyDeserializerChains; + private final Function renamer; + private final Class rawClass; + private final boolean failOnUnknownProperty; + private final Set ignoredProperties; + + ObjectDeserializer(Map> propertyDeserializerChains, + Function renamer, + Class rawClass, + boolean failOnUnknownProperty, + Set ignoredProperties) { + this.propertyDeserializerChains = Map.copyOf(propertyDeserializerChains); + this.renamer = renamer; + this.rawClass = rawClass; + this.failOnUnknownProperty = failOnUnknownProperty; + this.ignoredProperties = Set.copyOf(ignoredProperties); + } + + @Override + public Object deserialize(JsonParser parser, DeserializationContextImpl context) { + String key = null; + while (parser.hasNext()) { + final JsonParser.Event next = parser.next(); + context.setLastValueEvent(next); + switch (next) { + case KEY_NAME: + key = renamer.apply(parser.getString()); + break; + case VALUE_NULL: + case START_OBJECT: + case START_ARRAY: + case VALUE_STRING: + case VALUE_NUMBER: + case VALUE_FALSE: + case VALUE_TRUE: + if (propertyDeserializerChains.containsKey(key)) { + try { + propertyDeserializerChains.get(key).deserialize(parser, context); + } catch (JsonbException e) { + throw new JsonbException("Unable to deserialize property '" + key + "' because of: " + e.getMessage(), e); + } + } else if (failOnUnknownProperty && !ignoredProperties.contains(key)) { + throw new JsonbException(Messages.getMessage(MessageKeys.UNKNOWN_JSON_PROPERTY, key, rawClass)); + } + break; + case END_ARRAY: + break; + case END_OBJECT: + return context.getInstance(); + default: + throw new JsonbException("Unexpected state: " + next); + } + } + return context.getInstance(); + } +} diff --git a/src/main/java/org/eclipse/yasson/internal/deserializer/OptionalDeserializer.java b/src/main/java/org/eclipse/yasson/internal/deserializer/OptionalDeserializer.java new file mode 100644 index 000000000..2bc71abea --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/OptionalDeserializer.java @@ -0,0 +1,40 @@ +/* + * 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.deserializer; + +import java.util.Optional; + +import jakarta.json.stream.JsonParser; + +import org.eclipse.yasson.internal.DeserializationContextImpl; + +/** + * Deserializer of the {@link Optional} types. + */ +class OptionalDeserializer implements ModelDeserializer { + + private final ModelDeserializer typeDeserializer; + private final ModelDeserializer delegate; + + OptionalDeserializer(ModelDeserializer typeDeserializer, + ModelDeserializer delegate) { + this.typeDeserializer = typeDeserializer; + this.delegate = delegate; + } + + @Override + public Object deserialize(JsonParser value, DeserializationContextImpl context) { + Optional val = Optional.ofNullable(typeDeserializer.deserialize(value, context)); + return delegate.deserialize(val, context); + } +} diff --git a/src/main/java/org/eclipse/yasson/internal/deserializer/PositionChecker.java b/src/main/java/org/eclipse/yasson/internal/deserializer/PositionChecker.java new file mode 100644 index 000000000..61e4cb514 --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/PositionChecker.java @@ -0,0 +1,139 @@ +/* + * 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.deserializer; + +import java.lang.reflect.Type; +import java.util.Arrays; +import java.util.Map; +import java.util.Set; + +import jakarta.json.bind.JsonbException; +import jakarta.json.stream.JsonParser; + +import org.eclipse.yasson.internal.DeserializationContextImpl; + +import static jakarta.json.stream.JsonParser.Event; + +/** + * JSON document position checker. + *
+ * Checks whether json parser is in expected state. If not it will try to skip to the next event, since + * if user defined components are involved, it is possible to expect incorrect states in terms of the last expected events. + * If this checker is still not in expected state, an exception is thrown. + */ +public class PositionChecker implements ModelDeserializer { + + private static final Map CLOSING_EVENTS = Map.of(Event.START_ARRAY, Event.END_ARRAY, + Event.START_OBJECT, Event.END_OBJECT); + + private final Set expectedEvents; + private final ModelDeserializer delegate; + private final Type rType; + + /** + * Create new instance. + * + * @param delegate delegate which is call after the check + * @param rType runtime type + * @param checker bound group of events + */ + public PositionChecker(ModelDeserializer delegate, Type rType, Checker checker) { + this(checker.events, delegate, rType); + } + + /** + * Create new instance. + * + * @param delegate delegate which is call after the check + * @param rType runtime type + * @param events customized checked events + */ + public PositionChecker(ModelDeserializer delegate, Type rType, Event... events) { + this(Set.copyOf(Arrays.asList(events)), delegate, rType); + } + + private PositionChecker(Set expectedEvents, + ModelDeserializer delegate, Type rType) { + this.expectedEvents = expectedEvents; + this.delegate = delegate; + this.rType = rType; + } + + @Override + public Object deserialize(JsonParser value, DeserializationContextImpl context) { + Event original = context.getLastValueEvent(); + Event startEvent = original; + if (!expectedEvents.contains(startEvent)) { + startEvent = value.next(); + context.setLastValueEvent(startEvent); + if (!expectedEvents.contains(startEvent)) { + throw new JsonbException("Incorrect position for processing type: " + rType + ". " + + "Received event: " + original + " " + + "Allowed: " + expectedEvents); + } + } + Object o = delegate.deserialize(value, context); + if (CLOSING_EVENTS.containsKey(startEvent) + && CLOSING_EVENTS.get(startEvent) != context.getLastValueEvent()) { + throw new JsonbException("Incorrect parser position after processing of the type: " + rType + ". " + + "Start event: " + startEvent + " " + + "After processing event: " + context.getLastValueEvent()); + } + return o; + } + + @Override + public String toString() { + return "PositionChecker{" + + "expectedEvents=" + expectedEvents + + ", runtimeType=" + rType + + '}'; + } + + /** + * Grouped events according to whether it is container or value. + */ + public enum Checker { + + /** + * Value bound events. + */ + VALUES(Event.VALUE_FALSE, + Event.VALUE_TRUE, + Event.VALUE_STRING, + Event.VALUE_NUMBER, + Event.VALUE_NULL), + + /** + * Container bound events. + */ + CONTAINER(Event.START_OBJECT, + Event.START_ARRAY); + + private final Set events; + + Checker(Event... events) { + this.events = Set.of(events); + } + + /** + * Return events bound to the event group. + * + * @return set of bound events + */ + public Set getEvents() { + return events; + } + } + +} diff --git a/src/main/java/org/eclipse/yasson/internal/deserializer/RequiredCreatorParameter.java b/src/main/java/org/eclipse/yasson/internal/deserializer/RequiredCreatorParameter.java new file mode 100644 index 000000000..021817b85 --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/RequiredCreatorParameter.java @@ -0,0 +1,34 @@ +/* + * 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.deserializer; + +import jakarta.json.bind.JsonbException; + +import org.eclipse.yasson.internal.DeserializationContextImpl; +import org.eclipse.yasson.internal.properties.MessageKeys; +import org.eclipse.yasson.internal.properties.Messages; + +class RequiredCreatorParameter implements ModelDeserializer { + + private final String parameterName; + + RequiredCreatorParameter(String parameterName) { + this.parameterName = parameterName; + } + + @Override + public Object deserialize(Object value, DeserializationContextImpl context) { + throw new JsonbException(Messages.getMessage(MessageKeys.JSONB_CREATOR_MISSING_PROPERTY, parameterName)); + } + +} diff --git a/src/main/java/org/eclipse/yasson/internal/deserializer/UserDefinedDeserializer.java b/src/main/java/org/eclipse/yasson/internal/deserializer/UserDefinedDeserializer.java new file mode 100644 index 000000000..70ec44014 --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/UserDefinedDeserializer.java @@ -0,0 +1,75 @@ +/* + * 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.deserializer; + +import java.lang.reflect.Type; + +import jakarta.json.bind.serializer.JsonbDeserializer; +import jakarta.json.stream.JsonParser; + +import org.eclipse.yasson.internal.DeserializationContextImpl; +import org.eclipse.yasson.internal.model.customization.Customization; + +/** + * Deserializer used to invoke user defined deserializers. + */ +class UserDefinedDeserializer implements ModelDeserializer { + + private final JsonbDeserializer userDefinedDeserializer; + private final ModelDeserializer delegate; + private final Type rType; + private final Customization customization; + + //TODO remove or not? deserializer cycle + // public UserDefinedDeserializer(JsonbDeserializer userDefinedDeserializer, + // ModelDeserializer exactType, + // ModelDeserializer delegate, + // Type rType, + // Customization customization) { + // this.userDefinedDeserializer = userDefinedDeserializer; + // this.exactType = exactType; + // this.delegate = delegate; + // this.rType = rType; + // this.customization = customization; + // } + UserDefinedDeserializer(JsonbDeserializer userDefinedDeserializer, + ModelDeserializer delegate, + Type rType, + Customization customization) { + this.userDefinedDeserializer = userDefinedDeserializer; + this.delegate = delegate; + this.rType = rType; + this.customization = customization; + } + + @Override + public Object deserialize(JsonParser value, DeserializationContextImpl context) { + DeserializationContextImpl newContext = new DeserializationContextImpl(context); + newContext.setCustomization(customization); + //TODO remove or not? deserializer cycle + // if (context.getUserProcessorChain().contains(userDefinedDeserializer.getClass())) { + // if (context.getLastValueEvent() != JsonParser.Event.START_ARRAY + // && context.getLastValueEvent() != JsonParser.Event.START_OBJECT) { + // newContext.setDisableNextPositionCheck(true); + // } + // return exactType.deserialize(value, newContext); + // } + // newContext.getUserProcessorChain().add(userDefinedDeserializer.getClass()); + YassonParser yassonParser = new YassonParser(value, context.getLastValueEvent(), newContext); + Object object = userDefinedDeserializer.deserialize(yassonParser, newContext, rType); + yassonParser.skipRemaining(); + context.setLastValueEvent(newContext.getLastValueEvent()); + return delegate.deserialize(object, context); + } + +} diff --git a/src/main/java/org/eclipse/yasson/internal/deserializer/ValueExtractor.java b/src/main/java/org/eclipse/yasson/internal/deserializer/ValueExtractor.java new file mode 100644 index 000000000..f55c0494b --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/ValueExtractor.java @@ -0,0 +1,56 @@ +/* + * 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.deserializer; + +import jakarta.json.bind.JsonbException; +import jakarta.json.stream.JsonParser; + +import org.eclipse.yasson.internal.DeserializationContextImpl; +import org.eclipse.yasson.internal.deserializer.types.TypeDeserializer; + +/** + * Extracts the value out of the {@link JsonParser} based upon the last obtained event. + */ +public class ValueExtractor implements ModelDeserializer { + + private final TypeDeserializer delegate; + + /** + * Create new instance. + * + * @param delegate delegate to accept extracted value + */ + public ValueExtractor(TypeDeserializer delegate) { + this.delegate = delegate; + } + + @Override + public Object deserialize(JsonParser value, DeserializationContextImpl context) { + JsonParser.Event last = context.getLastValueEvent(); + switch (last) { + case VALUE_TRUE: + return delegate.deserialize(Boolean.TRUE, context); + case VALUE_FALSE: + return delegate.deserialize(Boolean.FALSE, context); + case KEY_NAME: + case VALUE_STRING: + return delegate.deserialize(value.getString(), context); + case VALUE_NUMBER: + //We don't know for sure how to handle the number value, it can be int, long etc. + //Value extraction has to be delegated to the TypeDeserializer + return delegate.deserialize(value, context); + default: + throw new JsonbException("Could not extract data. Received event: " + last); + } + } +} diff --git a/src/main/java/org/eclipse/yasson/internal/deserializer/ValueSetterDeserializer.java b/src/main/java/org/eclipse/yasson/internal/deserializer/ValueSetterDeserializer.java new file mode 100644 index 000000000..857e55aaf --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/ValueSetterDeserializer.java @@ -0,0 +1,44 @@ +/* + * 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.deserializer; + +import java.lang.invoke.MethodHandle; +import java.util.Objects; + +import jakarta.json.bind.JsonbException; + +import org.eclipse.yasson.internal.DeserializationContextImpl; + +/** + * Value setter. Invokes created {@link MethodHandle} to set deserialized value to the instance. + */ +class ValueSetterDeserializer implements ModelDeserializer { + + private final MethodHandle valueSetter; + + ValueSetterDeserializer(MethodHandle valueSetter) { + this.valueSetter = Objects.requireNonNull(valueSetter); + } + + @Override + public Object deserialize(Object value, DeserializationContextImpl context) { + Object object = context.getInstance(); + try { + valueSetter.invoke(object, value); + return value; + } catch (Throwable e) { + throw new JsonbException("Error setting value on: " + object, e); + } + } + +} diff --git a/src/main/java/org/eclipse/yasson/internal/deserializer/YassonParser.java b/src/main/java/org/eclipse/yasson/internal/deserializer/YassonParser.java new file mode 100644 index 000000000..c17f6ff56 --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/YassonParser.java @@ -0,0 +1,195 @@ +/* + * 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.deserializer; + +import java.math.BigDecimal; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.stream.Stream; + +import jakarta.json.JsonArray; +import jakarta.json.JsonObject; +import jakarta.json.JsonValue; +import jakarta.json.stream.JsonLocation; +import jakarta.json.stream.JsonParser; + +import org.eclipse.yasson.internal.DeserializationContextImpl; + +/** + * Yasson {@link YassonParser} parser wrapper. + *
+ * Used for user defined deserializers. Does not allow deserializer to read outside the scope it should be used on. + */ +class YassonParser implements JsonParser { + + private final JsonParser delegate; + private final DeserializationContextImpl context; + private int level; + + YassonParser(JsonParser delegate, Event firstEvent, DeserializationContextImpl context) { + this.delegate = delegate; + this.context = context; + this.level = determineLevelValue(firstEvent); + } + + private int determineLevelValue(Event firstEvent) { + switch (firstEvent) { + case START_ARRAY: + case START_OBJECT: + return 1; //container start, there will be more events to come + default: + return 0; //just this single value, do not allow reading more + } + } + + void skipRemaining() { + while (hasNext()) { + next(); + } + } + + @Override + public boolean hasNext() { + if (level < 1) { + return false; + } + return delegate.hasNext(); + } + + @Override + public Event next() { + validate(); + Event next = delegate.next(); + context.setLastValueEvent(next); + switch (next) { + case START_OBJECT: + case START_ARRAY: + level++; + break; + case END_OBJECT: + case END_ARRAY: + level--; + break; + default: + //no other changes needed + } + return next; + } + + @Override + public String getString() { + return delegate.getString(); + } + + @Override + public boolean isIntegralNumber() { + return delegate.isIntegralNumber(); + } + + @Override + public int getInt() { + return delegate.getInt(); + } + + @Override + public long getLong() { + return delegate.getLong(); + } + + @Override + public BigDecimal getBigDecimal() { + return delegate.getBigDecimal(); + } + + @Override + public JsonLocation getLocation() { + return delegate.getLocation(); + } + + @Override + public JsonObject getObject() { + validate(); + level--; + JsonObject jsonObject = delegate.getObject(); + context.setLastValueEvent(Event.END_OBJECT); + return jsonObject; + } + + @Override + public JsonValue getValue() { + final Event currentLevel = context.getLastValueEvent(); + switch (currentLevel) { + case START_ARRAY: + return getArray(); + case START_OBJECT: + return getObject(); + default: + return delegate.getValue(); + } + } + + @Override + public JsonArray getArray() { + validate(); + level--; + JsonArray array = delegate.getArray(); + context.setLastValueEvent(Event.END_ARRAY); + return array; + } + + @Override + public Stream getArrayStream() { + validate(); + level--; + return delegate.getArrayStream(); + } + + @Override + public Stream> getObjectStream() { + validate(); + level--; + return delegate.getObjectStream(); + } + + @Override + public Stream getValueStream() { + validate(); + level--; + return delegate.getValueStream(); + } + + @Override + public void skipArray() { + validate(); + level--; + delegate.skipArray(); + } + + @Override + public void skipObject() { + validate(); + level--; + delegate.skipObject(); + } + + @Override + public void close() { + throw new UnsupportedOperationException(); + } + + private void validate() { + if (level < 1) { + throw new NoSuchElementException("There are no more elements available!"); + } + } +} diff --git a/src/main/java/org/eclipse/yasson/internal/deserializer/types/AbstractDateDeserializer.java b/src/main/java/org/eclipse/yasson/internal/deserializer/types/AbstractDateDeserializer.java new file mode 100644 index 000000000..865a2431b --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/types/AbstractDateDeserializer.java @@ -0,0 +1,135 @@ +/* + * 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.deserializer.types; + +import java.lang.reflect.Type; +import java.sql.Date; +import java.time.DateTimeException; +import java.time.Instant; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.Locale; +import java.util.Optional; + +import jakarta.json.bind.JsonbException; +import jakarta.json.bind.annotation.JsonbDateFormat; + +import org.eclipse.yasson.internal.DeserializationContextImpl; +import org.eclipse.yasson.internal.JsonbConfigProperties; +import org.eclipse.yasson.internal.JsonbDateFormatter; +import org.eclipse.yasson.internal.deserializer.JustReturn; +import org.eclipse.yasson.internal.deserializer.ModelDeserializer; +import org.eclipse.yasson.internal.model.customization.Customization; +import org.eclipse.yasson.internal.properties.MessageKeys; +import org.eclipse.yasson.internal.properties.Messages; + +/** + * Base deserializer for all the date related types. + */ +abstract class AbstractDateDeserializer extends TypeDeserializer { + + static final ZoneId UTC = ZoneId.of("UTC"); + + private ModelDeserializer actualDeserializer; + + AbstractDateDeserializer(TypeDeserializerBuilder builder) { + super(builder); + this.actualDeserializer = actualDeserializer(builder.getConfigProperties(), builder.getCustomization()); + } + + AbstractDateDeserializer(Class clazz) { + super(new TypeDeserializerBuilder(clazz, null, null, JustReturn.instance())); + this.actualDeserializer = null; + } + + private ModelDeserializer actualDeserializer(JsonbConfigProperties properties, Customization customization) { + final JsonbDateFormatter formatter = getJsonbDateFormatter(properties, customization); + if (JsonbDateFormat.TIME_IN_MILLIS.equals(formatter.getFormat())) { + return (value, context) -> fromInstant(Instant.ofEpochMilli(Long.parseLong(value))); + } else if (formatter.getDateTimeFormatter() != null) { + return (value, context) -> parseWithFormatterInternal(value, formatter.getDateTimeFormatter()); + } else { + DateTimeFormatter configDateTimeFormatter = properties.getConfigDateFormatter().getDateTimeFormatter(); + if (configDateTimeFormatter != null) { + return (value, context) -> parseWithFormatterInternal(value, configDateTimeFormatter); + } + } + if (properties.isStrictIJson()) { + return (value, context) -> parseWithFormatterInternal(value, JsonbDateFormatter.IJSON_DATE_FORMATTER); + } + Locale locale = properties.getLocale(formatter.getLocale()); + return (value, context) -> { + try { + return parseDefault(value, locale); + } catch (DateTimeException e) { + throw new JsonbException(Messages.getMessage(MessageKeys.DATE_PARSE_ERROR, value, getType()), e); + } + }; + } + + private JsonbDateFormatter getJsonbDateFormatter(JsonbConfigProperties properties, Customization customization) { + return Optional.ofNullable(customization.getDeserializeDateFormatter()) + .orElse(properties.getConfigDateFormatter()); + } + + @Override + public Object deserializeStringValue(String value, DeserializationContextImpl context, Type rType) { + if (actualDeserializer == null) { + actualDeserializer = actualDeserializer(context.getJsonbContext().getConfigProperties(), context.getCustomization()); + } + return actualDeserializer.deserialize(value, context); + } + + /** + * Construct date object from an instant containing epoch millisecond. + * If date object supports zone offset / zone id, system default is used and warning is logged. + * + * @param instant instant to construct from + * @return date object + */ + abstract T fromInstant(Instant instant); + + /** + * Parse java.time date object with default formatter. + * Different default formatter for each date object type is used. + * + * @param jsonValue string value to parse from + * @param locale annotated locale or default + * @return parsed date object + */ + abstract T parseDefault(String jsonValue, Locale locale); + + /** + * Parse java.time date object with provided formatter. + * + * @param jsonValue string value to parse from + * @param formatter a formatter to use + * @return parsed date object + */ + abstract T parseWithFormatter(String jsonValue, DateTimeFormatter formatter); + + private T parseWithFormatterInternal(String jsonValue, DateTimeFormatter formatter) { + try { + return parseWithFormatter(jsonValue, formatter); + } catch (DateTimeException e) { + throw new JsonbException(Messages.getMessage(MessageKeys.DATE_PARSE_ERROR, jsonValue, getType()), e); + } + } + + protected DateTimeFormatter getZonedFormatter(DateTimeFormatter formatter) { + return formatter.getZone() != null + ? formatter + : formatter.withZone(UTC); + } + +} diff --git a/src/main/java/org/eclipse/yasson/internal/deserializer/types/AbstractNumberDeserializer.java b/src/main/java/org/eclipse/yasson/internal/deserializer/types/AbstractNumberDeserializer.java new file mode 100644 index 000000000..e50e003a1 --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/types/AbstractNumberDeserializer.java @@ -0,0 +1,92 @@ +/* + * 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.deserializer.types; + +import java.lang.reflect.Type; +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.text.NumberFormat; +import java.text.ParseException; +import java.util.Locale; +import java.util.function.Function; + +import jakarta.json.bind.JsonbException; + +import org.eclipse.yasson.internal.DeserializationContextImpl; +import org.eclipse.yasson.internal.JsonbNumberFormatter; +import org.eclipse.yasson.internal.deserializer.ModelDeserializer; +import org.eclipse.yasson.internal.model.customization.Customization; +import org.eclipse.yasson.internal.properties.MessageKeys; +import org.eclipse.yasson.internal.properties.Messages; + +/** + * Base deserializer for all the number types. + */ +abstract class AbstractNumberDeserializer extends TypeDeserializer { + + private final ModelDeserializer actualDeserializer; + private final boolean integerOnly; + + AbstractNumberDeserializer(TypeDeserializerBuilder builder, boolean integerOnly) { + super(builder); + this.actualDeserializer = actualDeserializer(builder); + this.integerOnly = integerOnly; + } + + private ModelDeserializer actualDeserializer(TypeDeserializerBuilder builder) { + Customization customization = builder.getCustomization(); + if (customization.getDeserializeNumberFormatter() == null) { + return (value, context) -> { + try { + return parseNumberValue(value); + } catch (NumberFormatException e) { + throw new JsonbException(Messages.getMessage(MessageKeys.DESERIALIZE_VALUE_ERROR, getType()), e); + } + }; + } + + final JsonbNumberFormatter numberFormat = customization.getDeserializeNumberFormatter(); + //consider synchronizing on format instance or per thread cache. + Locale locale = builder.getConfigProperties().getLocale(numberFormat.getLocale()); + final NumberFormat format = NumberFormat.getInstance(locale); + ((DecimalFormat) format).applyPattern(numberFormat.getFormat()); + format.setParseIntegerOnly(integerOnly); + Function valueChanger = createCompatibilityValueChanger(locale); + return (value, context) -> { + try { + String updated = valueChanger.apply(value); + return parseNumberValue(String.valueOf(format.parse(updated))); + } catch (ParseException e) { + throw new JsonbException(Messages.getMessage(MessageKeys.PARSING_NUMBER, value, numberFormat.getFormat()), e); + } + }; + } + + private Function createCompatibilityValueChanger(Locale locale) { + char beforeJdk13GroupSeparator = '\u00A0'; + char frenchGroupingSeparator = DecimalFormatSymbols.getInstance(Locale.FRENCH).getGroupingSeparator(); + if (locale.getLanguage().equals(Locale.FRENCH.getLanguage()) && beforeJdk13GroupSeparator != frenchGroupingSeparator) { + //JDK-8225245 + return value -> value.replace(beforeJdk13GroupSeparator, frenchGroupingSeparator); + } + return value -> value; + } + + abstract T parseNumberValue(String value); + + @Override + Object deserializeStringValue(String value, DeserializationContextImpl context, Type rType) { + return actualDeserializer.deserialize(value, context); + } + +} diff --git a/src/main/java/org/eclipse/yasson/internal/deserializer/types/BigDecimalDeserializer.java b/src/main/java/org/eclipse/yasson/internal/deserializer/types/BigDecimalDeserializer.java new file mode 100644 index 000000000..7eda5b762 --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/types/BigDecimalDeserializer.java @@ -0,0 +1,30 @@ +/* + * 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.deserializer.types; + +import java.math.BigDecimal; + +/** + * Deserializer of the {@link BigDecimal} type. + */ +class BigDecimalDeserializer extends AbstractNumberDeserializer { + + BigDecimalDeserializer(TypeDeserializerBuilder builder) { + super(builder, false); + } + + @Override + BigDecimal parseNumberValue(String value) { + return new BigDecimal(value); + } +} diff --git a/src/main/java/org/eclipse/yasson/internal/deserializer/types/BigIntegerDeserializer.java b/src/main/java/org/eclipse/yasson/internal/deserializer/types/BigIntegerDeserializer.java new file mode 100644 index 000000000..92670bb42 --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/types/BigIntegerDeserializer.java @@ -0,0 +1,30 @@ +/* + * 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.deserializer.types; + +import java.math.BigInteger; + +/** + * Deserializer of the {@link BigInteger} type. + */ +class BigIntegerDeserializer extends AbstractNumberDeserializer { + + BigIntegerDeserializer(TypeDeserializerBuilder builder) { + super(builder, true); + } + + @Override + BigInteger parseNumberValue(String value) { + return new BigInteger(value); + } +} diff --git a/src/main/java/org/eclipse/yasson/internal/deserializer/types/BooleanDeserializer.java b/src/main/java/org/eclipse/yasson/internal/deserializer/types/BooleanDeserializer.java new file mode 100644 index 000000000..ddbf0bb7d --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/types/BooleanDeserializer.java @@ -0,0 +1,37 @@ +/* + * 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.deserializer.types; + +import java.lang.reflect.Type; + +import org.eclipse.yasson.internal.DeserializationContextImpl; + +/** + * Deserializer of the {@link Boolean} type. + */ +class BooleanDeserializer extends TypeDeserializer { + + BooleanDeserializer(TypeDeserializerBuilder builder) { + super(builder); + } + + @Override + public Object deserializeStringValue(String value, DeserializationContextImpl context, Type rType) { + return Boolean.parseBoolean(value); + } + + @Override + Object deserializeBooleanValue(boolean value, DeserializationContextImpl context, Type rType) { + return value; + } +} diff --git a/src/main/java/org/eclipse/yasson/internal/deserializer/types/ByteDeserializer.java b/src/main/java/org/eclipse/yasson/internal/deserializer/types/ByteDeserializer.java new file mode 100644 index 000000000..21762ed36 --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/types/ByteDeserializer.java @@ -0,0 +1,29 @@ +/* + * 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.deserializer.types; + +/** + * Deserializer of the {@link Byte} type. + */ +class ByteDeserializer extends AbstractNumberDeserializer { + + ByteDeserializer(TypeDeserializerBuilder builder) { + super(builder, true); + } + + @Override + Byte parseNumberValue(String value) { + return Byte.parseByte(value); + } + +} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/CalendarTypeDeserializer.java b/src/main/java/org/eclipse/yasson/internal/deserializer/types/CalendarDeserializer.java similarity index 72% rename from src/main/java/org/eclipse/yasson/internal/serializer/CalendarTypeDeserializer.java rename to src/main/java/org/eclipse/yasson/internal/deserializer/types/CalendarDeserializer.java index 18ebf9254..b933d810a 100644 --- a/src/main/java/org/eclipse/yasson/internal/serializer/CalendarTypeDeserializer.java +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/types/CalendarDeserializer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2020 Oracle and/or its affiliates. All rights reserved. + * 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 @@ -10,7 +10,7 @@ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ -package org.eclipse.yasson.internal.serializer; +package org.eclipse.yasson.internal.deserializer.types; import java.time.Instant; import java.time.LocalDate; @@ -25,38 +25,31 @@ import java.util.Locale; import java.util.TimeZone; -import org.eclipse.yasson.internal.model.customization.Customization; - /** - * Deserializer for {@link Calendar} type. + * Deserializer of the {@link Calendar} type. */ -public class CalendarTypeDeserializer extends AbstractDateTimeDeserializer { +class CalendarDeserializer extends AbstractDateDeserializer { private static final LocalTime ZERO_LOCAL_TIME = LocalTime.parse("00:00:00"); private final Calendar calendarTemplate; - /** - * Creates an instance. - * - * @param customization Model customization. - */ - public CalendarTypeDeserializer(Customization customization) { - super(Calendar.class, customization); + CalendarDeserializer(TypeDeserializerBuilder builder) { + super(builder); this.calendarTemplate = new GregorianCalendar(); this.calendarTemplate.clear(); this.calendarTemplate.setTimeZone(TimeZone.getTimeZone(UTC)); } @Override - protected Calendar fromInstant(Instant instant) { + Calendar fromInstant(Instant instant) { final Calendar calendar = (Calendar) calendarTemplate.clone(); calendar.setTimeInMillis(instant.toEpochMilli()); return calendar; } @Override - protected Calendar parseDefault(String jsonValue, Locale locale) { + Calendar parseDefault(String jsonValue, Locale locale) { DateTimeFormatter formatter = jsonValue.contains("T") ? DateTimeFormatter.ISO_DATE_TIME : DateTimeFormatter.ISO_DATE; @@ -64,7 +57,7 @@ protected Calendar parseDefault(String jsonValue, Locale locale) { } @Override - protected Calendar parseWithFormatter(String jsonValue, DateTimeFormatter formatter) { + Calendar parseWithFormatter(String jsonValue, DateTimeFormatter formatter) { final TemporalAccessor parsed = formatter.parse(jsonValue); LocalTime time = parsed.query(TemporalQueries.localTime()); ZoneId zone = parsed.query(TemporalQueries.zone()); diff --git a/src/main/java/org/eclipse/yasson/internal/deserializer/types/CharDeserializer.java b/src/main/java/org/eclipse/yasson/internal/deserializer/types/CharDeserializer.java new file mode 100644 index 000000000..aeb1b6a5d --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/types/CharDeserializer.java @@ -0,0 +1,32 @@ +/* + * 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.deserializer.types; + +import java.lang.reflect.Type; + +import org.eclipse.yasson.internal.DeserializationContextImpl; + +/** + * Deserializer of the {@link Character} type. + */ +class CharDeserializer extends TypeDeserializer { + + CharDeserializer(TypeDeserializerBuilder builder) { + super(builder); + } + + @Override + Object deserializeStringValue(String value, DeserializationContextImpl context, Type rType) { + return value.charAt(0); + } +} diff --git a/src/main/java/org/eclipse/yasson/internal/deserializer/types/DateDeserializer.java b/src/main/java/org/eclipse/yasson/internal/deserializer/types/DateDeserializer.java new file mode 100644 index 000000000..723cdbe79 --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/types/DateDeserializer.java @@ -0,0 +1,57 @@ +/* + * 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.deserializer.types; + +import java.time.Instant; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Date; +import java.util.Locale; + +/** + * Deserializer of the {@link Date} type. + */ +class DateDeserializer extends AbstractDateDeserializer { + + private static final DateTimeFormatter DEFAULT_DATE_TIME_FORMATTER = DateTimeFormatter.ISO_DATE_TIME; + + DateDeserializer(TypeDeserializerBuilder builder) { + super(builder); + } + + @Override + Date fromInstant(Instant instant) { + return new Date(instant.toEpochMilli()); + } + + @Override + Date parseDefault(String jsonValue, Locale locale) { + return parseWithOrWithoutZone(jsonValue, DEFAULT_DATE_TIME_FORMATTER.withLocale(locale)); + } + + @Override + Date parseWithFormatter(String jsonValue, DateTimeFormatter formatter) { + return parseWithOrWithoutZone(jsonValue, formatter); + } + + private static Date parseWithOrWithoutZone(String jsonValue, DateTimeFormatter formatter) { + ZonedDateTime parsed; + if (formatter.getZone() == null) { + parsed = ZonedDateTime.parse(jsonValue, formatter.withZone(UTC)); + } else { + parsed = ZonedDateTime.parse(jsonValue, formatter); + } + return Date.from(parsed.toInstant()); + } + +} diff --git a/src/main/java/org/eclipse/yasson/internal/deserializer/types/DoubleDeserializer.java b/src/main/java/org/eclipse/yasson/internal/deserializer/types/DoubleDeserializer.java new file mode 100644 index 000000000..f64fe5982 --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/types/DoubleDeserializer.java @@ -0,0 +1,29 @@ +/* + * 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.deserializer.types; + +/** + * Deserializer of the {@link Double} type. + */ +class DoubleDeserializer extends AbstractNumberDeserializer { + + DoubleDeserializer(TypeDeserializerBuilder builder) { + super(builder, false); + } + + @Override + Double parseNumberValue(String value) { + return Double.parseDouble(value); + } + +} diff --git a/src/main/java/org/eclipse/yasson/internal/deserializer/types/DurationDeserializer.java b/src/main/java/org/eclipse/yasson/internal/deserializer/types/DurationDeserializer.java new file mode 100644 index 000000000..438b4bd0d --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/types/DurationDeserializer.java @@ -0,0 +1,34 @@ +/* + * 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.deserializer.types; + +import java.lang.reflect.Type; +import java.time.Duration; + +import org.eclipse.yasson.internal.DeserializationContextImpl; + +/** + * Deserializer of the {@link Duration} type. + */ +class DurationDeserializer extends TypeDeserializer { + + DurationDeserializer(TypeDeserializerBuilder builder) { + super(builder); + } + + @Override + public Object deserializeStringValue(String value, DeserializationContextImpl context, Type rType) { + return Duration.parse(value); + } + +} diff --git a/src/main/java/org/eclipse/yasson/internal/deserializer/types/EnumDeserializer.java b/src/main/java/org/eclipse/yasson/internal/deserializer/types/EnumDeserializer.java new file mode 100644 index 000000000..f32aeb86e --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/types/EnumDeserializer.java @@ -0,0 +1,33 @@ +/* + * 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.deserializer.types; + +import java.lang.reflect.Type; + +import org.eclipse.yasson.internal.DeserializationContextImpl; + +/** + * Deserializer of the {@link Enum}. + */ +class EnumDeserializer extends TypeDeserializer { + + EnumDeserializer(TypeDeserializerBuilder builder) { + super(builder); + } + + @SuppressWarnings("unchecked") + @Override + Object deserializeStringValue(String value, DeserializationContextImpl context, Type rType) { + return Enum.valueOf((Class) rType, value); + } +} diff --git a/src/main/java/org/eclipse/yasson/internal/deserializer/types/FloatDeserializer.java b/src/main/java/org/eclipse/yasson/internal/deserializer/types/FloatDeserializer.java new file mode 100644 index 000000000..83dde61d5 --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/types/FloatDeserializer.java @@ -0,0 +1,29 @@ +/* + * 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.deserializer.types; + +/** + * Deserializer of the {@link Float} type. + */ +class FloatDeserializer extends AbstractNumberDeserializer { + + FloatDeserializer(TypeDeserializerBuilder builder) { + super(builder, false); + } + + @Override + Float parseNumberValue(String value) { + return Float.parseFloat(value); + } + +} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/InstantTypeDeserializer.java b/src/main/java/org/eclipse/yasson/internal/deserializer/types/InstantDeserializer.java similarity index 67% rename from src/main/java/org/eclipse/yasson/internal/serializer/InstantTypeDeserializer.java rename to src/main/java/org/eclipse/yasson/internal/deserializer/types/InstantDeserializer.java index d0f837aab..f00e5219b 100644 --- a/src/main/java/org/eclipse/yasson/internal/serializer/InstantTypeDeserializer.java +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/types/InstantDeserializer.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 @@ -10,28 +10,21 @@ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ -package org.eclipse.yasson.internal.serializer; +package org.eclipse.yasson.internal.deserializer.types; import java.time.Instant; import java.time.format.DateTimeFormatter; import java.util.Locale; -import org.eclipse.yasson.internal.model.customization.Customization; - /** - * Deserializer for {@link Instant} type. + * Deserializer of the {@link Instant} type. */ -public class InstantTypeDeserializer extends AbstractDateTimeDeserializer { +class InstantDeserializer extends AbstractDateDeserializer { private static final DateTimeFormatter DEFAULT_FORMATTER = DateTimeFormatter.ISO_INSTANT.withZone(UTC); - /** - * Creates an instance. - * - * @param customization Model customization. - */ - public InstantTypeDeserializer(Customization customization) { - super(Instant.class, customization); + InstantDeserializer(TypeDeserializerBuilder builder) { + super(builder); } @Override diff --git a/src/main/java/org/eclipse/yasson/internal/deserializer/types/IntegerDeserializer.java b/src/main/java/org/eclipse/yasson/internal/deserializer/types/IntegerDeserializer.java new file mode 100644 index 000000000..73a503749 --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/types/IntegerDeserializer.java @@ -0,0 +1,39 @@ +/* + * 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.deserializer.types; + +import java.lang.reflect.Type; + +import jakarta.json.stream.JsonParser; + +import org.eclipse.yasson.internal.DeserializationContextImpl; + +/** + * Deserializer of the {@link Integer} type. + */ +class IntegerDeserializer extends AbstractNumberDeserializer { + + IntegerDeserializer(TypeDeserializerBuilder builder) { + super(builder, true); + } + + @Override + Integer parseNumberValue(String value) { + return Integer.parseInt(value); + } + + @Override + Object deserializeNumberValue(JsonParser value, DeserializationContextImpl context, Type rType) { + return value.getInt(); + } +} diff --git a/src/main/java/org/eclipse/yasson/internal/deserializer/types/JsonValueDeserializer.java b/src/main/java/org/eclipse/yasson/internal/deserializer/types/JsonValueDeserializer.java new file mode 100644 index 000000000..db609c08a --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/types/JsonValueDeserializer.java @@ -0,0 +1,60 @@ +/* + * 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.deserializer.types; + +import jakarta.json.JsonValue; +import jakarta.json.bind.JsonbException; +import jakarta.json.stream.JsonParser; + +import org.eclipse.yasson.internal.DeserializationContextImpl; +import org.eclipse.yasson.internal.deserializer.ModelDeserializer; +import org.eclipse.yasson.internal.properties.MessageKeys; +import org.eclipse.yasson.internal.properties.Messages; + +/** + * Deserializer of the {@link JsonValue} type. + */ +class JsonValueDeserializer implements ModelDeserializer { + + private final ModelDeserializer delegate; + + JsonValueDeserializer(TypeDeserializerBuilder builder) { + delegate = builder.getDelegate(); + } + + @Override + public Object deserialize(JsonParser value, DeserializationContextImpl context) { + JsonParser.Event last = context.getLastValueEvent(); + return delegate.deserialize(deserializeValue(last, value), context); + } + + private JsonValue deserializeValue(JsonParser.Event last, JsonParser parser) { + switch (last) { + case VALUE_TRUE: + return JsonValue.TRUE; + case VALUE_FALSE: + return JsonValue.FALSE; + case VALUE_NULL: + return JsonValue.NULL; + case VALUE_STRING: + case VALUE_NUMBER: + return parser.getValue(); + case START_OBJECT: + return parser.getObject(); + case START_ARRAY: + return parser.getArray(); + default: + throw new JsonbException(Messages.getMessage(MessageKeys.INTERNAL_ERROR, "Unknown JSON value: " + last)); + } + } +} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/LocalDateTypeDeserializer.java b/src/main/java/org/eclipse/yasson/internal/deserializer/types/LocalDateDeserializer.java similarity index 65% rename from src/main/java/org/eclipse/yasson/internal/serializer/LocalDateTypeDeserializer.java rename to src/main/java/org/eclipse/yasson/internal/deserializer/types/LocalDateDeserializer.java index 0631edec7..a38e72793 100644 --- a/src/main/java/org/eclipse/yasson/internal/serializer/LocalDateTypeDeserializer.java +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/types/LocalDateDeserializer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2020 Oracle and/or its affiliates. All rights reserved. + * 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 @@ -10,27 +10,20 @@ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ -package org.eclipse.yasson.internal.serializer; +package org.eclipse.yasson.internal.deserializer.types; import java.time.Instant; import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.util.Locale; -import org.eclipse.yasson.internal.model.customization.Customization; - /** - * Deserializer for {@link LocalDate} type. + * Deserializer of the {@link LocalDate} type. */ -public class LocalDateTypeDeserializer extends AbstractDateTimeDeserializer { +class LocalDateDeserializer extends AbstractDateDeserializer { - /** - * Creates a new instance. - * - * @param customization Customization model. - */ - public LocalDateTypeDeserializer(Customization customization) { - super(LocalDate.class, customization); + LocalDateDeserializer(TypeDeserializerBuilder builder) { + super(builder); } @Override diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/LocalDateTimeTypeDeserializer.java b/src/main/java/org/eclipse/yasson/internal/deserializer/types/LocalDateTimeDeserializer.java similarity index 65% rename from src/main/java/org/eclipse/yasson/internal/serializer/LocalDateTimeTypeDeserializer.java rename to src/main/java/org/eclipse/yasson/internal/deserializer/types/LocalDateTimeDeserializer.java index 94a68f9cd..111a1e0de 100644 --- a/src/main/java/org/eclipse/yasson/internal/serializer/LocalDateTimeTypeDeserializer.java +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/types/LocalDateTimeDeserializer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2020 Oracle and/or its affiliates. All rights reserved. + * 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 @@ -10,27 +10,20 @@ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ -package org.eclipse.yasson.internal.serializer; +package org.eclipse.yasson.internal.deserializer.types; import java.time.Instant; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.Locale; -import org.eclipse.yasson.internal.model.customization.Customization; - /** - * Deserializer for {@link LocalDateTime} type. + * Deserializer of the {@link LocalDateTime} type. */ -public class LocalDateTimeTypeDeserializer extends AbstractDateTimeDeserializer { +class LocalDateTimeDeserializer extends AbstractDateDeserializer { - /** - * Creates an instance. - * - * @param customization Model customization. - */ - public LocalDateTimeTypeDeserializer(Customization customization) { - super(LocalDateTime.class, customization); + LocalDateTimeDeserializer(TypeDeserializerBuilder builder) { + super(builder); } @Override diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/LocalTimeTypeDeserializer.java b/src/main/java/org/eclipse/yasson/internal/deserializer/types/LocalTimeDeserializer.java similarity index 70% rename from src/main/java/org/eclipse/yasson/internal/serializer/LocalTimeTypeDeserializer.java rename to src/main/java/org/eclipse/yasson/internal/deserializer/types/LocalTimeDeserializer.java index 9935cc5d9..979e2a179 100644 --- a/src/main/java/org/eclipse/yasson/internal/serializer/LocalTimeTypeDeserializer.java +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/types/LocalTimeDeserializer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2020 Oracle and/or its affiliates. All rights reserved. + * 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 @@ -10,7 +10,7 @@ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ -package org.eclipse.yasson.internal.serializer; +package org.eclipse.yasson.internal.deserializer.types; import java.time.Instant; import java.time.LocalTime; @@ -19,22 +19,16 @@ import jakarta.json.bind.JsonbException; -import org.eclipse.yasson.internal.model.customization.Customization; import org.eclipse.yasson.internal.properties.MessageKeys; import org.eclipse.yasson.internal.properties.Messages; /** - * Deserializer for {@link LocalTime} type. + * Deserializer of the {@link LocalTime} type. */ -public class LocalTimeTypeDeserializer extends AbstractDateTimeDeserializer { - - /** - * Creates an instance. - * - * @param customization Model customization. - */ - public LocalTimeTypeDeserializer(Customization customization) { - super(LocalTime.class, customization); +class LocalTimeDeserializer extends AbstractDateDeserializer { + + LocalTimeDeserializer(TypeDeserializerBuilder builder) { + super(builder); } @Override diff --git a/src/main/java/org/eclipse/yasson/internal/deserializer/types/LongDeserializer.java b/src/main/java/org/eclipse/yasson/internal/deserializer/types/LongDeserializer.java new file mode 100644 index 000000000..24f0eb730 --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/types/LongDeserializer.java @@ -0,0 +1,39 @@ +/* + * 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.deserializer.types; + +import java.lang.reflect.Type; + +import jakarta.json.stream.JsonParser; + +import org.eclipse.yasson.internal.DeserializationContextImpl; + +/** + * Deserializer of the {@link Long} type. + */ +class LongDeserializer extends AbstractNumberDeserializer { + + LongDeserializer(TypeDeserializerBuilder builder) { + super(builder, true); + } + + @Override + Long parseNumberValue(String value) { + return Long.parseLong(value); + } + + @Override + Object deserializeNumberValue(JsonParser value, DeserializationContextImpl context, Type rType) { + return value.getLong(); + } +} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/MonthDayTypeDeserializer.java b/src/main/java/org/eclipse/yasson/internal/deserializer/types/MonthDayTypeDeserializer.java similarity index 67% rename from src/main/java/org/eclipse/yasson/internal/serializer/MonthDayTypeDeserializer.java rename to src/main/java/org/eclipse/yasson/internal/deserializer/types/MonthDayTypeDeserializer.java index 6a680b523..89fb1d199 100644 --- a/src/main/java/org/eclipse/yasson/internal/serializer/MonthDayTypeDeserializer.java +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/types/MonthDayTypeDeserializer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. + * 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 @@ -10,29 +10,22 @@ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ -package org.eclipse.yasson.internal.serializer; +package org.eclipse.yasson.internal.deserializer.types; import java.time.Instant; import java.time.MonthDay; import java.time.format.DateTimeFormatter; import java.util.Locale; -import org.eclipse.yasson.internal.model.customization.Customization; - /** - * Deserializer for {@link MonthDay} type. + * Deserializer of the {@link MonthDay} type. */ -public class MonthDayTypeDeserializer extends AbstractDateTimeDeserializer { +class MonthDayTypeDeserializer extends AbstractDateDeserializer { private static final DateTimeFormatter DEFAULT_FORMAT = DateTimeFormatter.ofPattern("--MM-dd").withZone(UTC); - /** - * Creates an instance. - * - * @param customization Model customization. - */ - public MonthDayTypeDeserializer(Customization customization) { - super(MonthDay.class, customization); + MonthDayTypeDeserializer(TypeDeserializerBuilder builder) { + super(builder); } @Override diff --git a/src/main/java/org/eclipse/yasson/internal/deserializer/types/NumberDeserializer.java b/src/main/java/org/eclipse/yasson/internal/deserializer/types/NumberDeserializer.java new file mode 100644 index 000000000..a21f44422 --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/types/NumberDeserializer.java @@ -0,0 +1,34 @@ +/* + * 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.deserializer.types; + +import java.lang.reflect.Type; +import java.math.BigDecimal; + +import org.eclipse.yasson.internal.DeserializationContextImpl; + +/** + * Deserializer of the {@link Number} type. + */ +class NumberDeserializer extends TypeDeserializer { + + NumberDeserializer(TypeDeserializerBuilder builder) { + super(builder); + } + + @Override + Object deserializeStringValue(String value, DeserializationContextImpl context, Type rType) { + return new BigDecimal(value); + } + +} diff --git a/src/main/java/org/eclipse/yasson/internal/deserializer/types/ObjectTypeDeserializer.java b/src/main/java/org/eclipse/yasson/internal/deserializer/types/ObjectTypeDeserializer.java new file mode 100644 index 000000000..3f3d7aa3b --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/types/ObjectTypeDeserializer.java @@ -0,0 +1,71 @@ +/* + * 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.deserializer.types; + +import java.lang.reflect.Type; +import java.math.BigDecimal; +import java.util.List; + +import jakarta.json.bind.JsonbException; +import jakarta.json.stream.JsonParser; + +import org.eclipse.yasson.internal.DeserializationContextImpl; +import org.eclipse.yasson.internal.deserializer.ModelDeserializer; + +/** + * Deserializer of the {@link Object} type. + */ +class ObjectTypeDeserializer implements ModelDeserializer { + + private static final Type LIST = List.class; + + private final ModelDeserializer delegate; + private final Class mapClass; + + ObjectTypeDeserializer(TypeDeserializerBuilder builder) { + this.delegate = builder.getDelegate(); + this.mapClass = builder.getConfigProperties().getDefaultMapImplType(); + } + + @Override + public Object deserialize(JsonParser value, DeserializationContextImpl context) { + Object toSet; + switch (context.getLastValueEvent()) { + case VALUE_TRUE: + toSet = Boolean.TRUE; + break; + case VALUE_FALSE: + toSet = Boolean.FALSE; + break; + case VALUE_NUMBER: + toSet = new BigDecimal(value.getString()); + break; + case KEY_NAME: + case VALUE_STRING: + toSet = value.getString(); + break; + case START_OBJECT: + DeserializationContextImpl newContext = new DeserializationContextImpl(context); + toSet = newContext.deserialize(mapClass, value); + break; + case START_ARRAY: + DeserializationContextImpl newContext1 = new DeserializationContextImpl(context); + toSet = newContext1.deserialize(LIST, value); + break; + default: + throw new JsonbException("Unexpected event: " + context.getLastValueEvent()); + } + return delegate.deserialize(toSet, context); + } + +} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/OffsetDateTimeTypeDeserializer.java b/src/main/java/org/eclipse/yasson/internal/deserializer/types/OffsetDateTimeDeserializer.java similarity index 72% rename from src/main/java/org/eclipse/yasson/internal/serializer/OffsetDateTimeTypeDeserializer.java rename to src/main/java/org/eclipse/yasson/internal/deserializer/types/OffsetDateTimeDeserializer.java index aa7b24484..5ae090bef 100644 --- a/src/main/java/org/eclipse/yasson/internal/serializer/OffsetDateTimeTypeDeserializer.java +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/types/OffsetDateTimeDeserializer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2020 Oracle and/or its affiliates. All rights reserved. + * 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 @@ -10,7 +10,7 @@ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ -package org.eclipse.yasson.internal.serializer; +package org.eclipse.yasson.internal.deserializer.types; import java.time.Instant; import java.time.OffsetDateTime; @@ -18,24 +18,18 @@ import java.util.Locale; import java.util.logging.Logger; -import org.eclipse.yasson.internal.model.customization.Customization; import org.eclipse.yasson.internal.properties.MessageKeys; import org.eclipse.yasson.internal.properties.Messages; /** - * Deserializer for {@link OffsetDateTime} type. + * Deserializer of the {@link OffsetDateTime} type. */ -public class OffsetDateTimeTypeDeserializer extends AbstractDateTimeDeserializer { +class OffsetDateTimeDeserializer extends AbstractDateDeserializer { - private static final Logger LOGGER = Logger.getLogger(OffsetDateTimeTypeDeserializer.class.getName()); + private static final Logger LOGGER = Logger.getLogger(OffsetDateTimeDeserializer.class.getName()); - /** - * Creates an instance. - * - * @param customization Model customization. - */ - public OffsetDateTimeTypeDeserializer(Customization customization) { - super(OffsetDateTime.class, customization); + OffsetDateTimeDeserializer(TypeDeserializerBuilder builder) { + super(builder); } /** diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/OffsetTimeTypeDeserializer.java b/src/main/java/org/eclipse/yasson/internal/deserializer/types/OffsetTimeDeserializer.java similarity index 70% rename from src/main/java/org/eclipse/yasson/internal/serializer/OffsetTimeTypeDeserializer.java rename to src/main/java/org/eclipse/yasson/internal/deserializer/types/OffsetTimeDeserializer.java index f5554d447..7d9d14c5d 100644 --- a/src/main/java/org/eclipse/yasson/internal/serializer/OffsetTimeTypeDeserializer.java +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/types/OffsetTimeDeserializer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2020 Oracle and/or its affiliates. All rights reserved. + * 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 @@ -10,7 +10,7 @@ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ -package org.eclipse.yasson.internal.serializer; +package org.eclipse.yasson.internal.deserializer.types; import java.time.Instant; import java.time.OffsetTime; @@ -19,22 +19,16 @@ import jakarta.json.bind.JsonbException; -import org.eclipse.yasson.internal.model.customization.Customization; import org.eclipse.yasson.internal.properties.MessageKeys; import org.eclipse.yasson.internal.properties.Messages; /** - * Deserializer for {@link OffsetTime} type. + * Deserializer of the {@link OffsetTime} type. */ -public class OffsetTimeTypeDeserializer extends AbstractDateTimeDeserializer { - - /** - * Creates an instance. - * - * @param customization Model customization. - */ - public OffsetTimeTypeDeserializer(Customization customization) { - super(OffsetTime.class, customization); +class OffsetTimeDeserializer extends AbstractDateDeserializer { + + OffsetTimeDeserializer(TypeDeserializerBuilder builder) { + super(builder); } @Override diff --git a/src/main/java/org/eclipse/yasson/internal/deserializer/types/OptionalDoubleDeserializer.java b/src/main/java/org/eclipse/yasson/internal/deserializer/types/OptionalDoubleDeserializer.java new file mode 100644 index 000000000..d898a434c --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/types/OptionalDoubleDeserializer.java @@ -0,0 +1,43 @@ +/* + * 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.deserializer.types; + +import java.util.OptionalDouble; + +import jakarta.json.stream.JsonParser; + +import org.eclipse.yasson.internal.DeserializationContextImpl; +import org.eclipse.yasson.internal.deserializer.ModelDeserializer; + +/** + * Deserializer of the {@link OptionalDouble} type. + */ +class OptionalDoubleDeserializer implements ModelDeserializer { + + private final ModelDeserializer extractor; + private final ModelDeserializer nullValueDelegate; + + OptionalDoubleDeserializer(ModelDeserializer extractor, ModelDeserializer nullValueDelegate) { + this.extractor = extractor; + this.nullValueDelegate = nullValueDelegate; + } + + @Override + public Object deserialize(JsonParser value, DeserializationContextImpl context) { + if (context.getLastValueEvent() == JsonParser.Event.VALUE_NULL) { + return nullValueDelegate.deserialize(OptionalDouble.empty(), context); + } + OptionalDouble optional = OptionalDouble.of((Double) extractor.deserialize(value, context)); + return nullValueDelegate.deserialize(optional, context); + } +} diff --git a/src/main/java/org/eclipse/yasson/internal/deserializer/types/OptionalIntDeserializer.java b/src/main/java/org/eclipse/yasson/internal/deserializer/types/OptionalIntDeserializer.java new file mode 100644 index 000000000..261d8c69d --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/types/OptionalIntDeserializer.java @@ -0,0 +1,43 @@ +/* + * 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.deserializer.types; + +import java.util.OptionalInt; + +import jakarta.json.stream.JsonParser; + +import org.eclipse.yasson.internal.DeserializationContextImpl; +import org.eclipse.yasson.internal.deserializer.ModelDeserializer; + +/** + * Deserializer of the {@link OptionalInt} type. + */ +class OptionalIntDeserializer implements ModelDeserializer { + + private final ModelDeserializer extractor; + private final ModelDeserializer delegate; + + OptionalIntDeserializer(ModelDeserializer extractor, ModelDeserializer delegate) { + this.extractor = extractor; + this.delegate = delegate; + } + + @Override + public Object deserialize(JsonParser value, DeserializationContextImpl context) { + if (context.getLastValueEvent() == JsonParser.Event.VALUE_NULL) { + return delegate.deserialize(OptionalInt.empty(), context); + } + OptionalInt optional = OptionalInt.of((Integer) extractor.deserialize(value, context)); + return delegate.deserialize(optional, context); + } +} diff --git a/src/main/java/org/eclipse/yasson/internal/deserializer/types/OptionalLongDeserializer.java b/src/main/java/org/eclipse/yasson/internal/deserializer/types/OptionalLongDeserializer.java new file mode 100644 index 000000000..1501cca1a --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/types/OptionalLongDeserializer.java @@ -0,0 +1,43 @@ +/* + * 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.deserializer.types; + +import java.util.OptionalLong; + +import jakarta.json.stream.JsonParser; + +import org.eclipse.yasson.internal.DeserializationContextImpl; +import org.eclipse.yasson.internal.deserializer.ModelDeserializer; + +/** + * Deserializer of the {@link OptionalLong} type. + */ +class OptionalLongDeserializer implements ModelDeserializer { + + private final ModelDeserializer extractor; + private final ModelDeserializer nullValueDelegate; + + OptionalLongDeserializer(ModelDeserializer extractor, ModelDeserializer nullValueDelegate) { + this.extractor = extractor; + this.nullValueDelegate = nullValueDelegate; + } + + @Override + public Object deserialize(JsonParser value, DeserializationContextImpl context) { + if (context.getLastValueEvent() == JsonParser.Event.VALUE_NULL) { + return nullValueDelegate.deserialize(OptionalLong.empty(), context); + } + OptionalLong optional = OptionalLong.of((Long) extractor.deserialize(value, context)); + return nullValueDelegate.deserialize(optional, context); + } +} diff --git a/src/main/java/org/eclipse/yasson/internal/deserializer/types/PathDeserializer.java b/src/main/java/org/eclipse/yasson/internal/deserializer/types/PathDeserializer.java new file mode 100644 index 000000000..0bae35d91 --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/types/PathDeserializer.java @@ -0,0 +1,33 @@ +/* + * 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.deserializer.types; + +import java.lang.reflect.Type; +import java.nio.file.Paths; + +import org.eclipse.yasson.internal.DeserializationContextImpl; + +/** + * Deserializer of the {@link java.nio.file.Path} type. + */ +class PathDeserializer extends TypeDeserializer { + + PathDeserializer(TypeDeserializerBuilder builder) { + super(builder); + } + + @Override + Object deserializeStringValue(String value, DeserializationContextImpl context, Type rType) { + return Paths.get(value); + } +} diff --git a/src/main/java/org/eclipse/yasson/internal/deserializer/types/PeriodDeserializer.java b/src/main/java/org/eclipse/yasson/internal/deserializer/types/PeriodDeserializer.java new file mode 100644 index 000000000..2fb4aad27 --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/types/PeriodDeserializer.java @@ -0,0 +1,33 @@ +/* + * 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.deserializer.types; + +import java.lang.reflect.Type; +import java.time.Period; + +import org.eclipse.yasson.internal.DeserializationContextImpl; + +/** + * Deserializer of the {@link Period} type. + */ +class PeriodDeserializer extends TypeDeserializer { + + PeriodDeserializer(TypeDeserializerBuilder builder) { + super(builder); + } + + @Override + Object deserializeStringValue(String value, DeserializationContextImpl context, Type rType) { + return Period.parse(value); + } +} diff --git a/src/main/java/org/eclipse/yasson/internal/deserializer/types/ShortDeserializer.java b/src/main/java/org/eclipse/yasson/internal/deserializer/types/ShortDeserializer.java new file mode 100644 index 000000000..01e2cf2e1 --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/types/ShortDeserializer.java @@ -0,0 +1,29 @@ +/* + * 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.deserializer.types; + +/** + * Deserializer of the {@link Short} type. + */ +class ShortDeserializer extends AbstractNumberDeserializer { + + ShortDeserializer(TypeDeserializerBuilder builder) { + super(builder, true); + } + + @Override + Short parseNumberValue(String value) { + return Short.parseShort(value); + } + +} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/SqlDateTypeDeserializer.java b/src/main/java/org/eclipse/yasson/internal/deserializer/types/SqlDateDeserializer.java similarity index 53% rename from src/main/java/org/eclipse/yasson/internal/serializer/SqlDateTypeDeserializer.java rename to src/main/java/org/eclipse/yasson/internal/deserializer/types/SqlDateDeserializer.java index 626482667..0ff1eabf7 100644 --- a/src/main/java/org/eclipse/yasson/internal/serializer/SqlDateTypeDeserializer.java +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/types/SqlDateDeserializer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020 Oracle and/or its affiliates. All rights reserved. + * 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 @@ -9,37 +9,38 @@ * * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ -package org.eclipse.yasson.internal.serializer; +package org.eclipse.yasson.internal.deserializer.types; + +import java.lang.reflect.Type; import java.sql.Date; import java.time.Instant; import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.util.Locale; -import org.eclipse.yasson.internal.model.customization.Customization; +import jakarta.json.bind.serializer.DeserializationContext; +import jakarta.json.bind.serializer.JsonbDeserializer; +import jakarta.json.stream.JsonParser; + +import org.eclipse.yasson.internal.DeserializationContextImpl; /** - * Deserializer for {@link Date} type. + * Deserializer of the {@link Date} type. */ -public class SqlDateTypeDeserializer extends AbstractDateTimeDeserializer { +public class SqlDateDeserializer extends AbstractDateDeserializer implements JsonbDeserializer { private static final DateTimeFormatter DEFAULT_FORMATTER = DateTimeFormatter.ISO_DATE.withZone(UTC); - /** - * Creates an instance. - * - * @param customization Model customization. - */ - public SqlDateTypeDeserializer(Customization customization) { - super(Date.class, customization); + SqlDateDeserializer(TypeDeserializerBuilder builder) { + super(builder); } /** - * No arg constructor in order ot make usable in {@link jakarta.json.bind.annotation.JsonbTypeDeserializer}. + * Create new instance. */ - public SqlDateTypeDeserializer() { - super(Date.class, null); + public SqlDateDeserializer() { + super(Date.class); } @Override @@ -49,11 +50,17 @@ protected Date fromInstant(Instant instant) { @Override protected Date parseDefault(String jsonValue, Locale locale) { - return Date.valueOf(LocalDate.parse(jsonValue, DEFAULT_FORMATTER)); + return Date.valueOf(LocalDate.parse(jsonValue, DEFAULT_FORMATTER.withLocale(locale))); } @Override protected Date parseWithFormatter(String jsonValue, DateTimeFormatter formatter) { return Date.valueOf(LocalDate.parse(jsonValue, formatter)); } + + @Override + public Date deserialize(JsonParser parser, DeserializationContext ctx, Type rtType) { + DeserializationContextImpl context = (DeserializationContextImpl) ctx; + return (Date) deserialize(parser.getString(), context); + } } diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/SqlTimestampTypeDeserializer.java b/src/main/java/org/eclipse/yasson/internal/deserializer/types/SqlTimestampDeserializer.java similarity index 66% rename from src/main/java/org/eclipse/yasson/internal/serializer/SqlTimestampTypeDeserializer.java rename to src/main/java/org/eclipse/yasson/internal/deserializer/types/SqlTimestampDeserializer.java index b8a534359..b0ffee892 100644 --- a/src/main/java/org/eclipse/yasson/internal/serializer/SqlTimestampTypeDeserializer.java +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/types/SqlTimestampDeserializer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * 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 @@ -10,7 +10,7 @@ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ -package org.eclipse.yasson.internal.serializer; +package org.eclipse.yasson.internal.deserializer.types; import java.sql.Timestamp; import java.time.Instant; @@ -20,29 +20,15 @@ import java.time.temporal.TemporalAccessor; import java.util.Locale; -import org.eclipse.yasson.internal.model.customization.Customization; - /** - * Deserializer for {@link java.sql.Timestamp} type. + * Deserializer of the {@link Timestamp} type. */ -public class SqlTimestampTypeDeserializer extends AbstractDateTimeDeserializer { +class SqlTimestampDeserializer extends AbstractDateDeserializer { private static final DateTimeFormatter DEFAULT_FORMATTER = DateTimeFormatter.ISO_DATE_TIME.withZone(UTC); - /** - * Creates an instance. - * - * @param customization Model customization. - */ - public SqlTimestampTypeDeserializer(Customization customization) { - super(Timestamp.class, customization); - } - - /** - * No arg constructor in order to make usable in {@link jakarta.json.bind.annotation.JsonbTypeDeserializer}. - */ - public SqlTimestampTypeDeserializer() { - super(Timestamp.class, null); + SqlTimestampDeserializer(TypeDeserializerBuilder builder) { + super(builder); } @Override diff --git a/src/main/java/org/eclipse/yasson/internal/deserializer/types/StringDeserializer.java b/src/main/java/org/eclipse/yasson/internal/deserializer/types/StringDeserializer.java new file mode 100644 index 000000000..f1061cd6c --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/types/StringDeserializer.java @@ -0,0 +1,49 @@ +/* + * 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.deserializer.types; + +import java.lang.reflect.Type; +import java.nio.charset.StandardCharsets; + +import jakarta.json.bind.JsonbException; + +import org.eclipse.yasson.internal.DeserializationContextImpl; +import org.eclipse.yasson.internal.JsonbConfigProperties; +import org.eclipse.yasson.internal.properties.MessageKeys; +import org.eclipse.yasson.internal.properties.Messages; + +/** + * Deserializer of the {@link String} type. + */ +class StringDeserializer extends TypeDeserializer { + + StringDeserializer(TypeDeserializerBuilder builder) { + super(builder); + } + + @Override + public Object deserializeStringValue(String value, DeserializationContextImpl context, Type rType) { + JsonbConfigProperties config = context.getJsonbContext().getConfigProperties(); + return checkIJson(value, config); + } + + private String checkIJson(String value, JsonbConfigProperties config) { + if (config.isStrictIJson()) { + String newString = new String(value.getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8); + if (!newString.equals(value)) { + throw new JsonbException(Messages.getMessage(MessageKeys.UNPAIRED_SURROGATE)); + } + } + return value; + } +} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/TimeZoneTypeDeserializer.java b/src/main/java/org/eclipse/yasson/internal/deserializer/types/TimeZoneDeserializer.java similarity index 58% rename from src/main/java/org/eclipse/yasson/internal/serializer/TimeZoneTypeDeserializer.java rename to src/main/java/org/eclipse/yasson/internal/deserializer/types/TimeZoneDeserializer.java index c03c11f99..b225114a7 100644 --- a/src/main/java/org/eclipse/yasson/internal/serializer/TimeZoneTypeDeserializer.java +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/types/TimeZoneDeserializer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2020 Oracle and/or its affiliates. All rights reserved. + * 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 @@ -10,7 +10,7 @@ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ -package org.eclipse.yasson.internal.serializer; +package org.eclipse.yasson.internal.deserializer.types; import java.lang.reflect.Type; import java.time.LocalDateTime; @@ -18,38 +18,30 @@ import java.time.ZonedDateTime; import java.time.zone.ZoneRulesException; import java.util.SimpleTimeZone; -import java.util.TimeZone; import jakarta.json.bind.JsonbException; -import org.eclipse.yasson.internal.Unmarshaller; -import org.eclipse.yasson.internal.model.customization.Customization; +import org.eclipse.yasson.internal.DeserializationContextImpl; import org.eclipse.yasson.internal.properties.MessageKeys; import org.eclipse.yasson.internal.properties.Messages; /** - * Deserializer for {@link TimeZone} type. + * Deserializer of the {@link java.util.TimeZone} type. */ -public class TimeZoneTypeDeserializer extends AbstractValueTypeDeserializer { +class TimeZoneDeserializer extends TypeDeserializer { - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public TimeZoneTypeDeserializer(Customization customization) { - super(TimeZone.class, customization); + TimeZoneDeserializer(TypeDeserializerBuilder builder) { + super(builder); } @Override - protected TimeZone deserialize(String jsonValue, Unmarshaller unmarshaller, Type rtType) { + Object deserializeStringValue(String value, DeserializationContextImpl context, Type rType) { try { - final ZoneId zoneId = ZoneId.of(jsonValue); + final ZoneId zoneId = ZoneId.of(value); final ZonedDateTime zonedDateTime = LocalDateTime.now().atZone(zoneId); return new SimpleTimeZone(zonedDateTime.getOffset().getTotalSeconds() * 1000, zoneId.getId()); } catch (ZoneRulesException e) { - throw new JsonbException(Messages.getMessage(MessageKeys.ZONE_PARSE_ERROR, jsonValue), e); + throw new JsonbException(Messages.getMessage(MessageKeys.ZONE_PARSE_ERROR, value), e); } } - } diff --git a/src/main/java/org/eclipse/yasson/internal/deserializer/types/TypeDeserializer.java b/src/main/java/org/eclipse/yasson/internal/deserializer/types/TypeDeserializer.java new file mode 100644 index 000000000..0c7354fb6 --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/types/TypeDeserializer.java @@ -0,0 +1,62 @@ +/* + * 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.deserializer.types; + +import java.lang.reflect.Type; + +import jakarta.json.stream.JsonParser; + +import org.eclipse.yasson.internal.DeserializationContextImpl; +import org.eclipse.yasson.internal.deserializer.ModelDeserializer; + +/** + * Base for all type deserializers. + */ +public abstract class TypeDeserializer implements ModelDeserializer { + + private final ModelDeserializer delegate; + private final Class clazz; + + TypeDeserializer(TypeDeserializerBuilder builder) { + this.delegate = builder.getDelegate(); + this.clazz = builder.getClazz(); + } + + @Override + public final Object deserialize(String value, DeserializationContextImpl context) { + return delegate.deserialize(deserializeStringValue(value, context, clazz), context); + } + + public final Object deserialize(boolean value, DeserializationContextImpl context) { + return delegate.deserialize(deserializeBooleanValue(value, context, clazz), context); + } + + public final Object deserialize(JsonParser value, DeserializationContextImpl context) { + return delegate.deserialize(deserializeNumberValue(value, context, clazz), context); + } + + abstract Object deserializeStringValue(String value, DeserializationContextImpl context, Type rType); + + Object deserializeBooleanValue(boolean value, DeserializationContextImpl context, Type rType) { + return deserializeStringValue(String.valueOf(value), context, rType); + } + + Object deserializeNumberValue(JsonParser value, DeserializationContextImpl context, Type rType) { + return deserializeStringValue(value.getString(), context, rType); + } + + Class getType() { + return clazz; + } + +} diff --git a/src/main/java/org/eclipse/yasson/internal/deserializer/types/TypeDeserializerBuilder.java b/src/main/java/org/eclipse/yasson/internal/deserializer/types/TypeDeserializerBuilder.java new file mode 100644 index 000000000..c15ee2fc1 --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/types/TypeDeserializerBuilder.java @@ -0,0 +1,55 @@ +/* + * 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.deserializer.types; + +import java.util.Objects; + +import org.eclipse.yasson.internal.JsonbConfigProperties; +import org.eclipse.yasson.internal.deserializer.ModelDeserializer; +import org.eclipse.yasson.internal.model.customization.ClassCustomization; +import org.eclipse.yasson.internal.model.customization.Customization; + +class TypeDeserializerBuilder { + + private final Class clazz; + private final Customization customization; + private final JsonbConfigProperties configProperties; + private final ModelDeserializer delegate; + + TypeDeserializerBuilder(Class clazz, + Customization customization, + JsonbConfigProperties configProperties, + ModelDeserializer delegate) { + this.clazz = Objects.requireNonNull(clazz); + this.customization = customization == null ? ClassCustomization.empty() : customization; + this.configProperties = configProperties; + this.delegate = Objects.requireNonNull(delegate); + } + + public Class getClazz() { + return clazz; + } + + public JsonbConfigProperties getConfigProperties() { + return configProperties; + } + + public ModelDeserializer getDelegate() { + return delegate; + } + + public Customization getCustomization() { + return customization; + } + +} diff --git a/src/main/java/org/eclipse/yasson/internal/deserializer/types/TypeDeserializers.java b/src/main/java/org/eclipse/yasson/internal/deserializer/types/TypeDeserializers.java new file mode 100644 index 000000000..e6e98cbb8 --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/types/TypeDeserializers.java @@ -0,0 +1,196 @@ +/* + * 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.deserializer.types; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.net.URI; +import java.net.URL; +import java.nio.file.Path; +import java.sql.Timestamp; +import java.time.Duration; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.MonthDay; +import java.time.OffsetDateTime; +import java.time.OffsetTime; +import java.time.Period; +import java.time.YearMonth; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.HashMap; +import java.util.Map; +import java.util.OptionalDouble; +import java.util.OptionalInt; +import java.util.OptionalLong; +import java.util.Set; +import java.util.SimpleTimeZone; +import java.util.TimeZone; +import java.util.UUID; +import java.util.function.Function; + +import javax.xml.datatype.XMLGregorianCalendar; + +import jakarta.json.JsonValue; +import jakarta.json.bind.JsonbException; +import jakarta.json.stream.JsonParser; + +import org.eclipse.yasson.internal.JsonbConfigProperties; +import org.eclipse.yasson.internal.deserializer.JustReturn; +import org.eclipse.yasson.internal.deserializer.ModelDeserializer; +import org.eclipse.yasson.internal.deserializer.NullCheckDeserializer; +import org.eclipse.yasson.internal.deserializer.PositionChecker; +import org.eclipse.yasson.internal.deserializer.ValueExtractor; +import org.eclipse.yasson.internal.model.customization.Customization; + +import static org.eclipse.yasson.internal.BuiltInTypes.isClassAvailable; + +/** + * Specific type deserializers. + */ +public class TypeDeserializers { + + private static final Map, Function> DESERIALIZERS = + new HashMap<>(); + private static final Map, Class> OPTIONAL_TYPES = new HashMap<>(); + + static { + DESERIALIZERS.put(BigInteger.class, BigIntegerDeserializer::new); + DESERIALIZERS.put(BigDecimal.class, BigDecimalDeserializer::new); + DESERIALIZERS.put(Boolean.class, BooleanDeserializer::new); + DESERIALIZERS.put(Boolean.TYPE, BooleanDeserializer::new); + DESERIALIZERS.put(Byte.class, ByteDeserializer::new); + DESERIALIZERS.put(Byte.TYPE, ByteDeserializer::new); + DESERIALIZERS.put(Calendar.class, CalendarDeserializer::new); + DESERIALIZERS.put(Character.TYPE, CharDeserializer::new); + DESERIALIZERS.put(Character.class, CharDeserializer::new); + DESERIALIZERS.put(Date.class, DateDeserializer::new); + DESERIALIZERS.put(Double.class, DoubleDeserializer::new); + DESERIALIZERS.put(Double.TYPE, DoubleDeserializer::new); + DESERIALIZERS.put(Duration.class, DurationDeserializer::new); + DESERIALIZERS.put(Float.class, FloatDeserializer::new); + DESERIALIZERS.put(Float.TYPE, FloatDeserializer::new); + DESERIALIZERS.put(GregorianCalendar.class, CalendarDeserializer::new); + DESERIALIZERS.put(Instant.class, InstantDeserializer::new); + DESERIALIZERS.put(Integer.class, IntegerDeserializer::new); + DESERIALIZERS.put(Integer.TYPE, IntegerDeserializer::new); + DESERIALIZERS.put(LocalDate.class, LocalDateDeserializer::new); + DESERIALIZERS.put(LocalDateTime.class, LocalDateTimeDeserializer::new); + DESERIALIZERS.put(LocalTime.class, LocalTimeDeserializer::new); + DESERIALIZERS.put(Long.class, LongDeserializer::new); + DESERIALIZERS.put(Long.TYPE, LongDeserializer::new); + DESERIALIZERS.put(MonthDay.class, MonthDayTypeDeserializer::new); + DESERIALIZERS.put(Number.class, NumberDeserializer::new); + DESERIALIZERS.put(OffsetDateTime.class, OffsetDateTimeDeserializer::new); + DESERIALIZERS.put(OffsetTime.class, OffsetTimeDeserializer::new); + DESERIALIZERS.put(Path.class, PathDeserializer::new); + DESERIALIZERS.put(Period.class, PeriodDeserializer::new); + DESERIALIZERS.put(Short.class, ShortDeserializer::new); + DESERIALIZERS.put(Short.TYPE, ShortDeserializer::new); + DESERIALIZERS.put(String.class, StringDeserializer::new); + DESERIALIZERS.put(SimpleTimeZone.class, TimeZoneDeserializer::new); + DESERIALIZERS.put(TimeZone.class, TimeZoneDeserializer::new); + DESERIALIZERS.put(URI.class, UriDeserializer::new); + DESERIALIZERS.put(URL.class, UrlDeserializer::new); + DESERIALIZERS.put(UUID.class, UuidDeserializer::new); + if (isClassAvailable("javax.xml.datatype.XMLGregorianCalendar")) { + DESERIALIZERS.put(XMLGregorianCalendar.class, XmlGregorianCalendarDeserializer::new); + } + DESERIALIZERS.put(YearMonth.class, YearMonthTypeDeserializer::new); + DESERIALIZERS.put(ZonedDateTime.class, ZonedDateTimeDeserializer::new); + DESERIALIZERS.put(ZoneId.class, ZoneIdDeserializer::new); + DESERIALIZERS.put(ZoneOffset.class, ZoneOffsetDeserializer::new); + if (isClassAvailable("java.sql.Date")) { + DESERIALIZERS.put(java.sql.Date.class, SqlDateDeserializer::new); + DESERIALIZERS.put(Timestamp.class, SqlTimestampDeserializer::new); + } + + OPTIONAL_TYPES.put(OptionalLong.class, Long.class); + OPTIONAL_TYPES.put(OptionalInt.class, Integer.class); + OPTIONAL_TYPES.put(OptionalDouble.class, Double.class); + } + + private TypeDeserializers() { + throw new IllegalStateException("Utility classes cannot be instantiated"); + } + + /** + * Return deserializer for the given type. + * + * @param clazz type to create deserializer for + * @param customization type customization + * @param properties config properties + * @param delegate delegate to be called by the created deserializer + * @param events expected parser events at the beginning when deserializing the type + * @return type deserializer + */ + public static ModelDeserializer getTypeDeserializer(Class clazz, + Customization customization, + JsonbConfigProperties properties, + ModelDeserializer delegate, + Set events) { + JsonParser.Event[] eventArray = events.toArray(new JsonParser.Event[0]); + if (OPTIONAL_TYPES.containsKey(clazz)) { + Class optionalType = OPTIONAL_TYPES.get(clazz); + TypeDeserializerBuilder builder = new TypeDeserializerBuilder(optionalType, + customization, + properties, + JustReturn.instance()); + ValueExtractor valueExtractor = new ValueExtractor(DESERIALIZERS.get(optionalType).apply(builder)); + PositionChecker positionChecker = new PositionChecker(valueExtractor, clazz, eventArray); + if (OptionalLong.class.equals(clazz)) { + return new OptionalLongDeserializer(positionChecker, delegate); + } else if (OptionalInt.class.equals(clazz)) { + return new OptionalIntDeserializer(positionChecker, delegate); + } else if (OptionalDouble.class.equals(clazz)) { + return new OptionalDoubleDeserializer(positionChecker, delegate); + } else { + throw new JsonbException("Unsupported Optional type for deserialization: " + clazz); + } + } + + TypeDeserializerBuilder builder = new TypeDeserializerBuilder(clazz, customization, properties, delegate); + if (DESERIALIZERS.containsKey(clazz)) { + ValueExtractor valueExtractor = new ValueExtractor(DESERIALIZERS.get(clazz).apply(builder)); + return new NullCheckDeserializer(new PositionChecker(valueExtractor, clazz, eventArray), delegate); + } + + if (JsonValue.class.isAssignableFrom(builder.getClazz())) { + return new JsonValueDeserializer(builder); + } + ModelDeserializer deserializer = assignableCases(builder, eventArray); + if (deserializer != null) { + return new NullCheckDeserializer(deserializer, delegate); + } + return null; + } + + private static ModelDeserializer assignableCases(TypeDeserializerBuilder builder, + JsonParser.Event[] checker) { + if (Enum.class.isAssignableFrom(builder.getClazz())) { + return new PositionChecker(new ValueExtractor(new EnumDeserializer(builder)), + builder.getClazz(), + checker); + } else if (Object.class.equals(builder.getClazz())) { + return new ObjectTypeDeserializer(builder); + } + return null; + } + +} diff --git a/src/main/java/org/eclipse/yasson/internal/deserializer/types/UriDeserializer.java b/src/main/java/org/eclipse/yasson/internal/deserializer/types/UriDeserializer.java new file mode 100644 index 000000000..26ea0fb8e --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/types/UriDeserializer.java @@ -0,0 +1,33 @@ +/* + * 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.deserializer.types; + +import java.lang.reflect.Type; +import java.net.URI; + +import org.eclipse.yasson.internal.DeserializationContextImpl; + +/** + * Deserializer of the {@link URI} type. + */ +class UriDeserializer extends TypeDeserializer { + + UriDeserializer(TypeDeserializerBuilder builder) { + super(builder); + } + + @Override + Object deserializeStringValue(String value, DeserializationContextImpl context, Type rType) { + return URI.create(value); + } +} diff --git a/src/main/java/org/eclipse/yasson/internal/deserializer/types/UrlDeserializer.java b/src/main/java/org/eclipse/yasson/internal/deserializer/types/UrlDeserializer.java new file mode 100644 index 000000000..54cd2f346 --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/types/UrlDeserializer.java @@ -0,0 +1,40 @@ +/* + * 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.deserializer.types; + +import java.lang.reflect.Type; +import java.net.MalformedURLException; +import java.net.URL; + +import org.eclipse.yasson.internal.DeserializationContextImpl; + +/** + * Deserializer of the {@link URL} type. + */ +class UrlDeserializer extends TypeDeserializer { + + UrlDeserializer(TypeDeserializerBuilder builder) { + super(builder); + } + + @Override + Object deserializeStringValue(String value, DeserializationContextImpl context, Type rType) { + URL url = null; + try { + url = new URL(value); + } catch (MalformedURLException e) { + e.printStackTrace(); + } + return url; + } +} diff --git a/src/main/java/org/eclipse/yasson/internal/deserializer/types/UuidDeserializer.java b/src/main/java/org/eclipse/yasson/internal/deserializer/types/UuidDeserializer.java new file mode 100644 index 000000000..732484968 --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/types/UuidDeserializer.java @@ -0,0 +1,33 @@ +/* + * 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.deserializer.types; + +import java.lang.reflect.Type; +import java.util.UUID; + +import org.eclipse.yasson.internal.DeserializationContextImpl; + +/** + * Deserializer of the {@link UUID} type. + */ +class UuidDeserializer extends TypeDeserializer { + + UuidDeserializer(TypeDeserializerBuilder builder) { + super(builder); + } + + @Override + Object deserializeStringValue(String value, DeserializationContextImpl context, Type rType) { + return UUID.fromString(value); + } +} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/XMLGregorianCalendarTypeDeserializer.java b/src/main/java/org/eclipse/yasson/internal/deserializer/types/XmlGregorianCalendarDeserializer.java similarity index 83% rename from src/main/java/org/eclipse/yasson/internal/serializer/XMLGregorianCalendarTypeDeserializer.java rename to src/main/java/org/eclipse/yasson/internal/deserializer/types/XmlGregorianCalendarDeserializer.java index 894bee4f8..bb246bc09 100644 --- a/src/main/java/org/eclipse/yasson/internal/serializer/XMLGregorianCalendarTypeDeserializer.java +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/types/XmlGregorianCalendarDeserializer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020 Oracle and/or its affiliates. All rights reserved. + * 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 @@ -10,7 +10,7 @@ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ -package org.eclipse.yasson.internal.serializer; +package org.eclipse.yasson.internal.deserializer.types; import java.time.Instant; import java.time.LocalDate; @@ -25,33 +25,27 @@ import java.util.Locale; import java.util.TimeZone; -import jakarta.json.bind.JsonbException; - import javax.xml.datatype.DatatypeConfigurationException; import javax.xml.datatype.DatatypeFactory; import javax.xml.datatype.XMLGregorianCalendar; -import org.eclipse.yasson.internal.model.customization.Customization; +import jakarta.json.bind.JsonbException; + import org.eclipse.yasson.internal.properties.MessageKeys; import org.eclipse.yasson.internal.properties.Messages; /** - * Deserializer for {@link XMLGregorianCalendar} type. + * Deserializer of the {@link XMLGregorianCalendar} type. */ -public class XMLGregorianCalendarTypeDeserializer extends AbstractDateTimeDeserializer { +class XmlGregorianCalendarDeserializer extends AbstractDateDeserializer { private static final LocalTime ZERO_LOCAL_TIME = LocalTime.parse("00:00:00"); private final Calendar calendarTemplate; private final DatatypeFactory datatypeFactory; - /** - * Creates an instance. - * - * @param customization Model customization. - */ - public XMLGregorianCalendarTypeDeserializer(Customization customization) { - super(XMLGregorianCalendar.class, customization); + XmlGregorianCalendarDeserializer(TypeDeserializerBuilder builder) { + super(builder); this.calendarTemplate = new GregorianCalendar(); this.calendarTemplate.clear(); this.calendarTemplate.setTimeZone(TimeZone.getTimeZone(UTC)); diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/YearMonthTypeDeserializer.java b/src/main/java/org/eclipse/yasson/internal/deserializer/types/YearMonthTypeDeserializer.java similarity index 67% rename from src/main/java/org/eclipse/yasson/internal/serializer/YearMonthTypeDeserializer.java rename to src/main/java/org/eclipse/yasson/internal/deserializer/types/YearMonthTypeDeserializer.java index 350c401c8..30f1d3673 100644 --- a/src/main/java/org/eclipse/yasson/internal/serializer/YearMonthTypeDeserializer.java +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/types/YearMonthTypeDeserializer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. + * 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 @@ -10,29 +10,22 @@ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ -package org.eclipse.yasson.internal.serializer; +package org.eclipse.yasson.internal.deserializer.types; import java.time.Instant; import java.time.YearMonth; import java.time.format.DateTimeFormatter; import java.util.Locale; -import org.eclipse.yasson.internal.model.customization.Customization; - /** - * Deserializer for {@link YearMonth} type. + * Deserializer of the {@link YearMonth} type. */ -public class YearMonthTypeDeserializer extends AbstractDateTimeDeserializer { +class YearMonthTypeDeserializer extends AbstractDateDeserializer { private static final DateTimeFormatter DEFAULT_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM").withZone(UTC); - /** - * Creates an instance. - * - * @param customization Model customization. - */ - public YearMonthTypeDeserializer(Customization customization) { - super(YearMonth.class, customization); + YearMonthTypeDeserializer(TypeDeserializerBuilder builder) { + super(builder); } @Override diff --git a/src/main/java/org/eclipse/yasson/internal/deserializer/types/ZoneIdDeserializer.java b/src/main/java/org/eclipse/yasson/internal/deserializer/types/ZoneIdDeserializer.java new file mode 100644 index 000000000..4ece9a01d --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/types/ZoneIdDeserializer.java @@ -0,0 +1,33 @@ +/* + * 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.deserializer.types; + +import java.lang.reflect.Type; +import java.time.ZoneId; + +import org.eclipse.yasson.internal.DeserializationContextImpl; + +/** + * Deserializer of the {@link ZoneId} type. + */ +class ZoneIdDeserializer extends TypeDeserializer { + + ZoneIdDeserializer(TypeDeserializerBuilder builder) { + super(builder); + } + + @Override + Object deserializeStringValue(String value, DeserializationContextImpl context, Type rType) { + return ZoneId.of(value); + } +} diff --git a/src/main/java/org/eclipse/yasson/internal/deserializer/types/ZoneOffsetDeserializer.java b/src/main/java/org/eclipse/yasson/internal/deserializer/types/ZoneOffsetDeserializer.java new file mode 100644 index 000000000..a4eeb73e3 --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/types/ZoneOffsetDeserializer.java @@ -0,0 +1,33 @@ +/* + * 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.deserializer.types; + +import java.lang.reflect.Type; +import java.time.ZoneOffset; + +import org.eclipse.yasson.internal.DeserializationContextImpl; + +/** + * Deserializer of the {@link ZoneOffset} type. + */ +class ZoneOffsetDeserializer extends TypeDeserializer { + + ZoneOffsetDeserializer(TypeDeserializerBuilder builder) { + super(builder); + } + + @Override + Object deserializeStringValue(String value, DeserializationContextImpl context, Type rType) { + return ZoneOffset.of(value); + } +} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/ZonedDateTimeTypeDeserializer.java b/src/main/java/org/eclipse/yasson/internal/deserializer/types/ZonedDateTimeDeserializer.java similarity index 73% rename from src/main/java/org/eclipse/yasson/internal/serializer/ZonedDateTimeTypeDeserializer.java rename to src/main/java/org/eclipse/yasson/internal/deserializer/types/ZonedDateTimeDeserializer.java index b322dfdea..ba4db980c 100644 --- a/src/main/java/org/eclipse/yasson/internal/serializer/ZonedDateTimeTypeDeserializer.java +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/types/ZonedDateTimeDeserializer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2020 Oracle and/or its affiliates. All rights reserved. + * 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 @@ -10,7 +10,7 @@ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ -package org.eclipse.yasson.internal.serializer; +package org.eclipse.yasson.internal.deserializer.types; import java.time.Instant; import java.time.ZonedDateTime; @@ -18,24 +18,18 @@ import java.util.Locale; import java.util.logging.Logger; -import org.eclipse.yasson.internal.model.customization.Customization; import org.eclipse.yasson.internal.properties.MessageKeys; import org.eclipse.yasson.internal.properties.Messages; /** - * Deserializer for {@link ZonedDateTime} type. + * Deserializer of the {@link ZonedDateTime} type. */ -public class ZonedDateTimeTypeDeserializer extends AbstractDateTimeDeserializer { +class ZonedDateTimeDeserializer extends AbstractDateDeserializer { - private static final Logger LOGGER = Logger.getLogger(ZonedDateTimeTypeDeserializer.class.getName()); + private static final Logger LOGGER = Logger.getLogger(ZonedDateTimeDeserializer.class.getName()); - /** - * Creates an instance. - * - * @param customization Model customization. - */ - public ZonedDateTimeTypeDeserializer(Customization customization) { - super(ZonedDateTime.class, customization); + ZonedDateTimeDeserializer(TypeDeserializerBuilder builder) { + super(builder); } /** diff --git a/src/main/java/org/eclipse/yasson/internal/jsonstructure/JsonObjectIterator.java b/src/main/java/org/eclipse/yasson/internal/jsonstructure/JsonObjectIterator.java index 2ba327967..4ba94c7dc 100644 --- a/src/main/java/org/eclipse/yasson/internal/jsonstructure/JsonObjectIterator.java +++ b/src/main/java/org/eclipse/yasson/internal/jsonstructure/JsonObjectIterator.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 @@ -111,6 +111,9 @@ public boolean hasNext() { * @return Current JsonValue. */ public JsonValue getValue() { + if (state == State.START && currentKey == null) { + return jsonObject; + } return jsonObject.get(currentKey); } diff --git a/src/main/java/org/eclipse/yasson/internal/jsonstructure/JsonStructureToParserAdapter.java b/src/main/java/org/eclipse/yasson/internal/jsonstructure/JsonStructureToParserAdapter.java index 45784bea9..94d378215 100644 --- a/src/main/java/org/eclipse/yasson/internal/jsonstructure/JsonStructureToParserAdapter.java +++ b/src/main/java/org/eclipse/yasson/internal/jsonstructure/JsonStructureToParserAdapter.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 @@ -100,6 +100,12 @@ public BigDecimal getBigDecimal() { return getJsonNumberValue().bigDecimalValue(); } + @Override + public JsonObject getObject() { +// ((JsonObjectIterator) iterators.peek()).jsonObject + return iterators.peek().getValue().asJsonObject(); + } + private JsonNumber getJsonNumberValue() { JsonStructureIterator iterator = iterators.peek(); JsonValue value = iterator.getValue(); diff --git a/src/main/java/org/eclipse/yasson/internal/model/AnnotationTarget.java b/src/main/java/org/eclipse/yasson/internal/model/AnnotationTarget.java index 323b08d88..566c9f232 100644 --- a/src/main/java/org/eclipse/yasson/internal/model/AnnotationTarget.java +++ b/src/main/java/org/eclipse/yasson/internal/model/AnnotationTarget.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 @@ -12,10 +12,12 @@ package org.eclipse.yasson.internal.model; +import org.eclipse.yasson.internal.JsonbNumberFormatter; + /** * Represents the place in which a JSON annotation is applied. Some business functionalities are different based on whether * annotation (e.g. - * {@link jakarta.json.bind.annotation.JsonbTransient}, {@link org.eclipse.yasson.internal.serializer.JsonbNumberFormatter}, etc + * {@link jakarta.json.bind.annotation.JsonbTransient}, {@link JsonbNumberFormatter}, etc * .) is being applied on * getter method, setter method or directly on the property. */ diff --git a/src/main/java/org/eclipse/yasson/internal/model/ClassModel.java b/src/main/java/org/eclipse/yasson/internal/model/ClassModel.java index 6cb11cf60..7355360f3 100644 --- a/src/main/java/org/eclipse/yasson/internal/model/ClassModel.java +++ b/src/main/java/org/eclipse/yasson/internal/model/ClassModel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 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 @@ -111,7 +111,8 @@ private PropertyModel searchProperty(ClassModel classModel, String jsonReadName) } /** - * Check if name is equal according to property strategy. In case of {@link CaseInsensitiveStrategy} ignore case. + * Check if name is equal according to property strategy. + * In case of {@link StrategiesProvider#CASE_INSENSITIVE_STRATEGY} ignore case. * User can provide own strategy implementation, cast to custom interface is not an option. * * @return True if names are equal. diff --git a/src/main/java/org/eclipse/yasson/internal/model/CreatorModel.java b/src/main/java/org/eclipse/yasson/internal/model/CreatorModel.java index 8473eb82d..3ab3d9054 100644 --- a/src/main/java/org/eclipse/yasson/internal/model/CreatorModel.java +++ b/src/main/java/org/eclipse/yasson/internal/model/CreatorModel.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 @@ -12,15 +12,17 @@ package org.eclipse.yasson.internal.model; +import java.lang.reflect.Executable; import java.lang.reflect.Parameter; import java.lang.reflect.Type; import org.eclipse.yasson.internal.AnnotationIntrospector; import org.eclipse.yasson.internal.JsonbContext; -import org.eclipse.yasson.internal.model.customization.ClassCustomizationBuilder; +import org.eclipse.yasson.internal.JsonbDateFormatter; +import org.eclipse.yasson.internal.JsonbNumberFormatter; +import org.eclipse.yasson.internal.components.AdapterBinding; +import org.eclipse.yasson.internal.components.DeserializerBinding; import org.eclipse.yasson.internal.model.customization.CreatorCustomization; -import org.eclipse.yasson.internal.serializer.JsonbDateFormatter; -import org.eclipse.yasson.internal.serializer.JsonbNumberFormatter; /** * Parameter for creator constructor / method model. @@ -35,27 +37,39 @@ public class CreatorModel { /** * Creates a new instance. - * - * @param name Parameter name + * @param name Parameter name * @param parameter constructor parameter + * @param executable creator executable * @param context jsonb context */ - public CreatorModel(String name, Parameter parameter, JsonbContext context) { + public CreatorModel(String name, Parameter parameter, Executable executable, JsonbContext context) { this.name = name; this.type = parameter.getParameterizedType(); AnnotationIntrospector annotationIntrospector = context.getAnnotationIntrospector(); JsonbAnnotatedElement annotated = new JsonbAnnotatedElement<>(parameter); + boolean required = context.getAnnotationIntrospector().requiredParameters(executable, annotated); JsonbNumberFormatter constructorNumberFormatter = context.getAnnotationIntrospector() .getConstructorNumberFormatter(annotated); JsonbDateFormatter constructorDateFormatter = context.getAnnotationIntrospector().getConstructorDateFormatter(annotated); + DeserializerBinding deserializerBinding = annotationIntrospector.getDeserializerBinding(parameter); + AdapterBinding adapterBinding = annotationIntrospector.getAdapterBinding(parameter); final JsonbAnnotatedElement> clsElement = annotationIntrospector.collectAnnotations(parameter.getType()); - final ClassCustomizationBuilder builder = new ClassCustomizationBuilder(); - builder.setAdapterInfo(annotationIntrospector.getAdapterBinding(clsElement)); - builder.setDeserializerBinding(annotationIntrospector.getDeserializerBinding(clsElement)); - builder.setSerializerBinding(annotationIntrospector.getSerializerBinding(clsElement)); - this.creatorCustomization = new CreatorCustomization(builder, constructorNumberFormatter, constructorDateFormatter); + deserializerBinding = deserializerBinding == null + ? annotationIntrospector.getDeserializerBinding(clsElement) + : deserializerBinding; + adapterBinding = adapterBinding == null + ? annotationIntrospector.getAdapterBinding(clsElement) + : adapterBinding; + this.creatorCustomization = CreatorCustomization.builder() + .adapterBinding(adapterBinding) + .deserializerBinding(deserializerBinding) + .serializerBinding(annotationIntrospector.getSerializerBinding(clsElement)) + .numberFormatter(constructorNumberFormatter) + .dateFormatter(constructorDateFormatter) + .required(required) + .build(); } /** diff --git a/src/main/java/org/eclipse/yasson/internal/model/JsonbAnnotatedElement.java b/src/main/java/org/eclipse/yasson/internal/model/JsonbAnnotatedElement.java index 3a863a33e..89a0c9222 100644 --- a/src/main/java/org/eclipse/yasson/internal/model/JsonbAnnotatedElement.java +++ b/src/main/java/org/eclipse/yasson/internal/model/JsonbAnnotatedElement.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 @@ -14,13 +14,11 @@ import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedElement; +import java.util.Collection; import java.util.HashMap; +import java.util.LinkedList; import java.util.Map; - -import jakarta.json.bind.JsonbException; - -import org.eclipse.yasson.internal.properties.MessageKeys; -import org.eclipse.yasson.internal.properties.Messages; +import java.util.Optional; /** * Annotation holder for classes, superclasses, interfaces, fields, getters and setters. @@ -29,7 +27,7 @@ */ public class JsonbAnnotatedElement { - private final Map, Annotation> annotations = new HashMap<>(4); + private final Map, LinkedList>> annotations = new HashMap<>(4); private final T element; @@ -40,7 +38,11 @@ public class JsonbAnnotatedElement { */ public JsonbAnnotatedElement(T element) { for (Annotation ann : element.getAnnotations()) { - annotations.put(ann.annotationType(), ann); + if (element instanceof Class) { + putAnnotation(ann, false, (Class) element); + } else { + putAnnotation(ann, false, null); + } } this.element = element; @@ -57,28 +59,77 @@ public T getElement() { /** * Get an annotation by type. - * @param Type of annotation + * + * @param Type of annotation * @param annotationClass Type of annotation * @return Annotation by passed type */ - public AT getAnnotation(Class annotationClass) { - return annotationClass.cast(annotations.get(annotationClass)); + public Optional getAnnotation(Class annotationClass) { + return Optional.ofNullable(annotations.get(annotationClass)) + .map(LinkedList::getFirst) + .map(AnnotationWrapper::getAnnotation) + .map(annotationClass::cast); + } + + public LinkedList> getAnnotations(Class annotationClass) { + return annotations.getOrDefault(annotationClass, new LinkedList<>()); + } + + @SuppressWarnings("unchecked") + public AnnotationWrapper getAnnotationWrapper(Class annotationClass) { + return (AnnotationWrapper) annotations.get(annotationClass).getFirst(); } public Annotation[] getAnnotations() { - return annotations.values().toArray(new Annotation[0]); + return annotations.values().stream() + .flatMap(Collection::stream) + .map(AnnotationWrapper::getAnnotation) + .toArray(Annotation[]::new); } /** * Adds annotation. * * @param annotation Annotation to add. + * @param definedType */ - public void putAnnotation(Annotation annotation) { - if (annotations.containsKey(annotation.annotationType())) { - throw new JsonbException(Messages.getMessage(MessageKeys.INTERNAL_ERROR, - "Annotation already present: " + annotation)); + public void putAnnotation(Annotation annotation, boolean inherited, Class definedType) { +// if (annotations.containsKey(annotation.annotationType())) { +// throw new JsonbException(Messages.getMessage(MessageKeys.INTERNAL_ERROR, +// "Annotation already present: " + annotation)); +// } +// annotations.put(annotation.annotationType(), new AnnotationWrapper(annotation, inherited)); + annotations.computeIfAbsent(annotation.annotationType(), aClass -> new LinkedList<>()) + .add(new AnnotationWrapper(annotation, inherited, definedType)); + } + + public void putAnnotationWrapper(AnnotationWrapper annotationWrapper) { + annotations.computeIfAbsent(annotationWrapper.getAnnotation().annotationType(), aClass -> new LinkedList<>()) + .add(annotationWrapper); + } + + public static final class AnnotationWrapper { + + private final T annotation; + private final boolean inherited; + private final Class definedType; + + public AnnotationWrapper(T annotation, boolean inherited, Class definedType) { + this.annotation = annotation; + this.inherited = inherited; + this.definedType = definedType; + } + + public T getAnnotation() { + return annotation; + } + + public boolean isInherited() { + return inherited; + } + + public Class getDefinedType() { + return definedType; } - annotations.put(annotation.annotationType(), annotation); } } diff --git a/src/main/java/org/eclipse/yasson/internal/model/JsonbPropertyInfo.java b/src/main/java/org/eclipse/yasson/internal/model/JsonbPropertyInfo.java deleted file mode 100644 index 8e2e46e46..000000000 --- a/src/main/java/org/eclipse/yasson/internal/model/JsonbPropertyInfo.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.model; - -import java.lang.reflect.Type; - -import org.eclipse.yasson.internal.JsonbContext; -import org.eclipse.yasson.internal.serializer.CurrentItem; - -/** - * Wrapper for metadata of serialized property. - */ -public class JsonbPropertyInfo { - - private JsonbContext context; - - private Type runtimeType; - - private ClassModel classModel; - - private CurrentItem wrapper; - - /** - * Gets context. - * - * @return Context. - */ - public JsonbContext getContext() { - return context; - } - - /** - * Sets context. - * - * @param context Context to set. - * @return Updated object. - */ - public JsonbPropertyInfo setContext(JsonbContext context) { - this.context = context; - return this; - } - - /** - * Gets runtime type. - * - * @return Runtime type. - */ - public Type getRuntimeType() { - return runtimeType; - } - - /** - * Sets runtime type. - * - * @param runtimeType Runtime type to set. - * @return Updated object. - */ - public JsonbPropertyInfo withRuntimeType(Type runtimeType) { - this.runtimeType = runtimeType; - return this; - } - - /** - * Gets class model. - * - * @return Class model. - */ - public ClassModel getClassModel() { - return classModel; - } - - /** - * Sets class model. - * - * @param classModel Class model to set. - * @return Updated object. - */ - public JsonbPropertyInfo withClassModel(ClassModel classModel) { - this.classModel = classModel; - return this; - } - - /** - * Gets wrapper. - * - * @return Wrapper. - */ - public CurrentItem getWrapper() { - return wrapper; - } - - /** - * Sets wrapper. - * - * @param wrapper Wrapper to set. - * @return Updated object. - */ - public JsonbPropertyInfo withWrapper(CurrentItem wrapper) { - this.wrapper = wrapper; - return this; - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/model/ModulesUtil.java b/src/main/java/org/eclipse/yasson/internal/model/ModulesUtil.java index 030d37aff..2f2713949 100644 --- a/src/main/java/org/eclipse/yasson/internal/model/ModulesUtil.java +++ b/src/main/java/org/eclipse/yasson/internal/model/ModulesUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. + * 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 @@ -20,6 +20,6 @@ private ModulesUtil() { } static MethodHandles.Lookup lookup(){ - return MethodHandles.lookup(); + return MethodHandles.publicLookup(); } } diff --git a/src/main/java/org/eclipse/yasson/internal/model/PropertyModel.java b/src/main/java/org/eclipse/yasson/internal/model/PropertyModel.java index ced8673f0..f7d2828e9 100644 --- a/src/main/java/org/eclipse/yasson/internal/model/PropertyModel.java +++ b/src/main/java/org/eclipse/yasson/internal/model/PropertyModel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 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 @@ -24,36 +24,28 @@ import java.util.EnumSet; import java.util.Map; import java.util.Objects; -import java.util.Optional; import java.util.function.Predicate; import jakarta.json.bind.JsonbException; import jakarta.json.bind.config.PropertyNamingStrategy; import jakarta.json.bind.config.PropertyVisibilityStrategy; -import jakarta.json.bind.serializer.JsonbSerializer; import org.eclipse.yasson.internal.AnnotationIntrospector; import org.eclipse.yasson.internal.JsonbContext; -import org.eclipse.yasson.internal.ReflectionUtils; +import org.eclipse.yasson.internal.JsonbDateFormatter; +import org.eclipse.yasson.internal.JsonbNumberFormatter; import org.eclipse.yasson.internal.components.AdapterBinding; import org.eclipse.yasson.internal.components.SerializerBinding; import org.eclipse.yasson.internal.model.customization.PropertyCustomization; -import org.eclipse.yasson.internal.model.customization.PropertyCustomizationBuilder; -import org.eclipse.yasson.internal.serializer.AdaptedObjectSerializer; -import org.eclipse.yasson.internal.serializer.DefaultSerializers; -import org.eclipse.yasson.internal.serializer.JsonbDateFormatter; -import org.eclipse.yasson.internal.serializer.JsonbNumberFormatter; -import org.eclipse.yasson.internal.serializer.SerializerProviderWrapper; -import org.eclipse.yasson.internal.serializer.UserSerializerSerializer; /** * A model for class property. * Property is JavaBean alike meta information field / getter / setter of a property in class. */ public final class PropertyModel implements Comparable { - + private static final MethodHandles.Lookup LOOKUP = ModulesUtil.lookup(); - + /** * Field propertyName as in class by java bean convention. */ @@ -78,7 +70,7 @@ public final class PropertyModel implements Comparable { * Model of the class this field belongs to. */ private final ClassModel classModel; - + private final Property property; /** @@ -86,25 +78,24 @@ public final class PropertyModel implements Comparable { */ private final PropertyCustomization customization; - private final JsonbSerializer propertySerializer; - private final MethodHandle getValueHandle; private final MethodHandle setValueHandle; - + private final Field field; private final Method getter; private final Method setter; - + private final Type getterMethodType; private final Type setterMethodType; - + /** * Create a new PropertyModel that merges two existing PropertyModel that have identical read/write names. * The input PropertyModel objects MUST be equal (a.equals(b) == true) + * * @param a a PropertyModel instance to merge * @param b the other PropertyModel instance to merge */ @@ -112,7 +103,7 @@ public PropertyModel(PropertyModel a, PropertyModel b) { if (!a.equals(b)) { throw new IllegalStateException("Property models " + a + " and " + b + " cannot be merged"); } - + // Initial cloning steps this.classModel = a.classModel; this.propertyName = a.propertyName; @@ -120,7 +111,7 @@ public PropertyModel(PropertyModel a, PropertyModel b) { this.writeName = a.writeName; this.propertyType = a.propertyType; this.customization = a.customization; - + // Merging steps this.getterMethodType = a.getterMethodType != null ? a.getterMethodType : b.getterMethodType; this.setterMethodType = a.setterMethodType != null ? a.setterMethodType : b.setterMethodType; @@ -137,11 +128,10 @@ public PropertyModel(PropertyModel a, PropertyModel b) { this.field = property.getField(); this.getter = property.getGetter(); this.setter = property.getSetter(); - + PropertyVisibilityStrategy strategy = classModel.getClassCustomization().getPropertyVisibilityStrategy(); this.getValueHandle = createReadHandle(field, getter, isMethodVisible(getter, strategy), strategy); this.setValueHandle = createWriteHandle(field, setter, isMethodVisible(setter, strategy), strategy); - this.propertySerializer = resolveCachedSerializer(); } /** @@ -159,11 +149,11 @@ public PropertyModel(ClassModel classModel, Property property, JsonbContext json this.field = property.getField(); this.getter = property.getGetter(); this.setter = property.getSetter(); - + PropertyVisibilityStrategy strategy = classModel.getClassCustomization().getPropertyVisibilityStrategy(); boolean getterVisible = isMethodVisible(getter, strategy); boolean setterVisible = isMethodVisible(setter, strategy); - + this.getValueHandle = createReadHandle(field, getter, getterVisible, strategy); this.setValueHandle = createWriteHandle(field, setter, setterVisible, strategy); this.getterMethodType = getterVisible ? property.getGetterType() : null; @@ -173,34 +163,6 @@ public PropertyModel(ClassModel classModel, Property property, JsonbContext json jsonbContext.getConfigProperties().getPropertyNamingStrategy()); this.writeName = calculateReadWriteName(customization.getJsonWriteName(), propertyName, jsonbContext.getConfigProperties().getPropertyNamingStrategy()); - this.propertySerializer = resolveCachedSerializer(); - } - - /** - * Try to cache serializer for this bean property. Only if type cannot be changed during runtime. - * - * @return serializer instance to be cached - */ - @SuppressWarnings("unchecked") - private JsonbSerializer resolveCachedSerializer() { - Type serializationType = getPropertySerializationType(); - if (!ReflectionUtils.isResolvedType(serializationType)) { - return null; - } - if (customization.getSerializeAdapterBinding() != null) { - return new AdaptedObjectSerializer<>(classModel, customization.getSerializeAdapterBinding()); - } - if (customization.getSerializerBinding() != null) { - return new UserSerializerSerializer<>(classModel, customization.getSerializerBinding().getJsonbSerializer()); - } - - final Class propertyRawType = ReflectionUtils.getRawType(serializationType); - final Optional valueSerializerProvider = DefaultSerializers.findValueSerializerProvider(propertyRawType); - if (valueSerializerProvider.isPresent()) { - return valueSerializerProvider.get().getSerializerProvider().provideSerializer(customization); - } - - return null; } /** @@ -231,66 +193,65 @@ private SerializerBinding getUserSerializerBinding(Property property, JsonbCo private PropertyCustomization introspectCustomization(Property property, JsonbContext jsonbContext) { final AnnotationIntrospector introspector = jsonbContext.getAnnotationIntrospector(); - final PropertyCustomizationBuilder builder = new PropertyCustomizationBuilder(); + final PropertyCustomization.Builder builder = PropertyCustomization.builder(); //drop all other annotations for transient properties EnumSet transientInfo = introspector.getJsonbTransientCategorized(property); if (transientInfo.size() != 0) { - builder.setReadTransient(transientInfo.contains(AnnotationTarget.GETTER)); - builder.setWriteTransient(transientInfo.contains(AnnotationTarget.SETTER)); + builder.readTransient(transientInfo.contains(AnnotationTarget.GETTER)); + builder.writeTransient(transientInfo.contains(AnnotationTarget.SETTER)); if (transientInfo.contains(AnnotationTarget.PROPERTY)) { if (!transientInfo.contains(AnnotationTarget.GETTER)) { - builder.setReadTransient(true); + builder.readTransient(true); } if (!transientInfo.contains(AnnotationTarget.SETTER)) { - builder.setWriteTransient(true); + builder.writeTransient(true); } } - if (builder.isReadTransient()) { + if (builder.readTransient()) { introspector.checkTransientIncompatible(property.getFieldElement()); introspector.checkTransientIncompatible(property.getGetterElement()); } - if (builder.isWriteTransient()) { + if (builder.writeTransient()) { introspector.checkTransientIncompatible(property.getFieldElement()); introspector.checkTransientIncompatible(property.getSetterElement()); } } - if (!builder.isReadTransient()) { - builder.setJsonWriteName(introspector.getJsonbPropertyJsonWriteName(property)); - builder.setNillable(introspector.isPropertyNillable(property) - .orElse(classModel.getClassCustomization().isNillable())); - builder.setSerializerBinding(getUserSerializerBinding(property, jsonbContext)); + if (!builder.readTransient()) { + builder.jsonWriteName(introspector.getJsonbPropertyJsonWriteName(property)); + builder.nillable(introspector.isPropertyNillable(property).orElse(classModel.getClassCustomization().isNillable())); + builder.serializerBinding(getUserSerializerBinding(property, jsonbContext)); } - if (!builder.isWriteTransient()) { - builder.setJsonReadName(introspector.getJsonbPropertyJsonReadName(property)); - builder.setDeserializerBinding(introspector.getDeserializerBinding(property)); + if (!builder.writeTransient()) { + builder.jsonReadName(introspector.getJsonbPropertyJsonReadName(property)); + builder.deserializerBinding(introspector.getDeserializerBinding(property)); } final AdapterBinding adapterBinding = jsonbContext.getAnnotationIntrospector().getAdapterBinding(property); if (adapterBinding != null) { - builder.setSerializeAdapter(adapterBinding); - builder.setDeserializeAdapter(adapterBinding); + builder.serializeAdapter(adapterBinding); + builder.deserializeAdapter(adapterBinding); } else { - builder.setSerializeAdapter(jsonbContext.getComponentMatcher() - .getSerializeAdapterBinding(getPropertySerializationType(), null).orElse(null)); - builder.setDeserializeAdapter(jsonbContext.getComponentMatcher() - .getDeserializeAdapterBinding(getPropertyDeserializationType(), null) - .orElse(null)); + builder.serializeAdapter(jsonbContext.getComponentMatcher() + .getSerializeAdapterBinding(getPropertySerializationType(), null).orElse(null)); + builder.deserializeAdapter(jsonbContext.getComponentMatcher() + .getDeserializeAdapterBinding(getPropertyDeserializationType(), null) + .orElse(null)); } introspectDateFormatter(property, introspector, builder, jsonbContext); introspectNumberFormatter(property, introspector, builder); - builder.setImplementationClass(introspector.getImplementationClass(property)); + builder.implementationClass(introspector.getImplementationClass(property)); - return builder.buildPropertyCustomization(); + return builder.build(); } private static void introspectDateFormatter(Property property, AnnotationIntrospector introspector, - PropertyCustomizationBuilder builder, + PropertyCustomization.Builder builder, JsonbContext jsonbContext) { /* * If @JsonbDateFormat is placed on getter implementation must use this format on serialization. @@ -303,28 +264,28 @@ private static void introspectDateFormatter(Property property, .getJsonbDateFormatCategorized(property); final JsonbDateFormatter configDateFormatter = jsonbContext.getConfigProperties().getConfigDateFormatter(); - if (!builder.isReadTransient()) { + if (!builder.readTransient()) { final JsonbDateFormatter dateFormatter = getTargetForMostPreciseScope(jsonDateFormatCategorized, AnnotationTarget.GETTER, AnnotationTarget.PROPERTY, AnnotationTarget.CLASS); - builder.setSerializeDateFormatter(dateFormatter != null ? dateFormatter : configDateFormatter); + builder.serializeDateFormatter(dateFormatter != null ? dateFormatter : configDateFormatter); } - if (!builder.isWriteTransient()) { + if (!builder.writeTransient()) { final JsonbDateFormatter dateFormatter = getTargetForMostPreciseScope(jsonDateFormatCategorized, AnnotationTarget.SETTER, AnnotationTarget.PROPERTY, AnnotationTarget.CLASS); - builder.setDeserializeDateFormatter(dateFormatter != null ? dateFormatter : configDateFormatter); + builder.deserializeDateFormatter(dateFormatter != null ? dateFormatter : configDateFormatter); } } private static void introspectNumberFormatter(Property property, AnnotationIntrospector introspector, - PropertyCustomizationBuilder builder) { + PropertyCustomization.Builder builder) { /* * If @JsonbNumberFormat is placed on getter implementation must use this format on serialization. * If @JsonbNumberFormat is placed on setter implementation must use this format on deserialization. @@ -334,18 +295,18 @@ private static void introspectNumberFormatter(Property property, */ Map jsonNumberFormatCategorized = introspector.getJsonNumberFormatter(property); - if (!builder.isReadTransient()) { - builder.setSerializeNumberFormatter(getTargetForMostPreciseScope(jsonNumberFormatCategorized, - AnnotationTarget.GETTER, - AnnotationTarget.PROPERTY, - AnnotationTarget.CLASS)); + if (!builder.readTransient()) { + builder.serializeNumberFormatter(getTargetForMostPreciseScope(jsonNumberFormatCategorized, + AnnotationTarget.GETTER, + AnnotationTarget.PROPERTY, + AnnotationTarget.CLASS)); } - if (!builder.isWriteTransient()) { - builder.setDeserializeNumberFormatter(getTargetForMostPreciseScope(jsonNumberFormatCategorized, - AnnotationTarget.SETTER, - AnnotationTarget.PROPERTY, - AnnotationTarget.CLASS)); + if (!builder.writeTransient()) { + builder.deserializeNumberFormatter(getTargetForMostPreciseScope(jsonNumberFormatCategorized, + AnnotationTarget.SETTER, + AnnotationTarget.PROPERTY, + AnnotationTarget.CLASS)); } } @@ -355,7 +316,8 @@ private static void introspectNumberFormatter(Property property, * @param collectedAnnotations all targets * @param targets ordered target types by scope */ - private static T getTargetForMostPreciseScope(Map collectedAnnotations, AnnotationTarget... targets) { + private static T getTargetForMostPreciseScope(Map collectedAnnotations, + AnnotationTarget... targets) { for (AnnotationTarget target : targets) { final T result = collectedAnnotations.get(target); if (result != null) { @@ -461,7 +423,7 @@ public boolean equals(Object o) { } PropertyModel other = (PropertyModel) o; return Objects.equals(readName, other.readName) - && Objects.equals(writeName, other.writeName); + && Objects.equals(writeName, other.writeName); } @Override @@ -482,15 +444,6 @@ public String getWriteName() { return writeName; } - /** - * Gets serializer. - * - * @return Serializer. - */ - public JsonbSerializer getPropertySerializer() { - return propertySerializer; - } - /** * If customized by JsonbPropertyAnnotation, than is used, otherwise use strategy to translate. * Since this is cached for performance reasons strategy has to be consistent @@ -499,7 +452,7 @@ public JsonbSerializer getPropertySerializer() { private static String calculateReadWriteName(String readWriteName, String propertyName, PropertyNamingStrategy strategy) { return readWriteName != null ? readWriteName : strategy.translateName(propertyName); } - + /** * Field of a javabean property. * @@ -526,55 +479,66 @@ public Method getGetter() { public Method getSetter() { return setter; } - + // Used in ClassParser public static boolean isPropertyReadable(Field field, Method getter, PropertyVisibilityStrategy strategy) { return createReadHandle(field, getter, isMethodVisible(getter, strategy), strategy) != null; } - - private static MethodHandle createReadHandle(Field field, Method getter, boolean getterVisible, PropertyVisibilityStrategy strategy) { + + private static MethodHandle createReadHandle(Field field, + Method getter, + boolean getterVisible, + PropertyVisibilityStrategy strategy) { boolean fieldReadable = field == null || (field.getModifiers() & (Modifier.TRANSIENT | Modifier.STATIC)) == 0; - + if (fieldReadable) { if (getter != null && getterVisible) { try { return LOOKUP.unreflect(getter); } catch (Throwable e) { - throw new JsonbException("Error accessing getter '" + getter.getName() + "' declared in '" + getter.getDeclaringClass() + "'", e); + throw new JsonbException("Error accessing getter '" + getter.getName() + "' declared in '" + getter + .getDeclaringClass() + "'", e); } } if (isFieldVisible(field, getter, strategy)) { try { return LOOKUP.unreflectGetter(field); } catch (IllegalAccessException e) { - throw new JsonbException("Error accessing field '" + field.getName() + "' declared in '" + field.getDeclaringClass() + "'", e); + throw new JsonbException("Error accessing field '" + field.getName() + "' declared in '" + field + .getDeclaringClass() + "'", e); } } } - + return null; } - - private static MethodHandle createWriteHandle(Field field, Method setter, boolean setterVisible, PropertyVisibilityStrategy strategy) { - boolean fieldWritable = field == null || (field.getModifiers() & (Modifier.TRANSIENT | Modifier.STATIC | Modifier.FINAL)) == 0; - + + private static MethodHandle createWriteHandle(Field field, + Method setter, + boolean setterVisible, + PropertyVisibilityStrategy strategy) { + boolean fieldWritable = + field == null || (field.getModifiers() & (Modifier.TRANSIENT | Modifier.STATIC | Modifier.FINAL)) == 0; + if (fieldWritable) { if (setter != null && setterVisible && !setter.getDeclaringClass().isAnonymousClass()) { try { return LOOKUP.unreflect(setter); } catch (IllegalAccessException e) { - throw new JsonbException("Error accessing setter '" + setter.getName() + "' declared in '" + setter.getDeclaringClass() + "'", e); + throw new JsonbException("Error accessing setter '" + setter.getName() + "' declared in '" + setter + .getDeclaringClass() + "'", e); } } if (isFieldVisible(field, setter, strategy) && !field.getDeclaringClass().isAnonymousClass()) { try { return LOOKUP.unreflectSetter(field); } catch (IllegalAccessException e) { - throw new JsonbException("Error accessing field '" + field.getName() + "' declared in '" + field.getDeclaringClass() + "'", e); + throw new JsonbException("Error accessing field '" + field.getName() + "' declared in '" + field + .getDeclaringClass() + "'", e); } } } - + return null; } @@ -626,8 +590,12 @@ private static void overrideAccessible(AccessibleObject accessibleObject) { * @param visibilityCheckFunction function declaring visibility check * @return Optional with result of visibility check, or empty optional if no strategy is found */ - private static boolean isVisible(Predicate visibilityCheckFunction, Method method, PropertyVisibilityStrategy strategy) { - return strategy != null ? visibilityCheckFunction.test(strategy) : visibilityCheckFunction.test(new DefaultVisibilityStrategy(method)); + private static boolean isVisible(Predicate visibilityCheckFunction, + Method method, + PropertyVisibilityStrategy strategy) { + return strategy != null + ? visibilityCheckFunction.test(strategy) + : visibilityCheckFunction.test(new DefaultVisibilityStrategy(method)); } private static final class DefaultVisibilityStrategy implements PropertyVisibilityStrategy { @@ -649,4 +617,13 @@ public boolean isVisible(Method method) { return Modifier.isPublic(method.getModifiers()); } } + + public MethodHandle getGetValueHandle() { + return getValueHandle; + } + + public MethodHandle getSetValueHandle() { + return setValueHandle; + } + } diff --git a/src/main/java/org/eclipse/yasson/internal/model/customization/ClassCustomization.java b/src/main/java/org/eclipse/yasson/internal/model/customization/ClassCustomization.java index fe5b9ae48..f53a0ecae 100644 --- a/src/main/java/org/eclipse/yasson/internal/model/customization/ClassCustomization.java +++ b/src/main/java/org/eclipse/yasson/internal/model/customization/ClassCustomization.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 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 @@ -14,51 +14,45 @@ import jakarta.json.bind.config.PropertyVisibilityStrategy; +import org.eclipse.yasson.internal.JsonbDateFormatter; +import org.eclipse.yasson.internal.JsonbNumberFormatter; import org.eclipse.yasson.internal.model.JsonbCreator; -import org.eclipse.yasson.internal.serializer.JsonbDateFormatter; -import org.eclipse.yasson.internal.serializer.JsonbNumberFormatter; /** - * Customization, which could be applied on a class or package level. + * Customization which could be applied on a class or package level. */ public class ClassCustomization extends CustomizationBase { - private final JsonbCreator creator; - - private String[] propertyOrder; + private static final ClassCustomization EMPTY = new ClassCustomization(new Builder()); + private final JsonbCreator creator; + private final String[] propertyOrder; private final JsonbNumberFormatter numberFormatter; - private final JsonbDateFormatter dateTimeFormatter; - private final PropertyVisibilityStrategy propertyVisibilityStrategy; + private final TypeInheritanceConfiguration typeInheritanceConfiguration; /** * Copies properties from builder an creates immutable instance. * * @param builder not null */ - ClassCustomization(ClassCustomizationBuilder builder) { + private ClassCustomization(Builder builder) { super(builder); - this.creator = builder.getCreator(); - this.propertyOrder = builder.getPropertyOrder(); - this.numberFormatter = builder.getNumberFormatter(); - this.dateTimeFormatter = builder.getDateFormatter(); - this.propertyVisibilityStrategy = builder.getPropertyVisibilityStrategy(); + this.creator = builder.creator; + this.propertyOrder = builder.propertyOrder; + this.numberFormatter = builder.numberFormatter; + this.dateTimeFormatter = builder.dateTimeFormatter; + this.propertyVisibilityStrategy = builder.propertyVisibilityStrategy; + this.typeInheritanceConfiguration = builder.typeInheritanceConfiguration; } - /** - * Copy constructor. - * - * @param other other customization instance - */ - public ClassCustomization(ClassCustomization other) { - super(other); - this.creator = other.getCreator(); - this.propertyOrder = other.getPropertyOrder(); - this.numberFormatter = other.getSerializeNumberFormatter(); - this.dateTimeFormatter = other.getSerializeDateFormatter(); - this.propertyVisibilityStrategy = other.getPropertyVisibilityStrategy(); + public static ClassCustomization empty() { + return EMPTY; + } + + public static Builder builder() { + return new Builder(); } /** @@ -79,15 +73,6 @@ public String[] getPropertyOrder() { return propertyOrder; } - /** - * Sets sorted properties. - * - * @param propertyOrder sorted names of properties - */ - public void setPropertyOrder(String[] propertyOrder) { - this.propertyOrder = propertyOrder; - } - /** * Property visibility strategy for this class model. * @@ -117,4 +102,71 @@ public JsonbDateFormatter getDeserializeDateFormatter() { return dateTimeFormatter; } + public TypeInheritanceConfiguration getPolymorphismConfig() { + return typeInheritanceConfiguration; + } + + /** + * The customization builder that would be used to build an instance of {@link ClassCustomization} to ensure its immutability. + */ + public static class Builder extends CustomizationBase.Builder { + + private JsonbCreator creator; + private String[] propertyOrder; + private JsonbNumberFormatter numberFormatter; + private JsonbDateFormatter dateTimeFormatter; + private PropertyVisibilityStrategy propertyVisibilityStrategy; + private TypeInheritanceConfiguration typeInheritanceConfiguration; + + private Builder() { + } + + @Override + public Builder of(ClassCustomization customization) { + super.of(customization); + creator(customization.creator); + propertyOrder(customization.propertyOrder); + numberFormatter(customization.numberFormatter); + dateTimeFormatter(customization.dateTimeFormatter); + propertyVisibilityStrategy(customization.propertyVisibilityStrategy); + return this; + } + + public Builder creator(JsonbCreator creator) { + this.creator = creator; + return this; + } + + public Builder propertyOrder(String[] propertyOrder) { + this.propertyOrder = propertyOrder; + return this; + } + + public Builder numberFormatter(JsonbNumberFormatter numberFormatter) { + this.numberFormatter = numberFormatter; + return this; + } + + public Builder dateTimeFormatter(JsonbDateFormatter dateTimeFormatter) { + this.dateTimeFormatter = dateTimeFormatter; + return this; + } + + public Builder propertyVisibilityStrategy(PropertyVisibilityStrategy propertyVisibilityStrategy) { + this.propertyVisibilityStrategy = propertyVisibilityStrategy; + return this; + } + + public Builder polymorphismConfig(TypeInheritanceConfiguration typeInheritanceConfiguration) { + this.typeInheritanceConfiguration = typeInheritanceConfiguration; + return this; + } + + @Override + public ClassCustomization build() { + return new ClassCustomization(this); + } + + } + } diff --git a/src/main/java/org/eclipse/yasson/internal/model/customization/ClassCustomizationBuilder.java b/src/main/java/org/eclipse/yasson/internal/model/customization/ClassCustomizationBuilder.java deleted file mode 100644 index 9572126e6..000000000 --- a/src/main/java/org/eclipse/yasson/internal/model/customization/ClassCustomizationBuilder.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.model.customization; - -import jakarta.json.bind.config.PropertyVisibilityStrategy; - -import org.eclipse.yasson.internal.model.JsonbCreator; -import org.eclipse.yasson.internal.serializer.JsonbDateFormatter; -import org.eclipse.yasson.internal.serializer.JsonbNumberFormatter; - -/** - * The customization builder that would be used to build an instance of {@link ClassCustomization} to ensure its immutability. - */ -public class ClassCustomizationBuilder extends CustomizationBuilder { - - private JsonbCreator jsonbCreator; - - /** - * The class level number formatter that would be used by default for all number properties that don't have a dedicated - * number formatter - * annotation. - */ - private JsonbNumberFormatter numberFormatter; - - /** - * The class level date formatter that would be used by default for all date properties that don't have a dedicated date - * formatter annotation. - */ - private JsonbDateFormatter dateFormatter; - - /** - * The class or package level property visibility strategy. - */ - private PropertyVisibilityStrategy propertyVisibilityStrategy; - - /** - * Creates a customization for class properties. - * - * @return A new instance of {@link PropertyCustomization} - */ - public ClassCustomization buildClassCustomization() { - return new ClassCustomization(this); - } - - /** - * Returns the default number formatter instance that would be used for all number properties that don't have a dedicated - * number formatter. - * - * @return the default number formatter instance that would be used for all number properties that don't have a dedicated - * number formatter - */ - public JsonbNumberFormatter getNumberFormatter() { - return numberFormatter; - } - - /** - * Sets the default number formatter instance that would be used for all number properties that don't have a dedicated - * number formatter. - * - * @param numberFormatter the default number formatter instance that would be used for all number properties that don't - * have a dedicated number - * formatter. - */ - public void setNumberFormatter(JsonbNumberFormatter numberFormatter) { - this.numberFormatter = numberFormatter; - } - - /** - * Gets a date format for formatting dates. - * - * @return Date format. - */ - public JsonbDateFormatter getDateFormatter() { - return dateFormatter; - } - - /** - * Sets date format for formatting dates. - * - * @param dateFormatter Date format. - */ - public void setDateFormatter(JsonbDateFormatter dateFormatter) { - this.dateFormatter = dateFormatter; - } - - /** - * Gets custom constructor or method for user instantiation. - * - * @return Custom creator. - */ - public JsonbCreator getCreator() { - return jsonbCreator; - } - - /** - * Sets custom constructor or method for user instantiation. - * - * @param jsonbCreator Creator to set. - */ - public void setCreator(JsonbCreator jsonbCreator) { - this.jsonbCreator = jsonbCreator; - } - - /** - * Property visibility strategy for given class. - * - * @return property visibility strategy - */ - public PropertyVisibilityStrategy getPropertyVisibilityStrategy() { - return propertyVisibilityStrategy; - } - - /** - * Sets custom property visibility strategy. - * - * @param propertyVisibilityStrategy strategy - */ - public void setPropertyVisibilityStrategy(PropertyVisibilityStrategy propertyVisibilityStrategy) { - this.propertyVisibilityStrategy = propertyVisibilityStrategy; - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/model/customization/ComponentBoundCustomization.java b/src/main/java/org/eclipse/yasson/internal/model/customization/ComponentBoundCustomization.java index 069205e5d..e964ed805 100644 --- a/src/main/java/org/eclipse/yasson/internal/model/customization/ComponentBoundCustomization.java +++ b/src/main/java/org/eclipse/yasson/internal/model/customization/ComponentBoundCustomization.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 @@ -36,12 +36,12 @@ public interface ComponentBoundCustomization { * * @return serializer wrapper */ - SerializerBinding getSerializerBinding(); + SerializerBinding getSerializerBinding(); /** * Deserializer wrapper with resolved generic info. * * @return deserializer wrapper */ - DeserializerBinding getDeserializerBinding(); + DeserializerBinding getDeserializerBinding(); } diff --git a/src/main/java/org/eclipse/yasson/internal/model/customization/ContainerCustomization.java b/src/main/java/org/eclipse/yasson/internal/model/customization/ContainerCustomization.java deleted file mode 100644 index 826205b77..000000000 --- a/src/main/java/org/eclipse/yasson/internal/model/customization/ContainerCustomization.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.model.customization; - -/** - * Customization for container like types (Maps, Collections, Arrays). - */ -public class ContainerCustomization extends ClassCustomization { - - /** - * Creates a new instance. - * - * @param builder Builder to initialize from. - */ - public ContainerCustomization(ClassCustomizationBuilder builder) { - super(builder); - } - - /** - * Creates a new instance. - * - * @param other Class customization to initialize from. - */ - public ContainerCustomization(ClassCustomization other) { - super(other); - } - - /** - * Containers (types mapped to JsonArray) are always nillable by spec. - * - * @return always true - */ - @Override - public final boolean isNillable() { - return true; - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/model/customization/CreatorCustomization.java b/src/main/java/org/eclipse/yasson/internal/model/customization/CreatorCustomization.java index 985bd21b2..a3c863158 100644 --- a/src/main/java/org/eclipse/yasson/internal/model/customization/CreatorCustomization.java +++ b/src/main/java/org/eclipse/yasson/internal/model/customization/CreatorCustomization.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 @@ -12,34 +12,34 @@ package org.eclipse.yasson.internal.model.customization; +import org.eclipse.yasson.internal.JsonbDateFormatter; +import org.eclipse.yasson.internal.JsonbNumberFormatter; import org.eclipse.yasson.internal.model.PropertyModel; -import org.eclipse.yasson.internal.serializer.JsonbDateFormatter; -import org.eclipse.yasson.internal.serializer.JsonbNumberFormatter; /** * Customization for creator (constructor / factory methods) parameters. */ public class CreatorCustomization extends CustomizationBase { - private JsonbNumberFormatter numberFormatter; - - private JsonbDateFormatter dateFormatter; - + private final JsonbNumberFormatter numberFormatter; + private final JsonbDateFormatter dateFormatter; + private final boolean required; private PropertyModel propertyModel; /** * Creates new creator customization instance. * - * @param customization builder of the customization - * @param numberFormatter number formatter - * @param dateFormatter date formatter + * @param builder builder of the customization */ - public CreatorCustomization(CustomizationBuilder customization, - JsonbNumberFormatter numberFormatter, - JsonbDateFormatter dateFormatter) { - super(customization); - this.numberFormatter = numberFormatter; - this.dateFormatter = dateFormatter; + private CreatorCustomization(Builder builder) { + super(builder); + this.numberFormatter = builder.numberFormatter; + this.dateFormatter = builder.dateFormatter; + this.required = builder.required; + } + + public static Builder builder() { + return new Builder(); } @Override @@ -85,4 +85,48 @@ public boolean isNillable() { public void setPropertyModel(PropertyModel propertyModel) { this.propertyModel = propertyModel; } + + public boolean isRequired() { + return required; + } + + public static final class Builder extends CustomizationBase.Builder { + + private JsonbNumberFormatter numberFormatter; + private JsonbDateFormatter dateFormatter; + private boolean required = false; + + private Builder() { + } + + @Override + public Builder of(CreatorCustomization customization) { + super.of(customization); + numberFormatter = customization.numberFormatter; + dateFormatter = customization.dateFormatter; + return this; + } + + public Builder numberFormatter(JsonbNumberFormatter numberFormatter) { + this.numberFormatter = numberFormatter; + return this; + } + + public Builder dateFormatter(JsonbDateFormatter dateFormatter) { + this.dateFormatter = dateFormatter; + return this; + } + + public Builder required(boolean required) { + this.required = required; + return this; + } + + @Override + public CreatorCustomization build() { + return new CreatorCustomization(this); + } + + } + } diff --git a/src/main/java/org/eclipse/yasson/internal/model/customization/Customization.java b/src/main/java/org/eclipse/yasson/internal/model/customization/Customization.java index 3e592dde3..7cd90605d 100644 --- a/src/main/java/org/eclipse/yasson/internal/model/customization/Customization.java +++ b/src/main/java/org/eclipse/yasson/internal/model/customization/Customization.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 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 @@ -12,8 +12,8 @@ package org.eclipse.yasson.internal.model.customization; -import org.eclipse.yasson.internal.serializer.JsonbDateFormatter; -import org.eclipse.yasson.internal.serializer.JsonbNumberFormatter; +import org.eclipse.yasson.internal.JsonbDateFormatter; +import org.eclipse.yasson.internal.JsonbNumberFormatter; /** * Customization configuration for class or field. diff --git a/src/main/java/org/eclipse/yasson/internal/model/customization/CustomizationBase.java b/src/main/java/org/eclipse/yasson/internal/model/customization/CustomizationBase.java index 6f7a329a0..2b49180df 100644 --- a/src/main/java/org/eclipse/yasson/internal/model/customization/CustomizationBase.java +++ b/src/main/java/org/eclipse/yasson/internal/model/customization/CustomizationBase.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 @@ -22,11 +22,8 @@ abstract class CustomizationBase implements Customization, ComponentBoundCustomization { private final AdapterBinding adapterBinding; - - private final SerializerBinding serializerBinding; - - private final DeserializerBinding deserializerBinding; - + private final SerializerBinding serializerBinding; + private final DeserializerBinding deserializerBinding; private final boolean nillable; /** @@ -34,23 +31,11 @@ abstract class CustomizationBase implements Customization, ComponentBoundCustomi * * @param builder not null */ - CustomizationBase(CustomizationBuilder builder) { - this.nillable = builder.isNillable(); - this.adapterBinding = builder.getAdapterInfo(); - this.serializerBinding = builder.getSerializerBinding(); - this.deserializerBinding = builder.getDeserializerBinding(); - } - - /** - * Copy constructor. - * - * @param other other customization instance - */ - CustomizationBase(CustomizationBase other) { - this.nillable = other.isNillable(); - this.adapterBinding = other.getSerializeAdapterBinding(); - this.serializerBinding = other.getSerializerBinding(); - this.deserializerBinding = other.getDeserializerBinding(); + CustomizationBase(Builder builder) { + this.nillable = builder.nillable; + this.adapterBinding = builder.adapterBinding; + this.serializerBinding = builder.serializerBinding; + this.deserializerBinding = builder.deserializerBinding; } /** @@ -76,7 +61,7 @@ public AdapterBinding getDeserializeAdapterBinding() { * * @return serializer wrapper */ - public SerializerBinding getSerializerBinding() { + public SerializerBinding getSerializerBinding() { return serializerBinding; } @@ -85,8 +70,51 @@ public SerializerBinding getSerializerBinding() { * * @return deserializer wrapper */ - public DeserializerBinding getDeserializerBinding() { + public DeserializerBinding getDeserializerBinding() { return deserializerBinding; } + @SuppressWarnings("unchecked") + abstract static class Builder, B extends CustomizationBase> { + + private AdapterBinding adapterBinding; + private SerializerBinding serializerBinding; + private DeserializerBinding deserializerBinding; + private boolean nillable; + + Builder() { + } + + public T of(B customization) { + adapterBinding = customization.getDeserializeAdapterBinding(); + serializerBinding = customization.getSerializerBinding(); + deserializerBinding = customization.getDeserializerBinding(); + nillable = customization.isNillable(); + return (T) this; + } + + public T adapterBinding(AdapterBinding adapterBinding) { + this.adapterBinding = adapterBinding; + return (T) this; + } + + public T serializerBinding(SerializerBinding serializerBinding) { + this.serializerBinding = serializerBinding; + return (T) this; + } + + public T deserializerBinding(DeserializerBinding deserializerBinding) { + this.deserializerBinding = deserializerBinding; + return (T) this; + } + + public T nillable(boolean nillable) { + this.nillable = nillable; + return (T) this; + } + + public abstract B build(); + + } + } diff --git a/src/main/java/org/eclipse/yasson/internal/model/customization/CustomizationBuilder.java b/src/main/java/org/eclipse/yasson/internal/model/customization/CustomizationBuilder.java deleted file mode 100644 index 402586ee9..000000000 --- a/src/main/java/org/eclipse/yasson/internal/model/customization/CustomizationBuilder.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.model.customization; - -import org.eclipse.yasson.internal.components.AdapterBinding; -import org.eclipse.yasson.internal.components.DeserializerBinding; -import org.eclipse.yasson.internal.components.SerializerBinding; - -/** - * Abstract base builder for ensuring immutable state of {@link Customization} objects. - */ -public abstract class CustomizationBuilder { - - private boolean nillable; - - private AdapterBinding adapterInfo; - - private SerializerBinding serializerBinding; - - private DeserializerBinding deserializerBinding; - - private String[] propertyOrder; - - /** - * Returns true if nillable customization is present. - * - * @return True if nillable customization is present. - */ - public boolean isNillable() { - return nillable; - } - - /** - * Sets a presence of nillable customization. - * - * @param nillable Presence of nillable customization. - */ - public void setNillable(boolean nillable) { - this.nillable = nillable; - } - - /** - * Gets an components. - * - * @return Adapter. - */ - public AdapterBinding getAdapterInfo() { - return adapterInfo; - } - - /** - * Sets an components. - * - * @param adapterInfo Adapter. - */ - public void setAdapterInfo(AdapterBinding adapterInfo) { - this.adapterInfo = adapterInfo; - } - - /** - * Gets meta info for user serializers. - * - * @return Serializer info - */ - public SerializerBinding getSerializerBinding() { - return serializerBinding; - } - - /** - * Sets serializer info. - * - * @param serializerBinding Serializer info to set. - */ - public void setSerializerBinding(SerializerBinding serializerBinding) { - this.serializerBinding = serializerBinding; - } - - /** - * Gets a deserializer. - * - * @return Deserializer. - */ - public DeserializerBinding getDeserializerBinding() { - return deserializerBinding; - } - - /** - * Sets a deserializer info. - * - * @param deserializerBinding Deserializer. - */ - public void setDeserializerBinding(DeserializerBinding deserializerBinding) { - this.deserializerBinding = deserializerBinding; - } - - /** - * Gets ordered list of property names. - * - * @return Sorted names of properties. - */ - public String[] getPropertyOrder() { - return propertyOrder; - } - - /** - * Sets a sorted list of property names. - * - * @param propertyOrder Array containing property names - */ - public void setPropertyOrder(String[] propertyOrder) { - this.propertyOrder = propertyOrder; - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/model/customization/PropertyCustomization.java b/src/main/java/org/eclipse/yasson/internal/model/customization/PropertyCustomization.java index 60d1a9575..022e458bc 100644 --- a/src/main/java/org/eclipse/yasson/internal/model/customization/PropertyCustomization.java +++ b/src/main/java/org/eclipse/yasson/internal/model/customization/PropertyCustomization.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 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 @@ -12,9 +12,9 @@ package org.eclipse.yasson.internal.model.customization; +import org.eclipse.yasson.internal.JsonbDateFormatter; +import org.eclipse.yasson.internal.JsonbNumberFormatter; import org.eclipse.yasson.internal.components.AdapterBinding; -import org.eclipse.yasson.internal.serializer.JsonbDateFormatter; -import org.eclipse.yasson.internal.serializer.JsonbNumberFormatter; /** * Customization for a property of a class. @@ -33,8 +33,8 @@ public class PropertyCustomization extends CustomizationBase { private final AdapterBinding serializeAdapter; private final AdapterBinding deserializeAdapter; - private boolean readTransient; - private boolean writeTransient; + private final boolean readTransient; + private final boolean writeTransient; private final Class implementationClass; @@ -43,19 +43,23 @@ public class PropertyCustomization extends CustomizationBase { * * @param builder not null */ - public PropertyCustomization(PropertyCustomizationBuilder builder) { + private PropertyCustomization(Builder builder) { super(builder); - this.serializeAdapter = builder.getSerializeAdapter(); - this.deserializeAdapter = builder.getDeserializeAdapter(); - this.jsonReadName = builder.getJsonReadName(); - this.jsonWriteName = builder.getJsonWriteName(); - this.serializeNumberFormatter = builder.getSerializeNumberFormatter(); - this.deserializeNumberFormatter = builder.getDeserializeNumberFormatter(); - this.serializeDateFormatter = builder.getSerializeDateFormatter(); - this.deserializeDateFormatter = builder.getDeserializeDateFormatter(); - this.readTransient = builder.isReadTransient(); - this.writeTransient = builder.isWriteTransient(); - this.implementationClass = builder.getImplementationClass(); + this.serializeAdapter = builder.serializeAdapter; + this.deserializeAdapter = builder.deserializeAdapter; + this.jsonReadName = builder.jsonReadName; + this.jsonWriteName = builder.jsonWriteName; + this.serializeNumberFormatter = builder.serializeNumberFormatter; + this.deserializeNumberFormatter = builder.deserializeNumberFormatter; + this.serializeDateFormatter = builder.serializeDateFormatter; + this.deserializeDateFormatter = builder.deserializeDateFormatter; + this.readTransient = builder.readTransient; + this.writeTransient = builder.writeTransient; + this.implementationClass = builder.implementationClass; + } + + public static Builder builder() { + return new Builder(); } /** @@ -137,4 +141,152 @@ public AdapterBinding getSerializeAdapterBinding() { return serializeAdapter; } + public static final class Builder extends CustomizationBase.Builder { + + private String jsonReadName; + private String jsonWriteName; + private JsonbNumberFormatter serializeNumberFormatter; + private JsonbNumberFormatter deserializeNumberFormatter; + private JsonbDateFormatter serializeDateFormatter; + private JsonbDateFormatter deserializeDateFormatter; + private AdapterBinding serializeAdapter; + private AdapterBinding deserializeAdapter; + private boolean readTransient; + private boolean writeTransient; + private Class implementationClass; + + private Builder() { + } + + @Override + public Builder of(PropertyCustomization customization) { + jsonReadName = customization.jsonReadName; + jsonWriteName = customization.jsonWriteName; + serializeNumberFormatter = customization.serializeNumberFormatter; + deserializeNumberFormatter = customization.deserializeNumberFormatter; + serializeDateFormatter = customization.serializeDateFormatter; + deserializeDateFormatter = customization.deserializeDateFormatter; + serializeAdapter = customization.serializeAdapter; + deserializeAdapter = customization.deserializeAdapter; + readTransient = customization.readTransient; + writeTransient = customization.writeTransient; + implementationClass = customization.implementationClass; + return super.of(customization); + } + + /** + * Set a JSON property name used to read a property value from on deserialization. + * + * @param jsonReadName JSON property name + */ + public Builder jsonReadName(String jsonReadName) { + this.jsonReadName = jsonReadName; + return this; + } + + /** + * Set a property name which is written to JSON document on serialization. + * + * @param jsonWriteName Property name. + */ + public Builder jsonWriteName(String jsonWriteName) { + this.jsonWriteName = jsonWriteName; + return this; + } + + /** + * Set number formatter for formatting numbers during serialization process. + * + * @param serializeNumberFormatter Number formatter for formatting numbers during serialization process. + */ + public Builder serializeNumberFormatter(JsonbNumberFormatter serializeNumberFormatter) { + this.serializeNumberFormatter = serializeNumberFormatter; + return this; + } + + /** + * Set number formatter for formatting numbers during deserialization process. + * + * @param deserializeNumberFormatter Number formatter for formatting numbers during deserialization process. + */ + public Builder deserializeNumberFormatter(JsonbNumberFormatter deserializeNumberFormatter) { + this.deserializeNumberFormatter = deserializeNumberFormatter; + return this; + } + + /** + * Set date formatter for formatting dates during serialization process. + * + * @param serializeDateFormatter Date formatter for formatting dates during serialization process. + */ + public Builder serializeDateFormatter(JsonbDateFormatter serializeDateFormatter) { + this.serializeDateFormatter = serializeDateFormatter; + return this; + } + + /** + * Set date formatter for formatting dates during deserialization process. + * + * @param deserializeDateFormatter Date formatter for formatting dates during deserialization process. + */ + public Builder deserializeDateFormatter(JsonbDateFormatter deserializeDateFormatter) { + this.deserializeDateFormatter = deserializeDateFormatter; + return this; + } + + public Builder serializeAdapter(AdapterBinding serializeAdapter) { + this.serializeAdapter = serializeAdapter; + return this; + } + + public Builder deserializeAdapter(AdapterBinding deserializeAdapter) { + this.deserializeAdapter = deserializeAdapter; + return this; + } + + /** + * Sets a presence of read transient customization. + * + * @param readTransient Presence of read transient customization. + */ + public Builder readTransient(boolean readTransient) { + this.readTransient = readTransient; + return this; + } + + public boolean readTransient() { + return readTransient; + } + + /** + * Sets a presence of write transient customization. + * + * @param writeTransient Presence of write transient customization. + */ + public Builder writeTransient(boolean writeTransient) { + this.writeTransient = writeTransient; + return this; + } + + public boolean writeTransient() { + return writeTransient; + } + + /** + * Implementation class if property is interface type. + * + * @param implementationClass implementing property interface + */ + public Builder implementationClass(Class implementationClass) { + this.implementationClass = implementationClass; + return this; + } + + @Override + public PropertyCustomization build() { + return new PropertyCustomization(this); + } + + } + } diff --git a/src/main/java/org/eclipse/yasson/internal/model/customization/PropertyCustomizationBuilder.java b/src/main/java/org/eclipse/yasson/internal/model/customization/PropertyCustomizationBuilder.java deleted file mode 100644 index 705fe49c5..000000000 --- a/src/main/java/org/eclipse/yasson/internal/model/customization/PropertyCustomizationBuilder.java +++ /dev/null @@ -1,238 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.model.customization; - -import org.eclipse.yasson.internal.components.AdapterBinding; -import org.eclipse.yasson.internal.serializer.JsonbDateFormatter; -import org.eclipse.yasson.internal.serializer.JsonbNumberFormatter; - -/** - * The property customization builder that would be used to build an instance of {@link PropertyCustomization} to ensure its - * immutability. - */ -public class PropertyCustomizationBuilder extends CustomizationBuilder { - - private String jsonReadName; - private String jsonWriteName; - - private JsonbNumberFormatter serializeNumberFormatter; - private JsonbNumberFormatter deserializeNumberFormatter; - - private JsonbDateFormatter serializeDateFormatter; - private JsonbDateFormatter deserializeDateFormatter; - - private boolean readTransient; - private boolean writeTransient; - - private AdapterBinding serializeAdapter; - private AdapterBinding deserializeAdapter; - - private Class implementationClass; - - /** - * Creates a customization for class properties. - * - * @return A new instance of {@link PropertyCustomization} - */ - public PropertyCustomization buildPropertyCustomization() { - return new PropertyCustomization(this); - } - - /** - * Gets number formatter for formatting numbers during serialization process. - * - * @return Number formatter for formatting numbers during serialization process. - */ - public JsonbNumberFormatter getSerializeNumberFormatter() { - return serializeNumberFormatter; - } - - /** - * Sets number formatter for formatting numbers during serialization process. - * - * @param serializeNumberFormatter Number formatter for formatting numbers during serialization process. - */ - public void setSerializeNumberFormatter(JsonbNumberFormatter serializeNumberFormatter) { - this.serializeNumberFormatter = serializeNumberFormatter; - } - - /** - * Gets number formatter for formatting numbers during deserialization process. - * - * @return Number formatter for formatting numbers during deserialization process. - */ - public JsonbNumberFormatter getDeserializeNumberFormatter() { - return deserializeNumberFormatter; - } - - /** - * Sets number formatter for formatting numbers during deserialization process. - * - * @param deserializeNumberFormatter Number formatter for formatting numbers during deserialization process. - */ - public void setDeserializeNumberFormatter(JsonbNumberFormatter deserializeNumberFormatter) { - this.deserializeNumberFormatter = deserializeNumberFormatter; - } - - /** - * Gets date formatter for formatting dates during serialization process. - * - * @return date formatter for formatting dates during serialization process. - */ - public JsonbDateFormatter getSerializeDateFormatter() { - return serializeDateFormatter; - } - - /** - * Sets date formatter for formatting dates during serialization process. - * - * @param serializeDateFormatter Date formatter for formatting dates during serialization process. - */ - public void setSerializeDateFormatter(JsonbDateFormatter serializeDateFormatter) { - this.serializeDateFormatter = serializeDateFormatter; - } - - /** - * Gets date formatter for formatting dates during deserialization process. - * - * @return Date formatter for formatting dates during deserialization process. - */ - public JsonbDateFormatter getDeserializeDateFormatter() { - return deserializeDateFormatter; - } - - /** - * Sets date formatter for formatting dates during deserialization process. - * - * @param deserializeDateFormatter Date formatter for formatting dates during deserialization process. - */ - public void setDeserializeDateFormatter(JsonbDateFormatter deserializeDateFormatter) { - this.deserializeDateFormatter = deserializeDateFormatter; - } - - /** - * Sets a JSON property name used to read a property value from on deserialization. - * - * @return JSON property name - */ - public String getJsonReadName() { - return jsonReadName; - } - - /** - * Sets a JSON property name used to read a property value from on deserialization. - * - * @param jsonReadName JSON property name - */ - public void setJsonReadName(String jsonReadName) { - this.jsonReadName = jsonReadName; - } - - /** - * Gets a property name which is written to JSON document on serialization. - * - * @return Property name. - */ - public String getJsonWriteName() { - return jsonWriteName; - } - - /** - * Sets a property name which is written to JSON document on serialization. - * - * @param jsonWriteName Property name. - */ - public void setJsonWriteName(String jsonWriteName) { - this.jsonWriteName = jsonWriteName; - } - - /** - * Returns true if read transient customization is present. - * - * @return True if read transient customization is present. - */ - public boolean isReadTransient() { - return readTransient; - } - - /** - * Sets a presence of read transient customization. - * - * @param readTransient Presence of read transient customization. - */ - public void setReadTransient(boolean readTransient) { - this.readTransient = readTransient; - } - - /** - * Returns true if write transient customization is present. - * - * @return True if write transient customization is present. - */ - public boolean isWriteTransient() { - return writeTransient; - } - - /** - * Sets a presence of write transient customization. - * - * @param writeTransient Presence of write transient customization. - */ - public void setWriteTransient(boolean writeTransient) { - this.writeTransient = writeTransient; - } - - /** - * Implementation class if property is interface type. - * - * @return class implementing property interface - */ - public Class getImplementationClass() { - return implementationClass; - } - - /** - * Implementation class if property is interface type. - * - * @param implementationClass implementing property interface - */ - public void setImplementationClass(Class implementationClass) { - this.implementationClass = implementationClass; - } - - @Override - public void setAdapterInfo(AdapterBinding adapterInfo) { - throw new UnsupportedOperationException(); - } - - @Override - public AdapterBinding getAdapterInfo() { - return null; - } - - public AdapterBinding getSerializeAdapter() { - return serializeAdapter; - } - - public void setSerializeAdapter(AdapterBinding adapter) { - this.serializeAdapter = adapter; - } - - public AdapterBinding getDeserializeAdapter() { - return deserializeAdapter; - } - - public void setDeserializeAdapter(AdapterBinding adapter) { - this.deserializeAdapter = adapter; - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/model/customization/TypeInheritanceConfiguration.java b/src/main/java/org/eclipse/yasson/internal/model/customization/TypeInheritanceConfiguration.java new file mode 100644 index 000000000..48308d456 --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/model/customization/TypeInheritanceConfiguration.java @@ -0,0 +1,114 @@ +/* + * 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.model.customization; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +import jakarta.json.bind.annotation.JsonbTypeInfo; + +/** + * Type inheritance configuration. + */ +public class TypeInheritanceConfiguration { + + private final String fieldName; + private final boolean inherited; + private final Map, String> aliases; + private final Class definedType; + private final TypeInheritanceConfiguration parentConfig; + + private TypeInheritanceConfiguration(Builder builder) { + this.fieldName = builder.fieldName; + this.inherited = builder.inherited; + this.aliases = Map.copyOf(builder.aliases); + this.parentConfig = builder.parentConfig; + this.definedType = builder.definedType; + } + + public static Builder builder() { + return new Builder(); + } + + public String getFieldName() { + return fieldName; + } + + public boolean isInherited() { + return inherited; + } + + public Map, String> getAliases() { + return aliases; + } + + public Class getDefinedType() { + return definedType; + } + + public TypeInheritanceConfiguration getParentConfig() { + return parentConfig; + } + + public static final class Builder { + + private Map, String> aliases = new HashMap<>(); + private String fieldName = JsonbTypeInfo.DEFAULT_KEY_NAME; + private boolean inherited = false; + private Class definedType; + private TypeInheritanceConfiguration parentConfig; + + private Builder() { + } + + public Builder inherited(boolean inherited) { + this.inherited = inherited; + return this; + } + + public Builder fieldName(String fieldName) { + this.fieldName = Objects.requireNonNull(fieldName); + return this; + } + + public Builder alias(Class clazz, String alias) { + this.aliases.put(clazz, alias); + return this; + } + + public Builder parentConfig(TypeInheritanceConfiguration parentConfig) { + this.parentConfig = parentConfig; + return this; + } + + public Builder definedType(Class definedType) { + this.definedType = definedType; + return this; + } + + public Builder of(TypeInheritanceConfiguration typeInheritanceConfiguration) { + this.fieldName = typeInheritanceConfiguration.fieldName; + this.aliases = new HashMap<>(typeInheritanceConfiguration.aliases); + this.inherited = typeInheritanceConfiguration.inherited; + this.parentConfig = typeInheritanceConfiguration.parentConfig; + this.definedType = typeInheritanceConfiguration.definedType; + return this; + } + + public TypeInheritanceConfiguration build() { + return new TypeInheritanceConfiguration(this); + } + } + +} diff --git a/src/main/java/org/eclipse/yasson/internal/model/customization/VisibilityStrategiesProvider.java b/src/main/java/org/eclipse/yasson/internal/model/customization/VisibilityStrategiesProvider.java new file mode 100644 index 000000000..9967bb52a --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/model/customization/VisibilityStrategiesProvider.java @@ -0,0 +1,106 @@ +/* + * 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.model.customization; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; + +import jakarta.json.bind.JsonbException; +import jakarta.json.bind.config.PropertyVisibilityStrategy; + +import org.eclipse.yasson.internal.properties.MessageKeys; +import org.eclipse.yasson.internal.properties.Messages; + +/** + * Provider of the JSON-B visibility strategies. + */ +public class VisibilityStrategiesProvider { + + private static final PropertyVisibilityStrategy PUBLIC_PROPERTY = new PublicPropertyVisibilityStrategy(); + private static final PropertyVisibilityStrategy PUBLIC_ACCESSOR_METHODS = new PublicAccessorVisibilityStrategy(); + private static final PropertyVisibilityStrategy PUBLIC_FIELDS = new PublicFieldsVisibilityStrategy(); + private static final PropertyVisibilityStrategy ALL_FIELDS_AND_METHODS = new AllFieldsVisibilityStrategy(); + + private VisibilityStrategiesProvider() { + throw new IllegalStateException("This class cannot be instantiated"); + } + + public static PropertyVisibilityStrategy getStrategy(String strategy) { + switch (strategy) { + case "PUBLIC_PROPERTY": + return PUBLIC_PROPERTY; + case "PUBLIC_ACCESSOR_METHODS": + return PUBLIC_ACCESSOR_METHODS; + case "PUBLIC_FIELDS": + return PUBLIC_FIELDS; + case "ALL_FIELD_AND_ACCESSORS": + return ALL_FIELDS_AND_METHODS; + default: + throw new JsonbException(Messages.getMessage(MessageKeys.UNKNOWN_VISIBILITY_STRATEGY, strategy)); + } + } + + private static final class PublicPropertyVisibilityStrategy implements PropertyVisibilityStrategy { + @Override + public boolean isVisible(Field field) { + return Modifier.isPublic(field.getModifiers()); + } + + @Override + public boolean isVisible(Method method) { + return Modifier.isPublic(method.getModifiers()); + } + } + + private static final class PublicAccessorVisibilityStrategy implements PropertyVisibilityStrategy { + + @Override + public boolean isVisible(Field field) { + return false; + } + + @Override + public boolean isVisible(Method method) { + return Modifier.isPublic(method.getModifiers()); + } + + } + + private static final class PublicFieldsVisibilityStrategy implements PropertyVisibilityStrategy { + + @Override + public boolean isVisible(Field field) { + return Modifier.isPublic(field.getModifiers()); + } + + @Override + public boolean isVisible(Method method) { + return false; + } + + } + + private static final class AllFieldsVisibilityStrategy implements PropertyVisibilityStrategy { + @Override + public boolean isVisible(Field field) { + return true; + } + + @Override + public boolean isVisible(Method method) { + return true; + } + } + +} diff --git a/src/main/java/org/eclipse/yasson/internal/properties/MessageKeys.java b/src/main/java/org/eclipse/yasson/internal/properties/MessageKeys.java index 90fd80849..d08377cef 100644 --- a/src/main/java/org/eclipse/yasson/internal/properties/MessageKeys.java +++ b/src/main/java/org/eclipse/yasson/internal/properties/MessageKeys.java @@ -311,7 +311,11 @@ public enum MessageKeys { /** * Target json value is not valid {@link JsonNumber}. */ - NUMBER_INCOMPATIBLE_VALUE_TYPE_OBJECT("numberIncompatibleValueTypeObject"); + NUMBER_INCOMPATIBLE_VALUE_TYPE_OBJECT("numberIncompatibleValueTypeObject"), + /** + * Unknown visibility strategy. + */ + UNKNOWN_VISIBILITY_STRATEGY("unknownVisibilityStrategy"); /** * Message bundle key. diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/AbstractArrayDeserializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/AbstractArrayDeserializer.java deleted file mode 100644 index c7f7323a8..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/AbstractArrayDeserializer.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (c) 2016, 2021 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.serializer; - -import java.lang.reflect.GenericArrayType; -import java.util.List; - -import jakarta.json.bind.serializer.JsonbDeserializer; -import jakarta.json.stream.JsonParser; - -import org.eclipse.yasson.internal.JsonbParser; -import org.eclipse.yasson.internal.JsonbRiParser; -import org.eclipse.yasson.internal.ReflectionUtils; -import org.eclipse.yasson.internal.Unmarshaller; -import org.eclipse.yasson.internal.model.ClassModel; - -/** - * Common array unmarshalling item implementation. - * - * @param array type - */ -public abstract class AbstractArrayDeserializer extends AbstractContainerDeserializer implements EmbeddedItem { - - /** - * Runtime type class of an array. - */ - private final Class componentClass; - private final ClassModel componentClassModel; - - /** - * Creates new class instance. - * - * @param builder deserializer builder - */ - AbstractArrayDeserializer(DeserializerBuilder builder) { - super(builder); - if (getRuntimeType() instanceof GenericArrayType) { - componentClass = ReflectionUtils - .resolveRawType(this, ((GenericArrayType) getRuntimeType()).getGenericComponentType()); - } else { - componentClass = ReflectionUtils.getRawType(getRuntimeType()).getComponentType(); - } - if (!DefaultSerializers.isKnownType(componentClass)) { - componentClassModel = builder.getJsonbContext().getMappingContext().getOrCreateClassModel(componentClass); - } else { - componentClassModel = null; - } - } - - /** - * Returns component class. - * - * @return component class - */ - Class getComponentClass() { - return componentClass; - } - - @Override - public void appendResult(Object result, Unmarshaller context) { - appendCaptor(convertNullToOptionalEmpty(componentClass, result)); - } - - @SuppressWarnings("unchecked") - private void appendCaptor(X value) { - ((List) getItems()).add(value); - } - - @Override - protected void deserializeNext(JsonParser parser, Unmarshaller context) { - final JsonbDeserializer deserializer = newUnmarshallerItemBuilder(context.getJsonbContext()).withType(componentClass) - .withCustomization(componentClassModel == null ? null : componentClassModel.getClassCustomization()).build(); - appendResult(deserializer.deserialize(parser, context, componentClass), context); - } - - /** - * Returns list of deserialized items. - * - * @return list of items - */ - protected abstract List getItems(); - - @Override - protected JsonbRiParser.LevelContext moveToFirst(JsonbParser parser) { - parser.moveTo(JsonParser.Event.START_ARRAY); - return parser.getCurrentLevel(); - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/AbstractArraySerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/AbstractArraySerializer.java deleted file mode 100644 index 9bb4b1000..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/AbstractArraySerializer.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import jakarta.json.stream.JsonGenerator; - -/** - * Common serializer for arrays. - * - * @param Type to serialize. - */ -public abstract class AbstractArraySerializer extends AbstractContainerSerializer implements EmbeddedItem { - - /** - * Creates new instance of array serializer. - * - * @param builder serializer builder - */ - protected AbstractArraySerializer(SerializerBuilder builder) { - super(builder); - } - - @Override - protected void writeStart(JsonGenerator generator) { - generator.writeStartArray(); - } - - @Override - protected void writeStart(String key, JsonGenerator generator) { - generator.writeStartArray(key); - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/AbstractContainerDeserializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/AbstractContainerDeserializer.java deleted file mode 100644 index 34ab8009f..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/AbstractContainerDeserializer.java +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright (c) 2016, 2021 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.serializer; - -import java.lang.reflect.Type; -import java.util.Optional; -import java.util.OptionalDouble; -import java.util.OptionalInt; -import java.util.OptionalLong; - -import jakarta.json.bind.JsonbException; -import jakarta.json.bind.serializer.DeserializationContext; -import jakarta.json.bind.serializer.JsonbDeserializer; -import jakarta.json.stream.JsonParser; - -import org.eclipse.yasson.internal.JsonbContext; -import org.eclipse.yasson.internal.JsonbParser; -import org.eclipse.yasson.internal.JsonbRiParser; -import org.eclipse.yasson.internal.ReflectionUtils; -import org.eclipse.yasson.internal.Unmarshaller; -import org.eclipse.yasson.internal.properties.MessageKeys; -import org.eclipse.yasson.internal.properties.Messages; - -/** - * Base class for all deserializers producing non single value result. - * Deserialize bean objects, collections, maps, arrays, etc. - * - * @param container type - */ -public abstract class AbstractContainerDeserializer extends AbstractItem implements JsonbDeserializer { - - private JsonbRiParser.LevelContext parserContext; - - /** - * Create instance of current item with its builder. - * - * @param builder {@link DeserializerBuilder} used to build this instance - */ - AbstractContainerDeserializer(DeserializerBuilder builder) { - super(builder); - } - - /** - * Drives JSONP {@link JsonParser} to deserialize json document. - * - * @param parser JSON parser. - * @param context Deseriaization context. - * @param rtType Runtime type. - * @return Instance of a type for this item. - */ - @Override - public final T deserialize(JsonParser parser, DeserializationContext context, Type rtType) { - Unmarshaller ctx = (Unmarshaller) context; - deserializeInternal((JsonbParser) parser, ctx); - return getInstance((Unmarshaller) context); - } - - /** - * Creates and initializes an instance of deserializing item. - * - * @param unmarshaller Current deserialization context. - * @return An instance of deserializing item. - */ - protected abstract T getInstance(Unmarshaller unmarshaller); - - /** - * Deserialize specific item type. - * - * @param parser jsonb parser - * @param context context - */ - protected void deserializeInternal(JsonbParser parser, Unmarshaller context) { - parserContext = moveToFirst(parser); - while (parser.hasNext()) { - final JsonParser.Event event = parser.next(); - switch (event) { - case START_OBJECT: - case START_ARRAY: - case VALUE_STRING: - case VALUE_NUMBER: - case VALUE_FALSE: - case VALUE_TRUE: - try { - deserializeNext(parser, context); - } catch (JsonbException e) { - if (parserContext == null || parserContext.getLastKeyName() == null) { - throw e; - } else { - throw new JsonbException("Unable to deserialize property '" + parserContext.getLastKeyName() - + "' because of: " + e.getMessage(), e); - } - } - break; - case KEY_NAME: - break; - case VALUE_NULL: - appendResult(null, context); - break; - case END_OBJECT: - case END_ARRAY: - return; - default: - throw new JsonbException(Messages.getMessage(MessageKeys.NOT_VALUE_TYPE, event)); - } - } - } - - /** - * Determine class mappings and create an instance of a new deserializer. - * Currently processed deserializer is pushed to stack, for waiting till new object is finished. - * - * @param parser Json parser. - * @param context Current unmarshalling context. - */ - protected abstract void deserializeNext(JsonParser parser, Unmarshaller context); - - /** - * Move to first event for current deserializer structure. - * - * @param parser Json parser. - * @return First event. - */ - protected abstract JsonbRiParser.LevelContext moveToFirst(JsonbParser parser); - - /** - * Returns new deserialization builder for specific item. - * - * @param ctx jsonb context - * @return deserialization builder - */ - protected DeserializerBuilder newUnmarshallerItemBuilder(JsonbContext ctx) { - return ContainerDeserializerUtils.newUnmarshallerItemBuilder(this, ctx, parserContext.getLastEvent()); - } - - /** - * Returns new deserialization builder for specific collection or map. - * - * @param valueType value type - * @param ctx jsonb context - * @return deserialization builder - */ - protected JsonbDeserializer newCollectionOrMapItem(Type valueType, JsonbContext ctx) { - return ContainerDeserializerUtils.newCollectionOrMapItem(this, valueType, ctx, parserContext.getLastEvent()); - } - - /** - * If value is null and property model type is one of {@link Optional}, {@link OptionalDouble}, - * {@link OptionalInt}, or {@link OptionalLong}, value of corresponding {@code Optional#empty()} - * is returned. - * - * @param propertyType property type - * @param value value to set - * @return empty optional if applies - */ - protected Object convertNullToOptionalEmpty(Type propertyType, Object value) { - if (value != null) { - return value; - } - - if (!(propertyType instanceof Class)) { - propertyType = ReflectionUtils.getRawType(ReflectionUtils.resolveType(this, propertyType)); - } - - if (propertyType == Optional.class) { - return Optional.empty(); - } else if (propertyType == OptionalInt.class) { - return OptionalInt.empty(); - } else if (propertyType == OptionalLong.class) { - return OptionalLong.empty(); - } else if (propertyType == OptionalDouble.class) { - return OptionalDouble.empty(); - } else { - return null; - } - } - - /** - * After object is transitively deserialized from JSON, "append" it to its wrapper. - * In case of a field set value to field, in case of collections - * or other embedded objects use methods provided. - * - * @param result An instance result of an item. - * @param context Current unmarshalling context. - */ - public abstract void appendResult(Object result, Unmarshaller context); - - /** - * Returns parser context. - * - * @return parser context - */ - JsonbRiParser.LevelContext getParserContext() { - return parserContext; - } - - /** - * Sets new parser context. - * - * @param parserContext parser context - */ - void setParserContext(JsonbRiParser.LevelContext parserContext) { - this.parserContext = parserContext; - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/AbstractContainerSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/AbstractContainerSerializer.java deleted file mode 100644 index 24877570b..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/AbstractContainerSerializer.java +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; -import java.util.Objects; -import java.util.Optional; - -import jakarta.json.bind.serializer.JsonbSerializer; -import jakarta.json.bind.serializer.SerializationContext; -import jakarta.json.stream.JsonGenerator; - -import org.eclipse.yasson.internal.Marshaller; -import org.eclipse.yasson.internal.ReflectionUtils; -import org.eclipse.yasson.internal.model.ClassModel; -import org.eclipse.yasson.internal.model.customization.ClassCustomizationBuilder; -import org.eclipse.yasson.internal.model.customization.ContainerCustomization; - -/** - * Base class for container serializers (list, array, etc.). - * - * @param container value type - */ -public abstract class AbstractContainerSerializer extends AbstractItem implements JsonbSerializer { - - private JsonbSerializer valueSerializer; - - private Class valueClass; - - /** - * Create instance of current item with its builder. - * - * @param builder {@link SerializerBuilder} used to build this instance - */ - protected AbstractContainerSerializer(SerializerBuilder builder) { - super(builder); - } - - /** - * Creates a new instance. - * - * @param wrapper Item to serialize. - * @param runtimeType Runtime type of the item. - * @param classModel Class model. - */ - public AbstractContainerSerializer(CurrentItem wrapper, Type runtimeType, ClassModel classModel) { - super(wrapper, runtimeType, classModel); - } - - /** - * Process container before serialization begins. - * Does nothing by default. - * - * @param obj item to be serialized - */ - protected void beforeSerialize(T obj) { - } - - /** - * Write start of an object or an array without a key. - * - * @param generator JSON format generator - */ - protected abstract void writeStart(JsonGenerator generator); - - /** - * Write start of an object or an array with a key. - * - * @param key JSON key name. - * @param generator JSON format generator - */ - protected abstract void writeStart(String key, JsonGenerator generator); - - /** - * Writes end of an object or an array. - * - * @param generator JSON format generator - */ - protected void writeEnd(JsonGenerator generator) { - generator.writeEnd(); - } - - /** - * Serialize content of provided container. - * - * @param obj container to be serialized - * @param generator JSON format generator - * @param ctx JSON serialization context - */ - protected abstract void serializeInternal(T obj, JsonGenerator generator, SerializationContext ctx); - - @Override - public final void serialize(T obj, JsonGenerator generator, SerializationContext ctx) { - beforeSerialize(obj); - writeStart(generator); - serializeInternal(obj, generator, ctx); - writeEnd(generator); - } - - /** - * Serializes container object item. - * - * @param serializer serializer of the object - * @param object object to serialize - * @param generator json generator - * @param ctx context - * @param type of object - */ - @SuppressWarnings("unchecked") - protected void serializerCaptor(JsonbSerializer serializer, - X object, - JsonGenerator generator, - SerializationContext ctx) { - ((JsonbSerializer) serializer).serialize(object, generator, ctx); - } - - /** - * Return last used serializer if last value class matches. - * - * @param valueClass class of the serialized object - * @return cached serializer or null - */ - protected JsonbSerializer getValueSerializer(Class valueClass) { - if (valueSerializer != null && valueClass == this.valueClass) { - return valueSerializer; - } - return null; - } - - /** - * Cache a serializer and serialized object class for next use. - * - * @param valueSerializer serializer - * @param valueClass class of serializer object - */ - protected void addValueSerializer(JsonbSerializer valueSerializer, Class valueClass) { - Objects.requireNonNull(valueSerializer); - Objects.requireNonNull(valueClass); - this.valueSerializer = valueSerializer; - this.valueClass = valueClass; - } - - /** - * Serializes container object. - * - * @param item container - * @param generator json generator - * @param ctx context - */ - protected void serializeItem(Object item, JsonGenerator generator, SerializationContext ctx) { - if (item == null) { - generator.writeNull(); - return; - } - Class itemClass = item.getClass(); - //Not null when generic type is present or previous item is of same type - JsonbSerializer serializer = getValueSerializer(itemClass); - - //Raw collections + lost generic information - if (serializer == null) { - Type instanceValueType = getValueType(getRuntimeType()); - instanceValueType = instanceValueType.equals(Object.class) ? itemClass : instanceValueType; - - SerializerBuilder builder = new SerializerBuilder(((Marshaller) ctx).getJsonbContext()); - builder.withObjectClass(itemClass); - builder.withWrapper(this); - builder.withType(instanceValueType); - - if (!DefaultSerializers.isKnownType(itemClass)) { - //Need for class level annotations + user adapters/serializers bound to type - ClassModel classModel = ((Marshaller) ctx).getJsonbContext().getMappingContext().getOrCreateClassModel(itemClass); - builder.withCustomization(new ContainerCustomization(classModel.getClassCustomization())); - } else { - //Still need to override isNillable to true with ContainerCustomization for all serializers - //to preserve collections and array null elements - builder.withCustomization(new ContainerCustomization(new ClassCustomizationBuilder())); - } - serializer = builder.build(); - - //Cache last used value serializer in case of next item is the same type. - addValueSerializer(serializer, itemClass); - } - serializerCaptor(serializer, item, generator, ctx); - } - - /** - * Value type of the container. - * - * @param valueType value type - * @return raw value type - */ - protected Type getValueType(Type valueType) { - if (valueType instanceof ParameterizedType) { - Optional runtimeTypeOptional = ReflectionUtils - .resolveOptionalType(this, ((ParameterizedType) valueType).getActualTypeArguments()[0]); - return runtimeTypeOptional.orElse(Object.class); - } - return Object.class; - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/AbstractDateTimeDeserializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/AbstractDateTimeDeserializer.java deleted file mode 100644 index c609c6118..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/AbstractDateTimeDeserializer.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import java.lang.reflect.Type; -import java.time.DateTimeException; -import java.time.Instant; -import java.time.ZoneId; -import java.time.format.DateTimeFormatter; -import java.util.Locale; - -import jakarta.json.bind.JsonbException; -import jakarta.json.bind.annotation.JsonbDateFormat; - -import org.eclipse.yasson.internal.JsonbContext; -import org.eclipse.yasson.internal.Unmarshaller; -import org.eclipse.yasson.internal.model.customization.Customization; -import org.eclipse.yasson.internal.properties.MessageKeys; -import org.eclipse.yasson.internal.properties.Messages; - -/** - * Abstract class for converting date objects from java.time. - * - * @param date type - */ -public abstract class AbstractDateTimeDeserializer extends AbstractValueTypeDeserializer { - - /** - * Default zone id. - */ - public static final ZoneId UTC = ZoneId.of("UTC"); - - /** - * Creates an instance. - * - * @param clazz Class to create deserializer for. - * @param customization Model customization. - */ - public AbstractDateTimeDeserializer(Class clazz, Customization customization) { - super(clazz, customization); - } - - @Override - public T deserialize(String jsonValue, Unmarshaller unmarshaller, Type rtType) { - final JsonbDateFormatter formatter = getJsonbDateFormatter(unmarshaller.getJsonbContext()); - if (JsonbDateFormat.TIME_IN_MILLIS.equals(formatter.getFormat())) { - return fromInstant(Instant.ofEpochMilli(Long.parseLong(jsonValue))); - } else if (formatter.getDateTimeFormatter() != null) { - return parseWithFormatterInternal(jsonValue, formatter.getDateTimeFormatter()); - } else { - DateTimeFormatter configDateTimeFormatter = unmarshaller.getJsonbContext().getConfigProperties() - .getConfigDateFormatter().getDateTimeFormatter(); - if (configDateTimeFormatter != null) { - return parseWithFormatterInternal(jsonValue, configDateTimeFormatter); - } - } - final boolean strictIJson = unmarshaller.getJsonbContext().getConfigProperties().isStrictIJson(); - if (strictIJson) { - return parseWithFormatterInternal(jsonValue, JsonbDateFormatter.IJSON_DATE_FORMATTER); - } - try { - return parseDefault(jsonValue, unmarshaller.getJsonbContext().getConfigProperties().getLocale(formatter.getLocale())); - } catch (DateTimeException e) { - throw new JsonbException(Messages.getMessage(MessageKeys.DATE_PARSE_ERROR, jsonValue, getPropertyType()), e); - } - } - - /** - * Returns registered deserialization jsonb date formatter. - * - * @param context context - * @return date formatter - */ - protected JsonbDateFormatter getJsonbDateFormatter(JsonbContext context) { - if (getCustomization() != null && getCustomization().getDeserializeDateFormatter() != null) { - return getCustomization().getDeserializeDateFormatter(); - } - return context.getConfigProperties().getConfigDateFormatter(); - } - - /** - * Append UTC zone in case zone is not set on formatter. - * - * @param formatter formatter - * @return zoned formatter - */ - protected DateTimeFormatter getZonedFormatter(DateTimeFormatter formatter) { - return formatter.getZone() != null - ? formatter - : formatter.withZone(UTC); - } - - /** - * Construct date object from an instant containing epoch millisecond. - * If date object supports zone offset / zone id, system default is used and warning is logged. - * - * @param instant instant to construct from - * @return date object - */ - protected abstract T fromInstant(Instant instant); - - /** - * Parse java.time date object with default formatter. - * Different default formatter for each date object type is used. - * - * @param jsonValue string value to parse from - * @param locale annotated locale or default - * @return parsed date object - */ - protected abstract T parseDefault(String jsonValue, Locale locale); - - /** - * Parse java.time date object with provided formatter. - * - * @param jsonValue string value to parse from - * @param formatter a formatter to use - * @return parsed date object - */ - protected abstract T parseWithFormatter(String jsonValue, DateTimeFormatter formatter); - - private T parseWithFormatterInternal(String jsonValue, DateTimeFormatter formatter) { - try { - return parseWithFormatter(jsonValue, formatter); - } catch (DateTimeException e) { - throw new JsonbException(Messages.getMessage(MessageKeys.DATE_PARSE_ERROR, jsonValue, getPropertyType()), e); - } - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/AbstractItem.java b/src/main/java/org/eclipse/yasson/internal/serializer/AbstractItem.java deleted file mode 100644 index bdb174f23..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/AbstractItem.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import java.lang.reflect.Type; - -import org.eclipse.yasson.internal.model.ClassModel; - -/** - * Metadata wrapper for currently processed object. - * References mapping models of an unmarshalled item, - * creates instances of it, sets finished unmarshalled objects into object tree. - * - * @param Instantiated object type - */ -public abstract class AbstractItem implements CurrentItem { - - /** - * Item containing instance of wrapping object and its metadata. - * Null in case of a root object. - */ - private final CurrentItem wrapper; - - private final Type runtimeType; - - /** - * Cached reference to mapping model of an item. - */ - private final ClassModel classModel; - - /** - * Creates and populates an instance from given builder. - * - * @param builder Builder to initialize from. - */ - protected AbstractItem(AbstractSerializerBuilder builder) { - this.wrapper = builder.getWrapper(); - this.classModel = builder.getClassModel(); - this.runtimeType = builder.getRuntimeType(); - } - - /** - * Creates an instance. - * - * @param wrapper Item wrapper. - * @param runtimeType Runtime type. - * @param classModel Class model. - */ - public AbstractItem(CurrentItem wrapper, Type runtimeType, ClassModel classModel) { - this.wrapper = wrapper; - this.runtimeType = runtimeType; - this.classModel = classModel; - } - - @Override - public ClassModel getClassModel() { - return classModel; - } - - @Override - public CurrentItem getWrapper() { - return wrapper; - } - - @Override - public Type getRuntimeType() { - return runtimeType; - } - -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/AbstractJsonpDeserializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/AbstractJsonpDeserializer.java deleted file mode 100644 index f6b6310ef..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/AbstractJsonpDeserializer.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2016, 2021 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.serializer; - -import jakarta.json.JsonValue; -import jakarta.json.stream.JsonParser; - -import org.eclipse.yasson.internal.JsonbParser; -import org.eclipse.yasson.internal.JsonbRiParser; -import org.eclipse.yasson.internal.Unmarshaller; - -/** - * Common implementation for JSONP Object and Array. - * - * @param json value type - */ -public abstract class AbstractJsonpDeserializer extends AbstractContainerDeserializer { - - /** - * Create instance of current item with its builder. - * - * @param builder {@link DeserializerBuilder} used to build this instance - */ - protected AbstractJsonpDeserializer(DeserializerBuilder builder) { - super(builder); - } - - @Override - protected JsonbRiParser.LevelContext moveToFirst(JsonbParser parser) { - parser.moveToStartStructure(); - return parser.getCurrentLevel(); - } - - @Override - protected void deserializeNext(JsonParser parser, Unmarshaller context) { - throw new UnsupportedOperationException("Inner json structures are deserialized by JsonParser."); - } - - @Override - public void appendResult(Object result, Unmarshaller context) { - throw new UnsupportedOperationException("Inner json structures are deserialized by JsonParser."); - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/AbstractJsonpSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/AbstractJsonpSerializer.java deleted file mode 100644 index 227718122..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/AbstractJsonpSerializer.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import jakarta.json.JsonValue; - -/** - * Common serializer functionality. - * - * @param Type to serialize. - */ -public abstract class AbstractJsonpSerializer extends AbstractContainerSerializer { - - /** - * Creates new instance of jsonp serializer. - * - * @param builder serializer builder - */ - protected AbstractJsonpSerializer(SerializerBuilder builder) { - super(builder); - } - -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/AbstractNumberDeserializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/AbstractNumberDeserializer.java deleted file mode 100644 index 07984bb67..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/AbstractNumberDeserializer.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2016, 2021 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.serializer; - -import java.text.DecimalFormat; -import java.text.DecimalFormatSymbols; -import java.text.NumberFormat; -import java.text.ParseException; -import java.util.Locale; -import java.util.Optional; - -import jakarta.json.bind.JsonbException; - -import org.eclipse.yasson.internal.JsonbContext; -import org.eclipse.yasson.internal.model.customization.Customization; -import org.eclipse.yasson.internal.properties.MessageKeys; -import org.eclipse.yasson.internal.properties.Messages; - -/** - * Common serializer for numbers, using number format. - * - * @param Type to deserialize. - */ -public abstract class AbstractNumberDeserializer extends AbstractValueTypeDeserializer { - - /** - * Creates a new instance. - * - * @param clazz Class to work with. - * @param customization Model customization. - */ - public AbstractNumberDeserializer(Class clazz, Customization customization) { - super(clazz, customization); - } - - /** - * Returns formatted number value. - * - * @param jsonValue value to be formatted - * @param integerOnly format only integer - * @param jsonbContext context - * @return formatted number value - */ - protected final Optional deserializeFormatted(String jsonValue, boolean integerOnly, JsonbContext jsonbContext) { - if (getCustomization() == null || getCustomization().getDeserializeNumberFormatter() == null) { - return Optional.empty(); - } - - final JsonbNumberFormatter numberFormat = getCustomization().getDeserializeNumberFormatter(); - //consider synchronizing on format instance or per thread cache. - Locale locale = jsonbContext.getConfigProperties().getLocale(numberFormat.getLocale()); - final NumberFormat format = NumberFormat.getInstance(locale); - ((DecimalFormat) format).applyPattern(numberFormat.getFormat()); - format.setParseIntegerOnly(integerOnly); - try { - return Optional.of(format.parse(compatibilityChanger(jsonValue, locale))); - } catch (ParseException e) { - throw new JsonbException(Messages.getMessage(MessageKeys.PARSING_NUMBER, jsonValue, numberFormat.getFormat())); - } - } - - private String compatibilityChanger(String value, Locale locale) { - char beforeJdk13GroupSeparator = '\u00A0'; - char frenchGroupingSeparator = DecimalFormatSymbols.getInstance(Locale.FRENCH).getGroupingSeparator(); - if (locale.getLanguage().equals(Locale.FRENCH.getLanguage()) && beforeJdk13GroupSeparator != frenchGroupingSeparator) { - //JDK-8225245 - return value.replace(beforeJdk13GroupSeparator, frenchGroupingSeparator); - } - return value; - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/AbstractNumberSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/AbstractNumberSerializer.java deleted file mode 100644 index b2e23756d..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/AbstractNumberSerializer.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import java.text.DecimalFormat; -import java.text.NumberFormat; - -import jakarta.json.stream.JsonGenerator; - -import org.eclipse.yasson.internal.Marshaller; -import org.eclipse.yasson.internal.model.customization.Customization; - -/** - * Common serializer for numbers, using number format. - * - * @param number type - */ -public abstract class AbstractNumberSerializer extends AbstractValueTypeSerializer { - - private final JsonbNumberFormatter formatter; - - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public AbstractNumberSerializer(Customization customization) { - super(customization); - formatter = customization != null - ? customization.getSerializeNumberFormatter() - : null; - } - - /** - * Serialize raw number when NumberFormat is not present. - * - * @param obj number - * @param generator generator to use - * @param key json key - */ - protected abstract void serializeNonFormatted(T obj, JsonGenerator generator, String key); - - @Override - protected void serialize(T obj, JsonGenerator generator, Marshaller marshaller) { - if (formatter != null) { - final NumberFormat format = NumberFormat - .getInstance(marshaller.getJsonbContext().getConfigProperties().getLocale(formatter.getLocale())); - ((DecimalFormat) format).applyPattern(formatter.getFormat()); - generator.write(format.format(obj)); - } else { - serializeNonFormatted(obj, generator); - } - } - - /** - * Serialize raw number when NumberFormat is not present. - * - * @param obj number - * @param generator generator to use - */ - protected abstract void serializeNonFormatted(T obj, JsonGenerator generator); - -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/EmbeddedItem.java b/src/main/java/org/eclipse/yasson/internal/serializer/AbstractSerializer.java similarity index 58% rename from src/main/java/org/eclipse/yasson/internal/serializer/EmbeddedItem.java rename to src/main/java/org/eclipse/yasson/internal/serializer/AbstractSerializer.java index aaff53630..6ed18d81f 100644 --- a/src/main/java/org/eclipse/yasson/internal/serializer/EmbeddedItem.java +++ b/src/main/java/org/eclipse/yasson/internal/serializer/AbstractSerializer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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 @@ -13,8 +13,14 @@ package org.eclipse.yasson.internal.serializer; /** - * Tagging interface for embedded object items, such as List, Maps or Arrays. + * Abstract model serializer with delegate. */ -public interface EmbeddedItem { +abstract class AbstractSerializer implements ModelSerializer { + + final ModelSerializer delegate; + + AbstractSerializer(ModelSerializer delegate) { + this.delegate = delegate; + } } diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/AbstractSerializerBuilder.java b/src/main/java/org/eclipse/yasson/internal/serializer/AbstractSerializerBuilder.java deleted file mode 100644 index 87c62b46e..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/AbstractSerializerBuilder.java +++ /dev/null @@ -1,202 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import java.lang.reflect.Type; -import java.util.Objects; - -import org.eclipse.yasson.internal.JsonbContext; -import org.eclipse.yasson.internal.model.ClassModel; -import org.eclipse.yasson.internal.model.customization.Customization; - -/** - * Base class for serializer builders. - * - * @param serialization builder type - */ -public class AbstractSerializerBuilder { - - /** - * Not null with an exception of a root item. - */ - private CurrentItem wrapper; - - /** - * In case of unknown object genericType. - * Null for embedded objects such as collections, or known conversion types. - */ - private ClassModel classModel; - - /** - * Runtime type resolved after expanding type variables and wildcards. - */ - private Type runtimeType; - - /** - * Type is used when field model is not present. - * In case of root, or embedded objects such as collections. - */ - private Type genericType; - - /** - * Class customization. - */ - private Customization customization; - - /** - * Jsonb context. - */ - private final JsonbContext jsonbContext; - - /** - * Crates a builder. - * - * @param jsonbContext Not null. - */ - public AbstractSerializerBuilder(JsonbContext jsonbContext) { - Objects.requireNonNull(jsonbContext); - this.jsonbContext = jsonbContext; - } - - /** - * Wrapper item for this item. - * - * @param wrapper not null. - * @return Builder instance for call chaining. - */ - @SuppressWarnings("unchecked") - public T withWrapper(CurrentItem wrapper) { - this.wrapper = wrapper; - return (T) this; - } - - /** - * Customization of the class. - * - * @param customization Class customization - * @return Builder instance for call chaining. - */ - @SuppressWarnings("unchecked") - public T withCustomization(Customization customization) { - this.customization = customization; - return (T) this; - } - - /** - * Class model for this item. - * - * @param classModel class model - * @return Builder instance for call chaining. - */ - @SuppressWarnings("unchecked") - public T withClassModel(ClassModel classModel) { - this.classModel = classModel; - return (T) this; - } - - /** - * Runtime type for this item. - * - * @param runtimeType runtime type - * @return Builder instance for call chaining. - */ - @SuppressWarnings("unchecked") - public T withRuntimeType(Type runtimeType) { - this.runtimeType = runtimeType; - return (T) this; - } - - /*** - * Gets or load class model for a class an its superclasses. - * - * @param rawType Class to get model for. - * @return Class model. - */ - protected ClassModel getClassModel(Class rawType) { - ClassModel classModel = jsonbContext.getMappingContext().getClassModel(rawType); - if (classModel == null) { - classModel = jsonbContext.getMappingContext().getOrCreateClassModel(rawType); - } - return classModel; - } - - /** - * Wrapper item for this item. - * - * @return Wrapper item. - */ - public CurrentItem getWrapper() { - return wrapper; - } - - /** - * Model of a class representing current item and instance (if any). - * Known collection classes doesn't need such a model. - * - * @return model of a class - */ - public ClassModel getClassModel() { - return classModel; - } - - /** - * Resolved runtime type for instance in case of {@link java.lang.reflect.TypeVariable} or - * {@link java.lang.reflect.WildcardType}. - * Otherwise provided type in type field, or type of field model. - * - * @return runtime type - */ - public Type getRuntimeType() { - return runtimeType; - } - - /** - * Type for underlying instance to be created from. - * In case of type variable or wildcard, will be resolved recursively from parent items. - * - * @param type type of instance not null - * @return builder instance for call chaining - */ - @SuppressWarnings("unchecked") - public T withType(Type type) { - this.genericType = type; - return (T) this; - } - - /** - * Jsonb runtime context. - * - * @return jsonb context - */ - public JsonbContext getJsonbContext() { - return jsonbContext; - } - - /** - * Type customization. - * - * @return customization - */ - public Customization getCustomization() { - return customization; - } - - /** - * Generic type of the item. - * - * @return generic type - */ - public Type getGenericType() { - return genericType; - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/AbstractValueTypeDeserializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/AbstractValueTypeDeserializer.java deleted file mode 100644 index 893658e4d..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/AbstractValueTypeDeserializer.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import java.lang.reflect.Type; - -import jakarta.json.bind.serializer.DeserializationContext; -import jakarta.json.bind.serializer.JsonbDeserializer; -import jakarta.json.stream.JsonParser; - -import org.eclipse.yasson.internal.JsonbParser; -import org.eclipse.yasson.internal.Unmarshaller; -import org.eclipse.yasson.internal.model.customization.Customization; - -/** - * Common type for all supported value type serializers. - * - * @param value type - */ -public abstract class AbstractValueTypeDeserializer implements JsonbDeserializer { - - private final Class clazz; - - private final Customization customization; - - /** - * Creates a new instance. - * - * @param clazz Class to work with. - * @param customization Model customization. - */ - public AbstractValueTypeDeserializer(Class clazz, Customization customization) { - this.clazz = clazz; - this.customization = customization; - } - - /** - * Extracts single string value for conversion. - * - * @param parser Parser to get value from. - * @param ctx Unmarshaller. - * @param rtType return type. - * @return Deserialized object. - */ - @Override - public T deserialize(JsonParser parser, DeserializationContext ctx, Type rtType) { - Unmarshaller unmarshaller = (Unmarshaller) ctx; - final JsonParser.Event event = ((JsonbParser) parser).getCurrentLevel().getLastEvent(); - if (event == JsonParser.Event.VALUE_NULL) { - return null; - } - - final String value = parser.getString(); - return deserialize(value, unmarshaller, rtType); - } - - /** - * Convert string value to object. - * - * @param jsonValue Json value. - * @param unmarshaller Unmarshaller instance. - * @param rtType Runtime type. - * @return Deserialized object. - */ - protected T deserialize(String jsonValue, Unmarshaller unmarshaller, Type rtType) { - throw new UnsupportedOperationException("Operation not supported in " + getClass()); - } - - /** - * Returns customization of object. - * - * @return object customization - */ - public Customization getCustomization() { - return customization; - } - - /** - * Type of a property or creator parameter which is deserialized. - * - * @return property type. - */ - protected Class getPropertyType() { - return clazz; - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/AbstractValueTypeSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/AbstractValueTypeSerializer.java deleted file mode 100644 index 70043a2e2..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/AbstractValueTypeSerializer.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import jakarta.json.bind.serializer.JsonbSerializer; -import jakarta.json.bind.serializer.SerializationContext; -import jakarta.json.stream.JsonGenerator; - -import org.eclipse.yasson.internal.Marshaller; -import org.eclipse.yasson.internal.model.customization.Customization; - -/** - * Common type for all supported type serializers. - * - * @param value type - */ -public abstract class AbstractValueTypeSerializer implements JsonbSerializer { - - private final Customization customization; - - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public AbstractValueTypeSerializer(Customization customization) { - this.customization = customization; - } - - /** - * Serializes an object to JSON. - * - * @param obj Object to serialize. - * @param generator JSON generator to use. - * @param ctx JSON-B mapper context. - */ - @Override - public void serialize(T obj, JsonGenerator generator, SerializationContext ctx) { - Marshaller marshaller = (Marshaller) ctx; - serialize(obj, generator, marshaller); - } - - /** - * Serializes an object to JSON. - * - * @param obj Object to serialize. - * @param generator JSON generator to use. - * @param marshaller Marshaller. - */ - protected abstract void serialize(T obj, JsonGenerator generator, Marshaller marshaller); - - /** - * Returns value type customization. - * - * @return customization - */ - public Customization getCustomization() { - return customization; - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/AdaptedObjectDeserializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/AdaptedObjectDeserializer.java deleted file mode 100644 index 64dc4c900..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/AdaptedObjectDeserializer.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import java.lang.reflect.Type; - -import jakarta.json.bind.JsonbException; -import jakarta.json.bind.adapter.JsonbAdapter; -import jakarta.json.bind.serializer.DeserializationContext; -import jakarta.json.bind.serializer.JsonbDeserializer; -import jakarta.json.stream.JsonParser; - -import org.eclipse.yasson.internal.components.AdapterBinding; -import org.eclipse.yasson.internal.model.ClassModel; -import org.eclipse.yasson.internal.properties.MessageKeys; -import org.eclipse.yasson.internal.properties.Messages; - -/** - * Decorator for an item which builds adapted type instance by a {@link JsonbAdapter}. - * After adapted item is finished building its instance is converted to field type object by calling components. - * - * @param adapted type, type to deserialize JSON into - * @param required type, typically type of the field, which is adapted to another type - */ -public class AdaptedObjectDeserializer implements CurrentItem, JsonbDeserializer { - - private JsonbDeserializer adaptedTypeDeserializer; - - private final AdapterBinding adapterInfo; - - private final AbstractContainerDeserializer wrapperItem; - - /** - * Creates decoration instance wrapping real adapted object item. - * - * @param adapterInfo components type info - * @param wrapperItem wrapper item to get instance from - */ - public AdaptedObjectDeserializer(AdapterBinding adapterInfo, AbstractContainerDeserializer wrapperItem) { - this.adapterInfo = adapterInfo; - this.wrapperItem = wrapperItem; - } - - @Override - public ClassModel getClassModel() { - throw new UnsupportedOperationException(); - } - - @Override - public CurrentItem getWrapper() { - return wrapperItem; - } - - @Override - public Type getRuntimeType() { - if (adaptedTypeDeserializer instanceof AbstractContainerDeserializer) { - return ((AbstractContainerDeserializer) adaptedTypeDeserializer).getRuntimeType(); - } - throw new JsonbException(Messages.getMessage(MessageKeys.INTERNAL_ERROR, - "Deserialization propagation is not allowed for:" + adaptedTypeDeserializer)); - } - - /** - * Sets adapted item. - * - * @param adaptedTypeDeserializer Adapted item to set. - */ - public void setAdaptedTypeDeserializer(JsonbDeserializer adaptedTypeDeserializer) { - this.adaptedTypeDeserializer = adaptedTypeDeserializer; - } - - @Override - @SuppressWarnings("unchecked") - public T deserialize(JsonParser parser, DeserializationContext context, Type rtType) { - try { - final A result = adaptedTypeDeserializer.deserialize(parser, context, rtType); - final T adapted = ((JsonbAdapter) adapterInfo.getAdapter()).adaptFromJson(result); - return adapted; - } catch (Exception e) { - throw new JsonbException(Messages.getMessage(MessageKeys.ADAPTER_EXCEPTION, - adapterInfo.getBindingType(), - adapterInfo.getToType(), - adapterInfo.getAdapter().getClass()), e); - } - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/AdaptedObjectSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/AdaptedObjectSerializer.java deleted file mode 100644 index 27e1fce2c..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/AdaptedObjectSerializer.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import java.lang.reflect.Type; - -import jakarta.json.bind.JsonbException; -import jakarta.json.bind.adapter.JsonbAdapter; -import jakarta.json.bind.serializer.JsonbSerializer; -import jakarta.json.bind.serializer.SerializationContext; -import jakarta.json.stream.JsonGenerator; - -import org.eclipse.yasson.internal.Marshaller; -import org.eclipse.yasson.internal.ProcessingContext; -import org.eclipse.yasson.internal.components.AdapterBinding; -import org.eclipse.yasson.internal.model.ClassModel; -import org.eclipse.yasson.internal.model.JsonbPropertyInfo; -import org.eclipse.yasson.internal.properties.MessageKeys; -import org.eclipse.yasson.internal.properties.Messages; - -/** - * Serializer for adapted object. - * Converts object using components first, than serializes result with standard process. - * - * @param source type - * @param adapted type - */ -public class AdaptedObjectSerializer implements CurrentItem, JsonbSerializer { - - private final ClassModel classModel; - - private final AdapterBinding adapterInfo; - - /** - * Creates AdapterObjectSerializer. - * - * @param classModel Class model. - * @param adapter Adapter. - */ - public AdaptedObjectSerializer(ClassModel classModel, AdapterBinding adapter) { - this.classModel = classModel; - this.adapterInfo = adapter; - } - - @Override - @SuppressWarnings("unchecked") - public void serialize(T obj, JsonGenerator generator, SerializationContext ctx) { - ProcessingContext context = (ProcessingContext) ctx; - try { - if (context.addProcessedObject(obj)) { - final JsonbAdapter adapter = (JsonbAdapter) adapterInfo.getAdapter(); - A adapted = adapter.adaptToJson(obj); - if (adapted == null) { - generator.writeNull(); - return; - } - final JsonbSerializer serializer = resolveSerializer((Marshaller) ctx, adapted); - serializer.serialize(adapted, generator, ctx); - } else { - throw new JsonbException(Messages.getMessage(MessageKeys.RECURSIVE_REFERENCE, obj.getClass())); - } - } catch (Exception e) { - throw new JsonbException(Messages.getMessage(MessageKeys.ADAPTER_EXCEPTION, - adapterInfo.getBindingType(), - adapterInfo.getToType(), - adapterInfo.getAdapter().getClass()), e); - } finally { - context.removeProcessedObject(obj); - } - } - - @SuppressWarnings("unchecked") - private JsonbSerializer resolveSerializer(Marshaller ctx, A adapted) { - final ContainerSerializerProvider cached = ctx.getMappingContext().getSerializerProvider(adapted.getClass()); - if (cached != null) { - return (JsonbSerializer) cached.provideSerializer(new JsonbPropertyInfo() - .withWrapper(this) - .withRuntimeType(classModel == null - ? null - : classModel.getType())); - } - return (JsonbSerializer) new SerializerBuilder(ctx.getJsonbContext()) - .withObjectClass(adapted.getClass()) - .withCustomization(classModel == null ? null : classModel.getClassCustomization()) - .withWrapper(this) - .build(); - } - - @Override - public ClassModel getClassModel() { - return null; - } - - @Override - public CurrentItem getWrapper() { - return null; - } - - @Override - public Type getRuntimeType() { - return null; - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/AdapterSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/AdapterSerializer.java new file mode 100644 index 000000000..582c581d0 --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/serializer/AdapterSerializer.java @@ -0,0 +1,52 @@ +/* + * 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.serializer; + +import jakarta.json.bind.JsonbException; +import jakarta.json.bind.adapter.JsonbAdapter; +import jakarta.json.stream.JsonGenerator; + +import org.eclipse.yasson.internal.SerializationContextImpl; +import org.eclipse.yasson.internal.components.AdapterBinding; +import org.eclipse.yasson.internal.properties.MessageKeys; +import org.eclipse.yasson.internal.properties.Messages; + +/** + * User defined adapter invoker. + */ +class AdapterSerializer extends AbstractSerializer { + + private final JsonbAdapter adapter; + private final AdapterBinding adapterBinding; + + @SuppressWarnings("unchecked") + AdapterSerializer(AdapterBinding adapterBinding, + ModelSerializer delegate) { + super(delegate); + this.adapter = (JsonbAdapter) adapterBinding.getAdapter(); + this.adapterBinding = adapterBinding; + } + + @Override + public void serialize(Object value, JsonGenerator generator, SerializationContextImpl context) { + try { + delegate.serialize(adapter.adaptToJson(value), generator, context); + } catch (Exception e) { + throw new JsonbException(Messages.getMessage(MessageKeys.ADAPTER_EXCEPTION, + adapterBinding.getBindingType(), + adapterBinding.getToType(), + adapter.getClass()), e); + } + } + +} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/ArraySerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/ArraySerializer.java new file mode 100644 index 000000000..f538bc69e --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/serializer/ArraySerializer.java @@ -0,0 +1,248 @@ +/* + * 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.serializer; + +import java.util.Base64; +import java.util.Map; +import java.util.function.Function; + +import jakarta.json.bind.JsonbException; +import jakarta.json.bind.config.BinaryDataStrategy; +import jakarta.json.stream.JsonGenerator; + +import org.eclipse.yasson.internal.JsonbContext; +import org.eclipse.yasson.internal.SerializationContextImpl; +import org.eclipse.yasson.internal.properties.MessageKeys; +import org.eclipse.yasson.internal.properties.Messages; + +/** + * Array container serializer. + */ +abstract class ArraySerializer implements ModelSerializer { + + private static final Map, Function> ARRAY_SERIALIZERS; + + static { + ARRAY_SERIALIZERS = Map.of(boolean[].class, BooleanArraySerializer::new, + byte[].class, ByteArraySerializer::new, + char[].class, CharacterArraySerializer::new, + double[].class, DoubleArraySerializer::new, + float[].class, FloatArraySerializer::new, + int[].class, IntegerArraySerializer::new, + long[].class, LongArraySerializer::new, + short[].class, ShortArraySerializer::new); + } + + private final ModelSerializer valueSerializer; + + protected ArraySerializer(ModelSerializer valueSerializer) { + this.valueSerializer = valueSerializer; + } + + public static ModelSerializer create(Class arrayType, + JsonbContext jsonbContext, + ModelSerializer modelSerializer) { + String binaryDataStrategy = jsonbContext.getConfigProperties().getBinaryDataStrategy(); + if (byte[].class.equals(arrayType) && !binaryDataStrategy.equals(BinaryDataStrategy.BYTE)) { + return new Base64ByteArraySerializer(binaryDataStrategy); + } + if (ARRAY_SERIALIZERS.containsKey(arrayType)) { + return ARRAY_SERIALIZERS.get(arrayType).apply(modelSerializer); + } + return new ObjectArraySerializer(modelSerializer); + } + + @Override + public void serialize(Object value, JsonGenerator generator, SerializationContextImpl context) { + generator.writeStartArray(); + serializeArray(value, generator, context); + generator.writeEnd(); + } + + abstract void serializeArray(Object value, JsonGenerator generator, SerializationContextImpl context); + + protected ModelSerializer getValueSerializer() { + return valueSerializer; + } + + private static final class ByteArraySerializer extends ArraySerializer { + + ByteArraySerializer(ModelSerializer valueSerializer) { + super(valueSerializer); + } + + @Override + public void serializeArray(Object value, JsonGenerator generator, SerializationContextImpl context) { + byte[] array = (byte[]) value; + for (byte b : array) { + getValueSerializer().serialize(b, generator, context); + } + } + + } + + private static final class Base64ByteArraySerializer implements ModelSerializer { + + private final Base64.Encoder encoder; + + Base64ByteArraySerializer(String strategy) { + this.encoder = getEncoder(strategy); + } + + @Override + public void serialize(Object value, JsonGenerator generator, SerializationContextImpl context) { + byte[] array = (byte[]) value; + generator.write(encoder.encodeToString(array)); + } + + private Base64.Encoder getEncoder(String strategy) { + switch (strategy) { + case BinaryDataStrategy.BASE_64: + return Base64.getEncoder(); + case BinaryDataStrategy.BASE_64_URL: + return Base64.getUrlEncoder(); + default: + throw new JsonbException(Messages.getMessage(MessageKeys.INTERNAL_ERROR, "Invalid strategy: " + strategy)); + } + } + } + + private static final class ShortArraySerializer extends ArraySerializer { + + ShortArraySerializer(ModelSerializer valueSerializer) { + super(valueSerializer); + } + + @Override + public void serializeArray(Object value, JsonGenerator generator, SerializationContextImpl context) { + short[] array = (short[]) value; + for (short s : array) { + getValueSerializer().serialize(s, generator, context); + } + } + + } + + private static final class IntegerArraySerializer extends ArraySerializer { + + IntegerArraySerializer(ModelSerializer valueSerializer) { + super(valueSerializer); + } + + @Override + public void serializeArray(Object value, JsonGenerator generator, SerializationContextImpl context) { + int[] array = (int[]) value; + for (int i : array) { + getValueSerializer().serialize(i, generator, context); + } + } + + } + + private static final class LongArraySerializer extends ArraySerializer { + + LongArraySerializer(ModelSerializer valueSerializer) { + super(valueSerializer); + } + + @Override + public void serializeArray(Object value, JsonGenerator generator, SerializationContextImpl context) { + long[] array = (long[]) value; + for (long l : array) { + getValueSerializer().serialize(l, generator, context); + } + } + + } + + private static final class FloatArraySerializer extends ArraySerializer { + + FloatArraySerializer(ModelSerializer valueSerializer) { + super(valueSerializer); + } + + @Override + public void serializeArray(Object value, JsonGenerator generator, SerializationContextImpl context) { + float[] array = (float[]) value; + for (float f : array) { + getValueSerializer().serialize(f, generator, context); + } + } + + } + + private static final class DoubleArraySerializer extends ArraySerializer { + + DoubleArraySerializer(ModelSerializer valueSerializer) { + super(valueSerializer); + } + + @Override + public void serializeArray(Object value, JsonGenerator generator, SerializationContextImpl context) { + double[] array = (double[]) value; + for (double d : array) { + getValueSerializer().serialize(d, generator, context); + } + } + + } + + private static final class BooleanArraySerializer extends ArraySerializer { + + BooleanArraySerializer(ModelSerializer valueSerializer) { + super(valueSerializer); + } + + @Override + public void serializeArray(Object value, JsonGenerator generator, SerializationContextImpl context) { + boolean[] array = (boolean[]) value; + for (boolean b : array) { + getValueSerializer().serialize(b, generator, context); + } + } + + } + + private static final class CharacterArraySerializer extends ArraySerializer { + + CharacterArraySerializer(ModelSerializer valueSerializer) { + super(valueSerializer); + } + + @Override + public void serializeArray(Object value, JsonGenerator generator, SerializationContextImpl context) { + char[] array = (char[]) value; + for (char c : array) { + getValueSerializer().serialize(c, generator, context); + } + } + + } + + private static final class ObjectArraySerializer extends ArraySerializer { + + ObjectArraySerializer(ModelSerializer valueSerializer) { + super(valueSerializer); + } + + @Override + public void serializeArray(Object value, JsonGenerator generator, SerializationContextImpl context) { + Object[] array = (Object[]) value; + for (Object o : array) { + getValueSerializer().serialize(o, generator, context); + } + } + + } + +} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/BigDecimalTypeDeserializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/BigDecimalTypeDeserializer.java deleted file mode 100644 index 993a1b4b4..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/BigDecimalTypeDeserializer.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import java.lang.reflect.Type; -import java.math.BigDecimal; - -import jakarta.json.bind.JsonbException; - -import org.eclipse.yasson.internal.Unmarshaller; -import org.eclipse.yasson.internal.model.customization.Customization; -import org.eclipse.yasson.internal.properties.MessageKeys; -import org.eclipse.yasson.internal.properties.Messages; - -/** - * Deserializer for {@link BigDecimal} type. - */ -public class BigDecimalTypeDeserializer extends AbstractNumberDeserializer { - - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public BigDecimalTypeDeserializer(Customization customization) { - super(BigDecimal.class, customization); - } - - @Override - public BigDecimal deserialize(String jsonValue, Unmarshaller unmarshaller, Type rtType) { - return deserializeFormatted(jsonValue, false, unmarshaller.getJsonbContext()) - .map(num -> new BigDecimal(num.toString())) - .orElseGet(() -> { - try { - return new BigDecimal(jsonValue); - } catch (NumberFormatException e) { - throw new JsonbException(Messages.getMessage(MessageKeys.DESERIALIZE_VALUE_ERROR, - BigDecimal.class)); - } - }); - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/BigDecimalTypeSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/BigDecimalTypeSerializer.java deleted file mode 100644 index 465bbe13c..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/BigDecimalTypeSerializer.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import java.math.BigDecimal; - -import jakarta.json.stream.JsonGenerator; - -import org.eclipse.yasson.internal.model.customization.Customization; - -/** - * Serializer for {@link BigDecimal} type. - */ -public class BigDecimalTypeSerializer extends AbstractNumberSerializer { - - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public BigDecimalTypeSerializer(Customization customization) { - super(customization); - } - - @Override - protected void serializeNonFormatted(BigDecimal obj, JsonGenerator generator, String key) { - generator.write(key, obj); - } - - @Override - protected void serializeNonFormatted(BigDecimal obj, JsonGenerator generator) { - generator.write(obj); - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/BigIntegerTypeDeserializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/BigIntegerTypeDeserializer.java deleted file mode 100644 index b6a302772..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/BigIntegerTypeDeserializer.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import java.lang.reflect.Type; -import java.math.BigInteger; - -import jakarta.json.bind.JsonbException; - -import org.eclipse.yasson.internal.Unmarshaller; -import org.eclipse.yasson.internal.model.customization.Customization; -import org.eclipse.yasson.internal.properties.MessageKeys; -import org.eclipse.yasson.internal.properties.Messages; - -/** - * Deserializer for {@link BigInteger} type. - */ -public class BigIntegerTypeDeserializer extends AbstractNumberDeserializer { - - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public BigIntegerTypeDeserializer(Customization customization) { - super(BigInteger.class, customization); - } - - @Override - public BigInteger deserialize(String jsonValue, Unmarshaller unmarshaller, Type rtType) { - return deserializeFormatted(jsonValue, true, unmarshaller.getJsonbContext()) - .map(num -> new BigInteger(num.toString())) - .orElseGet(() -> { - try { - return new BigInteger(jsonValue); - } catch (NumberFormatException e) { - throw new JsonbException(Messages.getMessage(MessageKeys.DESERIALIZE_VALUE_ERROR, - BigInteger.class)); - } - }); - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/BigIntegerTypeSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/BigIntegerTypeSerializer.java deleted file mode 100644 index 700faf4f1..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/BigIntegerTypeSerializer.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import java.math.BigInteger; - -import jakarta.json.stream.JsonGenerator; - -import org.eclipse.yasson.internal.model.customization.Customization; - -/** - * Serializer for {@link BigInteger} type. - */ -public class BigIntegerTypeSerializer extends AbstractNumberSerializer { - - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public BigIntegerTypeSerializer(Customization customization) { - super(customization); - } - - @Override - protected void serializeNonFormatted(BigInteger obj, JsonGenerator generator, String key) { - generator.write(key, obj); - } - - @Override - protected void serializeNonFormatted(BigInteger obj, JsonGenerator generator) { - generator.write(obj); - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/BooleanArrayDeserializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/BooleanArrayDeserializer.java deleted file mode 100644 index 3ad774ea7..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/BooleanArrayDeserializer.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import java.util.ArrayList; -import java.util.List; - -import org.eclipse.yasson.internal.Unmarshaller; - -/** - * Array unmarshaller item implementation for booleans. - */ -public class BooleanArrayDeserializer extends AbstractArrayDeserializer { - - private final List items = new ArrayList<>(); - - /** - * Creates new instance of boolean array deserializer. - * - * @param builder deserializer builder - */ - protected BooleanArrayDeserializer(DeserializerBuilder builder) { - super(builder); - } - - @Override - protected List getItems() { - return items; - } - - @Override - public boolean[] getInstance(Unmarshaller unmarshaller) { - final int size = items.size(); - final boolean[] byteArray = new boolean[size]; - for (int i = 0; i < size; i++) { - byteArray[i] = items.get(i); - } - return byteArray; - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/BooleanArraySerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/BooleanArraySerializer.java deleted file mode 100644 index aadb00c74..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/BooleanArraySerializer.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import jakarta.json.bind.serializer.SerializationContext; -import jakarta.json.stream.JsonGenerator; - -/** - * Serializes byte array as JSON array of booleans. - */ -public class BooleanArraySerializer extends AbstractArraySerializer { - - /** - * Creates new instance of boolean array serializer. - * - * @param builder serializer builder - */ - protected BooleanArraySerializer(SerializerBuilder builder) { - super(builder); - } - - @Override - protected void serializeInternal(boolean[] obj, JsonGenerator generator, SerializationContext ctx) { - for (boolean b : obj) { - generator.write(b); - } - } - -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/BooleanTypeDeserializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/BooleanTypeDeserializer.java deleted file mode 100644 index cf91a861d..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/BooleanTypeDeserializer.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import java.lang.reflect.Type; - -import jakarta.json.bind.JsonbException; -import jakarta.json.bind.serializer.DeserializationContext; -import jakarta.json.stream.JsonParser; - -import org.eclipse.yasson.internal.JsonbParser; -import org.eclipse.yasson.internal.model.customization.Customization; -import org.eclipse.yasson.internal.properties.MessageKeys; -import org.eclipse.yasson.internal.properties.Messages; - -/** - * Deserializer for {@link Boolean} type. - */ -public class BooleanTypeDeserializer extends AbstractValueTypeDeserializer { - - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public BooleanTypeDeserializer(Customization customization) { - super(Boolean.class, customization); - } - - @Override - public Boolean deserialize(JsonParser parser, DeserializationContext ctx, Type rtType) { - JsonParser.Event event = ((JsonbParser) parser).moveToValue(); - switch (event) { - case VALUE_TRUE: - return Boolean.TRUE; - case VALUE_FALSE: - return Boolean.FALSE; - case VALUE_STRING: - return Boolean.parseBoolean(parser.getString()); - default: - throw new JsonbException(Messages.getMessage(MessageKeys.INTERNAL_ERROR, "Unknown JSON value: " + event)); - } - } - -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/BooleanTypeSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/BooleanTypeSerializer.java deleted file mode 100644 index 7f2da9a83..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/BooleanTypeSerializer.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import jakarta.json.stream.JsonGenerator; - -import org.eclipse.yasson.internal.Marshaller; -import org.eclipse.yasson.internal.model.customization.Customization; - -/** - * Serializer for {@link Boolean} type. - */ -public class BooleanTypeSerializer extends AbstractValueTypeSerializer { - - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public BooleanTypeSerializer(Customization customization) { - super(customization); - } - - @Override - protected void serialize(Boolean obj, JsonGenerator generator, Marshaller marshaller) { - generator.write(obj); - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/ByteArrayBase64Deserializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/ByteArrayBase64Deserializer.java deleted file mode 100644 index 5fc5aa94b..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/ByteArrayBase64Deserializer.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import java.lang.reflect.Type; -import java.util.Base64; - -import jakarta.json.bind.JsonbException; -import jakarta.json.bind.config.BinaryDataStrategy; - -import org.eclipse.yasson.internal.Unmarshaller; -import org.eclipse.yasson.internal.model.customization.Customization; -import org.eclipse.yasson.internal.properties.MessageKeys; -import org.eclipse.yasson.internal.properties.Messages; - -/** - * Deserialize Base64 json string value into byte array. - */ -public class ByteArrayBase64Deserializer extends AbstractValueTypeDeserializer { - - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public ByteArrayBase64Deserializer(Customization customization) { - super(byte[].class, customization); - } - - @Override - protected byte[] deserialize(String jsonValue, Unmarshaller unmarshaller, Type rtType) { - return getDecoder(unmarshaller.getJsonbContext().getConfigProperties().getBinaryDataStrategy()).decode(jsonValue); - } - - private Base64.Decoder getDecoder(String strategy) { - switch (strategy) { - case BinaryDataStrategy.BASE_64: - return Base64.getDecoder(); - case BinaryDataStrategy.BASE_64_URL: - return Base64.getUrlDecoder(); - default: - throw new JsonbException(Messages.getMessage(MessageKeys.INTERNAL_ERROR, "Invalid strategy: " + strategy)); - } - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/ByteArrayBase64Serializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/ByteArrayBase64Serializer.java deleted file mode 100644 index 8f3ae6d57..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/ByteArrayBase64Serializer.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import java.util.Base64; - -import jakarta.json.bind.JsonbException; -import jakarta.json.bind.config.BinaryDataStrategy; -import jakarta.json.stream.JsonGenerator; - -import org.eclipse.yasson.internal.Marshaller; -import org.eclipse.yasson.internal.model.customization.Customization; -import org.eclipse.yasson.internal.properties.MessageKeys; -import org.eclipse.yasson.internal.properties.Messages; - -/** - * Serializes byte array with Base64. - */ -public class ByteArrayBase64Serializer extends AbstractValueTypeSerializer { - - /** - * Creates a new instance. - * - * @param customization Customization model. - */ - public ByteArrayBase64Serializer(Customization customization) { - super(customization); - } - - @Override - protected void serialize(byte[] obj, JsonGenerator generator, Marshaller marshaller) { - generator.write(getEncoder(marshaller.getJsonbContext().getConfigProperties().getBinaryDataStrategy()) - .encodeToString(obj)); - } - - private Base64.Encoder getEncoder(String strategy) { - switch (strategy) { - case BinaryDataStrategy.BASE_64: - return Base64.getEncoder(); - case BinaryDataStrategy.BASE_64_URL: - return Base64.getUrlEncoder(); - default: - throw new JsonbException(Messages.getMessage(MessageKeys.INTERNAL_ERROR, - "Invalid strategy: " + strategy)); - } - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/ByteArrayDeserializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/ByteArrayDeserializer.java deleted file mode 100644 index 038c18531..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/ByteArrayDeserializer.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import java.util.ArrayList; -import java.util.List; - -import org.eclipse.yasson.internal.Unmarshaller; - -/** - * Array unmarshaller item implementation for small int. - */ -public class ByteArrayDeserializer extends AbstractArrayDeserializer { - - private final List items = new ArrayList<>(); - - /** - * Creates new instance of byte array deserializer. - * - * @param builder deserializer builder - */ - protected ByteArrayDeserializer(DeserializerBuilder builder) { - super(builder); - } - - @Override - protected List getItems() { - return items; - } - - @Override - public byte[] getInstance(Unmarshaller unmarshaller) { - final int size = items.size(); - final byte[] byteArray = new byte[size]; - for (int i = 0; i < size; i++) { - byteArray[i] = items.get(i); - } - return byteArray; - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/ByteArraySerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/ByteArraySerializer.java deleted file mode 100644 index 79e0a047a..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/ByteArraySerializer.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import jakarta.json.bind.serializer.SerializationContext; -import jakarta.json.stream.JsonGenerator; - -/** - * Serializes byte array as JSON array of ints. - */ -public class ByteArraySerializer extends AbstractArraySerializer { - - /** - * Creates new instance of byte array serializer. - * - * @param builder serializer builder - */ - protected ByteArraySerializer(SerializerBuilder builder) { - super(builder); - } - - @Override - protected void serializeInternal(byte[] obj, JsonGenerator generator, SerializationContext ctx) { - for (byte b : obj) { - generator.write(b); - } - } - -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/ByteTypeDeserializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/ByteTypeDeserializer.java deleted file mode 100644 index c00ac6790..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/ByteTypeDeserializer.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import java.lang.reflect.Type; - -import jakarta.json.bind.JsonbException; - -import org.eclipse.yasson.internal.Unmarshaller; -import org.eclipse.yasson.internal.model.customization.Customization; -import org.eclipse.yasson.internal.properties.MessageKeys; -import org.eclipse.yasson.internal.properties.Messages; - -/** - * Serializer for {@link Byte} type. - */ -public class ByteTypeDeserializer extends AbstractNumberDeserializer { - - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public ByteTypeDeserializer(Customization customization) { - super(Byte.class, customization); - } - - @Override - protected Byte deserialize(String value, Unmarshaller unmarshaller, Type rtType) { - return deserializeFormatted(value, true, unmarshaller.getJsonbContext()) - .map(num -> Byte.parseByte(num.toString())) - .orElseGet(() -> { - try { - return Byte.parseByte(value); - } catch (NumberFormatException e) { - throw new JsonbException(Messages.getMessage(MessageKeys.DESERIALIZE_VALUE_ERROR, Byte.class)); - } - }); - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/ByteTypeSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/ByteTypeSerializer.java deleted file mode 100644 index 22738fd60..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/ByteTypeSerializer.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import jakarta.json.stream.JsonGenerator; - -import org.eclipse.yasson.internal.model.customization.Customization; - -/** - * Serializer for {@link Byte} type. - */ -public class ByteTypeSerializer extends AbstractNumberSerializer { - - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public ByteTypeSerializer(Customization customization) { - super(customization); - } - - @Override - protected void serializeNonFormatted(Byte obj, JsonGenerator generator, String key) { - generator.write(key, obj); - } - - @Override - protected void serializeNonFormatted(Byte obj, JsonGenerator generator) { - generator.write(obj); - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/CharArrayDeserializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/CharArrayDeserializer.java deleted file mode 100644 index 66f1d6b28..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/CharArrayDeserializer.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2019, 2020 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.serializer; - -import java.util.ArrayList; -import java.util.List; - -import org.eclipse.yasson.internal.Unmarshaller; - -/** - * Array unmarshaller item implementation for char. - */ -public class CharArrayDeserializer extends AbstractArrayDeserializer { - - private final List items = new ArrayList<>(); - - /** - * Creates new instance of char array deserializer. - * - * @param builder deserializer builder - */ - protected CharArrayDeserializer(DeserializerBuilder builder) { - super(builder); - } - - @Override - protected List getItems() { - return items; - } - - @Override - public char[] getInstance(Unmarshaller unmarshaller) { - final int size = items.size(); - final char[] charArray = new char[size]; - for (int i = 0; i < size; i++) { - charArray[i] = items.get(i); - } - return charArray; - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/CharArraySerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/CharArraySerializer.java deleted file mode 100644 index 42997644c..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/CharArraySerializer.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2019, 2020 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.serializer; - -import jakarta.json.bind.serializer.SerializationContext; -import jakarta.json.stream.JsonGenerator; - -/** - * Serializes byte array as JSON array of ints. - */ -public class CharArraySerializer extends AbstractArraySerializer { - - /** - * Creates new instance of char array serializer. - * - * @param builder serializer builder - */ - protected CharArraySerializer(SerializerBuilder builder) { - super(builder); - } - - @Override - protected void serializeInternal(char[] obj, JsonGenerator generator, SerializationContext ctx) { - for (char c : obj) { - generator.write(Character.valueOf(c).toString()); - } - } - -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/CharacterTypeDeserializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/CharacterTypeDeserializer.java deleted file mode 100644 index c8f70c8ca..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/CharacterTypeDeserializer.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import java.lang.reflect.Type; - -import org.eclipse.yasson.internal.Unmarshaller; -import org.eclipse.yasson.internal.model.customization.Customization; - -/** - * Deserializer for {@link Character} type. - */ -public class CharacterTypeDeserializer extends AbstractValueTypeDeserializer { - - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public CharacterTypeDeserializer(Customization customization) { - super(Character.class, customization); - } - - @Override - protected Character deserialize(String value, Unmarshaller unmarshaller, Type rtType) { - return value.charAt(0); - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/CharacterTypeSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/CharacterTypeSerializer.java deleted file mode 100644 index 0838fc5ed..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/CharacterTypeSerializer.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import jakarta.json.stream.JsonGenerator; - -import org.eclipse.yasson.internal.Marshaller; -import org.eclipse.yasson.internal.model.customization.Customization; - -/** - * Serializer for {@link Character} type. - */ -public class CharacterTypeSerializer extends AbstractValueTypeSerializer { - - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public CharacterTypeSerializer(Customization customization) { - super(customization); - } - - @Override - protected void serialize(Character obj, JsonGenerator generator, Marshaller marshaller) { - generator.write(String.valueOf(obj)); - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/CollectionDeserializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/CollectionDeserializer.java deleted file mode 100644 index aad837fad..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/CollectionDeserializer.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (c) 2015, 2021 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.serializer; - -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; -import java.util.ArrayDeque; -import java.util.ArrayList; -import java.util.Collection; -import java.util.EnumSet; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Queue; -import java.util.Set; -import java.util.SortedSet; -import java.util.TreeSet; - -import jakarta.json.bind.serializer.JsonbDeserializer; -import jakarta.json.stream.JsonParser; - -import org.eclipse.yasson.internal.JsonbParser; -import org.eclipse.yasson.internal.JsonbRiParser; -import org.eclipse.yasson.internal.ReflectionUtils; -import org.eclipse.yasson.internal.Unmarshaller; - -/** - * Item implementation for {@link java.util.List} fields. - */ -class CollectionDeserializer> extends AbstractContainerDeserializer implements EmbeddedItem { - - /** - * Generic bound parameter of List. - */ - private final Type collectionValueType; - - private T instance; - - /** - * @param builder {@link DeserializerBuilder) used to build this instance - */ - protected CollectionDeserializer(DeserializerBuilder builder) { - super(builder); - collectionValueType = getRuntimeType() instanceof ParameterizedType - ? ReflectionUtils.resolveType(this, ((ParameterizedType) getRuntimeType()).getActualTypeArguments()[0]) - : Object.class; - - instance = createInstance(builder); - } - - @SuppressWarnings("unchecked") - private T createInstance(DeserializerBuilder builder) { - Class rawType = (Class) ReflectionUtils.getRawType(getRuntimeType()); - - if (rawType.isInterface()) { - final T x = createInterfaceInstance(rawType); - if (x != null) { - return x; - } - } else if (EnumSet.class.isAssignableFrom(rawType)) { - return (T) EnumSet.noneOf((Class) collectionValueType); - } - return builder.getJsonbContext().getInstanceCreator().createInstance(rawType); - } - - @SuppressWarnings("unchecked") - private T createInterfaceInstance(Class ifcType) { - if (List.class.isAssignableFrom(ifcType)) { - if (LinkedList.class == ifcType) { - return (T) new LinkedList(); - } - return (T) new ArrayList<>(); - } - if (Set.class.isAssignableFrom(ifcType)) { - if (SortedSet.class.isAssignableFrom(ifcType)) { - return (T) new TreeSet<>(); - } - return (T) new HashSet<>(); - } - if (Queue.class.isAssignableFrom(ifcType)) { - return (T) new ArrayDeque<>(); - } - if (Collection.class == ifcType) { - return (T) new ArrayList(); - } - return null; - } - - @Override - public T getInstance(Unmarshaller unmarshaller) { - return instance; - } - - @Override - public void appendResult(Object result, Unmarshaller context) { - appendCaptor(convertNullToOptionalEmpty(collectionValueType, result)); - } - - @SuppressWarnings("unchecked") - private void appendCaptor(T object) { - ((Collection) instance).add(object); - } - - @Override - protected void deserializeNext(JsonParser parser, Unmarshaller context) { - final JsonbDeserializer deserializer = newCollectionOrMapItem(collectionValueType, context.getJsonbContext()); - appendResult(deserializer.deserialize(parser, context, collectionValueType), context); - } - - @Override - protected JsonbRiParser.LevelContext moveToFirst(JsonbParser parser) { - parser.moveTo(JsonParser.Event.START_ARRAY); - return parser.getCurrentLevel(); - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/CollectionSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/CollectionSerializer.java index ebcf76575..2fa904af9 100644 --- a/src/main/java/org/eclipse/yasson/internal/serializer/CollectionSerializer.java +++ b/src/main/java/org/eclipse/yasson/internal/serializer/CollectionSerializer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2020 Oracle and/or its affiliates. All rights reserved. + * 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 @@ -14,39 +14,28 @@ import java.util.Collection; -import jakarta.json.bind.serializer.SerializationContext; import jakarta.json.stream.JsonGenerator; +import org.eclipse.yasson.internal.SerializationContextImpl; + /** - * Serializer for collections. - * - * @param type of {@code Collection} value + * Collection container serializer. */ -public class CollectionSerializer extends AbstractContainerSerializer> implements EmbeddedItem { - - /** - * Creates new collection serializer. - * - * @param builder serializer builder - */ - protected CollectionSerializer(SerializerBuilder builder) { - super(builder); - } +class CollectionSerializer implements ModelSerializer { - @Override - protected void serializeInternal(Collection collection, JsonGenerator generator, SerializationContext ctx) { - for (Object item : collection) { - serializeItem(item, generator, ctx); - } + private final ModelSerializer delegate; + + CollectionSerializer(ModelSerializer delegate) { + this.delegate = delegate; } + @SuppressWarnings("unchecked") @Override - protected void writeStart(JsonGenerator generator) { + public void serialize(Object value, JsonGenerator generator, SerializationContextImpl context) { + Collection collection = (Collection) value; generator.writeStartArray(); + collection.forEach(object -> delegate.serialize(object, generator, context)); + generator.writeEnd(); } - @Override - protected void writeStart(String key, JsonGenerator generator) { - generator.writeStartArray(key); - } } diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/ContainerDeserializerUtils.java b/src/main/java/org/eclipse/yasson/internal/serializer/ContainerDeserializerUtils.java deleted file mode 100644 index a55c2a954..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/ContainerDeserializerUtils.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (c) 2019, 2020 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.serializer; - -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; -import java.util.HashMap; -import java.util.Map; -import java.util.SortedMap; -import java.util.TreeMap; - -import jakarta.json.bind.serializer.JsonbDeserializer; -import jakarta.json.stream.JsonParser; - -import org.eclipse.yasson.internal.JsonbContext; -import org.eclipse.yasson.internal.ReflectionUtils; -import org.eclipse.yasson.internal.RuntimeTypeInfo; -import org.eclipse.yasson.internal.model.ClassModel; - -/** - * Internal container de-serializing interface. - * - * @param container type - */ -class ContainerDeserializerUtils { - - private ContainerDeserializerUtils() { - throw new IllegalStateException("Util classes cannot be instantiated!"); - } - - /** - * Resolve {@code Map} key type. - * - * @param item item containing wrapper class of a type field, shall not be {@code null} - * @param mapType type to resolve, typically field type or generic bound, shall not be {@code null} - * @return resolved {@code Map} key type - */ - public static Type mapKeyType(RuntimeTypeInfo item, Type mapType) { - return mapType instanceof ParameterizedType - ? ReflectionUtils.resolveType(item, ((ParameterizedType) mapType).getActualTypeArguments()[0]) - : Object.class; - } - - /** - * Resolve {@code Map} value type. - * - * @param item item containing wrapper class of a type field, shall not be {@code null} - * @param mapType type to resolve, typically field type or generic bound, shall not be {@code null} - * @return resolved {@code Map} value type - */ - public static Type mapValueType(RuntimeTypeInfo item, Type mapType) { - return mapType instanceof ParameterizedType - ? ReflectionUtils.resolveType(item, ((ParameterizedType) mapType).getActualTypeArguments()[1]) - : Object.class; - } - - /** - * Creates an instance of {@code Map} being de-serialized. - * - * @param type of {@code Map} instance to be returned - * @param builder de-serializer builder - * @param mapType type of returned {@code Map} instance - * @return created {@code Map} instance - */ - @SuppressWarnings("unchecked") - public static > T createMapInstance(DeserializerBuilder builder, Type mapType) { - Class rawType = ReflectionUtils.getRawType(mapType); - if (rawType.isInterface()) { - if (SortedMap.class.isAssignableFrom(rawType)) { - Class defaultMapImplType = builder.getJsonbContext().getConfigProperties().getDefaultMapImplType(); - return SortedMap.class.isAssignableFrom(defaultMapImplType) - ? (T) builder.getJsonbContext().getInstanceCreator().createInstance(defaultMapImplType) - : (T) new TreeMap<>(); - } else { - return (T) new HashMap<>(); - } - } else { - return (T) builder.getJsonbContext().getInstanceCreator().createInstance(rawType); - } - } - - /** - * Builds new de-serializer for {@code Collection} or {@code Map} item (key or value). - * - * @param wrapper item wrapper. {@code Collection} or {@code Map} instance. - * @param valueType type of deserialized value - * @param ctx JSON-B parser context - * @param event JSON parser event - * @return de-serializer for {@code Collection} or {@code Map} item - */ - public static JsonbDeserializer newCollectionOrMapItem(CurrentItem wrapper, - Type valueType, - JsonbContext ctx, - JsonParser.Event event) { - //TODO needs performance optimization on not to create deserializer each time - //TODO In contrast to serialization value type cannot change here - Type actualValueType = ReflectionUtils.resolveType(wrapper, valueType); - DeserializerBuilder deserializerBuilder = newUnmarshallerItemBuilder(wrapper, ctx, event).withType(actualValueType); - if (!DefaultSerializers.isKnownType(ReflectionUtils.getRawType(actualValueType))) { - ClassModel classModel = ctx.getMappingContext().getOrCreateClassModel(ReflectionUtils.getRawType(actualValueType)); - deserializerBuilder.withCustomization(classModel == null ? null : classModel.getClassCustomization()); - } - return deserializerBuilder.build(); - } - - /** - * Creates new instance of {@code DeserializerBuilder}. - * - * @param wrapper item wrapper. {@code Collection} or {@code Map} instance. - * @param ctx JSON-P parser context - * @param event JSON parser event - * @return new instance of {@code DeserializerBuilder} - */ - public static DeserializerBuilder newUnmarshallerItemBuilder(CurrentItem wrapper, - JsonbContext ctx, - JsonParser.Event event) { - return new DeserializerBuilder(ctx).withWrapper(wrapper).withJsonValueType(event); - } - -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/ContainerSerializerProvider.java b/src/main/java/org/eclipse/yasson/internal/serializer/ContainerSerializerProvider.java deleted file mode 100644 index 0a309373c..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/ContainerSerializerProvider.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import jakarta.json.bind.serializer.JsonbSerializer; - -import org.eclipse.yasson.internal.model.JsonbPropertyInfo; - -/** - * Provides container serializer instance. - */ -public interface ContainerSerializerProvider { - - /** - * Provides container serializer instance for given property. - * - * @param propertyInfo Property to create serializer for. - * @return Serializer instance. - */ - JsonbSerializer provideSerializer(JsonbPropertyInfo propertyInfo); -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/CurrentItem.java b/src/main/java/org/eclipse/yasson/internal/serializer/CurrentItem.java deleted file mode 100644 index 5e452fe9d..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/CurrentItem.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import org.eclipse.yasson.internal.RuntimeTypeInfo; -import org.eclipse.yasson.internal.model.ClassModel; - -/** - * Currently processing item. - * - * @param item type - */ -public interface CurrentItem extends RuntimeTypeInfo { - - /** - * Class model containing property for this item. - * - * @return Class model. - */ - ClassModel getClassModel(); - - /** - * Item wrapper. Null only in case of a root item. - * - * @return Wrapper item of this item. - */ - CurrentItem getWrapper(); - -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/CyclicReferenceSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/CyclicReferenceSerializer.java new file mode 100644 index 000000000..910225662 --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/serializer/CyclicReferenceSerializer.java @@ -0,0 +1,41 @@ +/* + * 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.serializer; + +import java.lang.reflect.Type; + +import jakarta.json.stream.JsonGenerator; + +import org.eclipse.yasson.internal.SerializationContextImpl; + +/** + * Solution for cyclic references in serialization. + * This approach helps us to avoid creation of multiple serializers for the same type. + */ +class CyclicReferenceSerializer implements ModelSerializer { + + private final Type type; + private ModelSerializer delegate; + + CyclicReferenceSerializer(Type type) { + this.type = type; + } + + @Override + public void serialize(Object value, JsonGenerator generator, SerializationContextImpl context) { + if (delegate == null) { + delegate = context.getJsonbContext().getSerializationModelCreator().serializerChain(type, true, true); + } + delegate.serialize(value, generator, context); + } +} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/DateTypeDeserializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/DateTypeDeserializer.java deleted file mode 100644 index 113415a0d..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/DateTypeDeserializer.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import java.time.Instant; -import java.time.ZoneId; -import java.time.ZonedDateTime; -import java.time.format.DateTimeFormatter; -import java.time.format.DateTimeParseException; -import java.time.temporal.TemporalAccessor; -import java.util.Date; -import java.util.Locale; - -import org.eclipse.yasson.internal.model.customization.Customization; - -/** - * Deserializer for {@link Date} type. - */ -public class DateTypeDeserializer extends AbstractDateTimeDeserializer { - - private static final DateTimeFormatter DEFAULT_DATE_TIME_FORMATTER = DateTimeFormatter.ISO_DATE_TIME; - - /** - * Creates an instance. - * - * @param customization Model customization. - */ - public DateTypeDeserializer(Customization customization) { - super(Date.class, customization); - } - - @Override - protected Date fromInstant(Instant instant) { - return new Date(instant.toEpochMilli()); - } - - @Override - protected Date parseDefault(String jsonValue, Locale locale) { - TemporalAccessor parsed = parseWithOrWithoutZone(jsonValue, DEFAULT_DATE_TIME_FORMATTER.withLocale(locale), UTC); - - return new Date(Instant.from(parsed).toEpochMilli()); - } - - @Override - protected Date parseWithFormatter(String jsonValue, DateTimeFormatter formatter) { - TemporalAccessor parsed = parseWithOrWithoutZone(jsonValue, formatter, UTC); - - return new Date(Instant.from(parsed).toEpochMilli()); - } - - /** - * Parses the jsonValue as a java.time.ZonedDateTime that can later be use to be converted into a java.util.Date.
- * At first the Json-Date is parsed with an Offset/Zone.
- * If no Offset/Zone is present and the parsing fails, it will be parsed again with the fixed Zone that was passed as - * defaultZone. - * - * @param jsonValue String value from json - * @param formatter DateTimeFormat options - * @param defaultZone This Zone will be used if no other Zone was found in the jsonValue - * @return Parsed date on base of a java.time.ZonedDateTime - */ - private static TemporalAccessor parseWithOrWithoutZone(String jsonValue, DateTimeFormatter formatter, ZoneId defaultZone) { - try { - // Try parsing with a Zone - return ZonedDateTime.parse(jsonValue, formatter); - } catch (DateTimeParseException e) { - // Possibly exception occures because no Offset/ZoneId was found - // Therefore parse with defaultZone again - return ZonedDateTime.parse(jsonValue, formatter.withZone(defaultZone)); - } - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/DefaultSerializers.java b/src/main/java/org/eclipse/yasson/internal/serializer/DefaultSerializers.java deleted file mode 100644 index 5d08e79e0..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/DefaultSerializers.java +++ /dev/null @@ -1,219 +0,0 @@ -/* - * Copyright (c) 2016, 2021 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.serializer; - -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.MonthDay; -import java.time.OffsetDateTime; -import java.time.OffsetTime; -import java.time.Period; -import java.time.YearMonth; -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.GregorianCalendar; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; -import java.util.OptionalDouble; -import java.util.OptionalInt; -import java.util.OptionalLong; -import java.util.TimeZone; -import java.util.UUID; - -import jakarta.json.JsonArray; -import jakarta.json.JsonNumber; -import jakarta.json.JsonObject; -import jakarta.json.JsonString; -import jakarta.json.JsonValue; - -import javax.xml.datatype.XMLGregorianCalendar; - -/** - * Cache of default serializers. - */ -public class DefaultSerializers { - - private static final Map, SerializerProviderWrapper> SERIALIZERS = initSerializers(); - - private static final SerializerProviderWrapper ENUM_PROVIDER = new SerializerProviderWrapper(EnumTypeSerializer::new, EnumTypeDeserializer::new); - - private DefaultSerializers() { - } - - private static Map, SerializerProviderWrapper> initSerializers() { - final Map, SerializerProviderWrapper> serializers = new HashMap<>(); - - serializers.put(Boolean.class, new SerializerProviderWrapper(BooleanTypeSerializer::new, BooleanTypeDeserializer::new)); - serializers.put(Boolean.TYPE, new SerializerProviderWrapper(BooleanTypeSerializer::new, BooleanTypeDeserializer::new)); - serializers.put(Byte.class, new SerializerProviderWrapper(ByteTypeSerializer::new, ByteTypeDeserializer::new)); - serializers.put(Byte.TYPE, new SerializerProviderWrapper(ByteTypeSerializer::new, ByteTypeDeserializer::new)); - serializers - .put(Calendar.class, new SerializerProviderWrapper(CalendarTypeSerializer::new, CalendarTypeDeserializer::new)); - serializers.put(GregorianCalendar.class, - new SerializerProviderWrapper(CalendarTypeSerializer::new, CalendarTypeDeserializer::new)); - serializers.put(Character.class, - new SerializerProviderWrapper(CharacterTypeSerializer::new, CharacterTypeDeserializer::new)); - serializers - .put(Character.TYPE, new SerializerProviderWrapper(CharacterTypeSerializer::new, CharacterTypeDeserializer::new)); - - if (isClassAvailable("java.sql.Date")) { - serializers.put(Date.class, new SerializerProviderWrapper(SqlDateTypeSerializer::new, DateTypeDeserializer::new)); - serializers.put(java.sql.Date.class, - new SerializerProviderWrapper(SqlDateTypeSerializer::new, SqlDateTypeDeserializer::new)); - serializers.put(java.sql.Timestamp.class, - new SerializerProviderWrapper(SqlTimestampTypeSerializer::new, SqlTimestampTypeDeserializer::new)); - } else { - serializers.put(Date.class, new SerializerProviderWrapper(DateTypeSerializer::new, DateTypeDeserializer::new)); - } - - serializers.put(Double.class, new SerializerProviderWrapper(DoubleTypeSerializer::new, DoubleTypeDeserializer::new)); - serializers.put(Double.TYPE, new SerializerProviderWrapper(DoubleTypeSerializer::new, DoubleTypeDeserializer::new)); - serializers.put(Float.class, new SerializerProviderWrapper(FloatTypeSerializer::new, FloatTypeDeserializer::new)); - serializers.put(Float.TYPE, new SerializerProviderWrapper(FloatTypeSerializer::new, FloatTypeDeserializer::new)); - serializers.put(Instant.class, new SerializerProviderWrapper(InstantTypeSerializer::new, InstantTypeDeserializer::new)); - serializers.put(Integer.class, new SerializerProviderWrapper(IntegerTypeSerializer::new, IntegerTypeDeserializer::new)); - serializers.put(Integer.TYPE, new SerializerProviderWrapper(IntegerTypeSerializer::new, IntegerTypeDeserializer::new)); - serializers - .put(JsonNumber.class, new SerializerProviderWrapper(JsonValueSerializer::new, JsonNumberTypeDeserializer::new)); - serializers - .put(JsonString.class, new SerializerProviderWrapper(JsonValueSerializer::new, JsonStringTypeDeserializer::new)); - serializers.put(JsonValue.class, new SerializerProviderWrapper(JsonValueSerializer::new, JsonValueDeserializer::new)); - serializers.put(LocalDateTime.class, - new SerializerProviderWrapper(LocalDateTimeTypeSerializer::new, LocalDateTimeTypeDeserializer::new)); - serializers.put(LocalDate.class, - new SerializerProviderWrapper(LocalDateTypeSerializer::new, LocalDateTypeDeserializer::new)); - serializers.put(LocalTime.class, - new SerializerProviderWrapper(LocalTimeTypeSerializer::new, LocalTimeTypeDeserializer::new)); - serializers.put(Long.class, new SerializerProviderWrapper(LongTypeSerializer::new, LongTypeDeserializer::new)); - serializers.put(Long.TYPE, new SerializerProviderWrapper(LongTypeSerializer::new, LongTypeDeserializer::new)); - serializers.put(Number.class, new SerializerProviderWrapper(NumberTypeSerializer::new, NumberTypeDeserializer::new)); - serializers.put(OffsetDateTime.class, - new SerializerProviderWrapper(OffsetDateTimeTypeSerializer::new, OffsetDateTimeTypeDeserializer::new)); - serializers.put(OffsetTime.class, - new SerializerProviderWrapper(OffsetTimeTypeSerializer::new, OffsetTimeTypeDeserializer::new)); - serializers.put(OptionalDouble.class, - new SerializerProviderWrapper(OptionalDoubleTypeSerializer::new, OptionalDoubleTypeDeserializer::new)); - serializers.put(OptionalInt.class, - new SerializerProviderWrapper(OptionalIntTypeSerializer::new, OptionalIntTypeDeserializer::new)); - serializers.put(OptionalLong.class, - new SerializerProviderWrapper(OptionalLongTypeSerializer::new, OptionalLongTypeDeserializer::new)); - serializers.put(Path.class, - new SerializerProviderWrapper(PathTypeSerializer::new, PathTypeDeserializer::new)); - serializers.put(Short.class, new SerializerProviderWrapper(ShortTypeSerializer::new, ShortTypeDeserializer::new)); - serializers.put(Short.TYPE, new SerializerProviderWrapper(ShortTypeSerializer::new, ShortTypeDeserializer::new)); - serializers.put(String.class, new SerializerProviderWrapper(StringTypeSerializer::new, StringTypeDeserializer::new)); - serializers - .put(TimeZone.class, new SerializerProviderWrapper(TimeZoneTypeSerializer::new, TimeZoneTypeDeserializer::new)); - serializers.put(URI.class, new SerializerProviderWrapper(URITypeSerializer::new, URITypeDeserializer::new)); - serializers.put(URL.class, new SerializerProviderWrapper(URLTypeSerializer::new, URLTypeDeserializer::new)); - serializers.put(UUID.class, new SerializerProviderWrapper(UUIDTypeSerializer::new, UUIDTypeDeserializer::new)); - serializers.put(ZonedDateTime.class, - new SerializerProviderWrapper(ZonedDateTimeTypeSerializer::new, ZonedDateTimeTypeDeserializer::new)); - serializers - .put(Duration.class, new SerializerProviderWrapper(DurationTypeSerializer::new, DurationTypeDeserializer::new)); - serializers.put(Period.class, new SerializerProviderWrapper(PeriodTypeSerializer::new, PeriodTypeDeserializer::new)); - serializers.put(ZoneId.class, new SerializerProviderWrapper(ZoneIdTypeSerializer::new, ZoneIdTypeDeserializer::new)); - serializers.put(BigInteger.class, - new SerializerProviderWrapper(BigIntegerTypeSerializer::new, BigIntegerTypeDeserializer::new)); - serializers.put(BigDecimal.class, - new SerializerProviderWrapper(BigDecimalTypeSerializer::new, BigDecimalTypeDeserializer::new)); - serializers.put(ZoneOffset.class, - new SerializerProviderWrapper(ZoneOffsetTypeSerializer::new, ZoneOffsetTypeDeserializer::new)); - - if (isClassAvailable("javax.xml.datatype.XMLGregorianCalendar")) { - serializers.put(XMLGregorianCalendar.class, - new SerializerProviderWrapper(XMLGregorianCalendarTypeSerializer::new, - XMLGregorianCalendarTypeDeserializer::new)); - } - - serializers.put(YearMonth.class, - new SerializerProviderWrapper(YearMonthTypeSerializer::new, YearMonthTypeDeserializer::new)); - serializers.put(MonthDay.class, - new SerializerProviderWrapper(MonthDayTypeSerializer::new, MonthDayTypeDeserializer::new)); - - return serializers; - } - - /** - * Look for a provider for a supported value type. These serializers are basically singleton stateless shared instances. - * - * @param clazz supported type class - * @param Type of serializer - * @return serializer if found - */ - public static Optional findValueSerializerProvider(Class clazz) { - Class candidate = clazz; - do { - final SerializerProviderWrapper provider = SERIALIZERS.get(candidate); - if (provider != null) { - return Optional.of(provider); - } - candidate = candidate.getSuperclass(); - } while (candidate != null); - - return findByCondition(clazz); - } - - private static Optional findByCondition(Class clazz) { - if (Enum.class.isAssignableFrom(clazz)) { - return Optional.of(ENUM_PROVIDER); - } else if (JsonString.class.isAssignableFrom(clazz)) { - return Optional.of(SERIALIZERS.get(JsonString.class)); - } else if (JsonNumber.class.isAssignableFrom(clazz)) { - return Optional.of(SERIALIZERS.get(JsonNumber.class)); - } else if (JsonValue.class.isAssignableFrom(clazz) && !( - JsonObject.class.isAssignableFrom(clazz) || JsonArray.class.isAssignableFrom(clazz))) { - return Optional.of(SERIALIZERS.get(JsonValue.class)); - } - return Optional.empty(); - } - - /** - * Checks a class if it is supported by Yasson builtin serializers/deserializers in order to decide if it - * should be introspected with reflection. - * - * @param clazz class to check - * @return true if 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 || findValueSerializerProvider(clazz).isPresent(); - } - - private static boolean isClassAvailable(String className) { - try { - Class.forName(className); - return true; - } catch (ClassNotFoundException | LinkageError e) { - return false; - } - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/DeserializerBuilder.java b/src/main/java/org/eclipse/yasson/internal/serializer/DeserializerBuilder.java deleted file mode 100644 index 27ea24e6a..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/DeserializerBuilder.java +++ /dev/null @@ -1,304 +0,0 @@ -/* - * Copyright (c) 2015, 2020 Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2019, 2020 Payara Foundation 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.serializer; - -import java.lang.reflect.GenericArrayType; -import java.lang.reflect.Type; -import java.math.BigDecimal; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Map; -import java.util.Optional; - -import jakarta.json.JsonValue; -import jakarta.json.bind.JsonbException; -import jakarta.json.bind.config.BinaryDataStrategy; -import jakarta.json.bind.serializer.JsonbDeserializer; -import jakarta.json.stream.JsonParser; - -import org.eclipse.yasson.internal.ComponentMatcher; -import org.eclipse.yasson.internal.JsonbContext; -import org.eclipse.yasson.internal.ReflectionUtils; -import org.eclipse.yasson.internal.components.AdapterBinding; -import org.eclipse.yasson.internal.components.DeserializerBinding; -import org.eclipse.yasson.internal.model.customization.ComponentBoundCustomization; -import org.eclipse.yasson.internal.model.customization.Customization; -import org.eclipse.yasson.internal.model.customization.PropertyCustomization; -import org.eclipse.yasson.internal.properties.MessageKeys; -import org.eclipse.yasson.internal.properties.Messages; - -/** - * Builder for currently processed items by unmarshaller. - */ -public class DeserializerBuilder extends AbstractSerializerBuilder { - - /** - * Value type of JSON event. - */ - private JsonParser.Event jsonEvent; - - /** - * Creates a new builder. - * - * @param jsonbContext Context. - */ - public DeserializerBuilder(JsonbContext jsonbContext) { - super(jsonbContext); - } - - /** - * Sets value type. - * - * @param event last json event for constructed deserializer. - * @return Updated object. - */ - public DeserializerBuilder withJsonValueType(JsonParser.Event event) { - this.jsonEvent = event; - return this; - } - - /** - * Build an fully initialized item. - * - * @return built item - */ - public JsonbDeserializer build() { - withRuntimeType(resolveRuntimeType()); - Class rawType = ReflectionUtils.getRawType(getRuntimeType()); - - Optional adapterInfoOptional = Optional.empty(); - Customization customization = getCustomization(); - if (customization == null - || customization instanceof ComponentBoundCustomization) { - ComponentBoundCustomization componentBoundCustomization = (ComponentBoundCustomization) customization; - - //First check if user deserializer is registered for such type - final ComponentMatcher componentMatcher = getJsonbContext().getComponentMatcher(); - Optional> userDeserializer = - componentMatcher.getDeserializerBinding(getRuntimeType(), componentBoundCustomization); - if (userDeserializer.isPresent()) { - return new UserDeserializerDeserializer<>(this, userDeserializer.get()); - } - - //Second user components is registered. - Optional adapterBinding = componentMatcher - .getDeserializeAdapterBinding(getRuntimeType(), componentBoundCustomization); - if (adapterBinding.isPresent()) { - adapterInfoOptional = adapterBinding; - withRuntimeType(adapterInfoOptional.get().getToType()); - withWrapper(new AdaptedObjectDeserializer<>(adapterInfoOptional.get(), - (AbstractContainerDeserializer) getWrapper())); - rawType = ReflectionUtils.getRawType(getRuntimeType()); - } - } - - if (Optional.class == rawType) { - return new OptionalObjectDeserializer(this); - } - - //In case of Base64 json value would be string and recognition by JsonValueType would not work - if (isByteArray(rawType)) { - String strategy = getJsonbContext().getConfigProperties().getBinaryDataStrategy(); - switch (strategy) { - case BinaryDataStrategy.BYTE: - return new ByteArrayDeserializer(this); - default: - return new ByteArrayBase64Deserializer(customization); - } - } - - if (isCharArray(rawType)) { - return new CharArrayDeserializer(this); - } - - //Third deserializer is a supported value type to deserialize to JSON_VALUE - if (isJsonValueEvent(jsonEvent)) { - final Optional> supportedTypeDeserializer = getSupportedTypeDeserializer(rawType); - if (!supportedTypeDeserializer.isPresent()) { - if (jsonEvent == JsonParser.Event.VALUE_NULL) { - return NullDeserializer.INSTANCE; - } - throw new JsonbException(Messages.getMessage(MessageKeys.DESERIALIZE_VALUE_ERROR, getRuntimeType())); - } - return wrapAdapted(adapterInfoOptional, supportedTypeDeserializer.get()); - } - - JsonbDeserializer deserializer; - if (jsonEvent == JsonParser.Event.START_ARRAY) { - if (JsonValue.class.isAssignableFrom(rawType)) { - return wrapAdapted(adapterInfoOptional, new JsonArrayDeserializer(this)); - } else if (Map.class.isAssignableFrom(rawType)) { - final JsonbDeserializer mapDeserializer = new MapEntriesArrayDeserializer<>(this); - return wrapAdapted(adapterInfoOptional, mapDeserializer); - } else if (rawType.isArray() || getRuntimeType() instanceof GenericArrayType) { - deserializer = createArrayItem(rawType.getComponentType()); - return wrapAdapted(adapterInfoOptional, deserializer); - } else if (Collection.class.isAssignableFrom(rawType)) { - deserializer = new CollectionDeserializer<>(this); - return wrapAdapted(adapterInfoOptional, deserializer); - } else { - throw new JsonbException("Can't deserialize JSON array into: " + getRuntimeType()); - } - } else if (jsonEvent == JsonParser.Event.START_OBJECT) { - if (JsonValue.class.isAssignableFrom(rawType)) { - return wrapAdapted(adapterInfoOptional, new JsonObjectDeserializer(this)); - } else if (Map.class.isAssignableFrom(rawType)) { - final JsonbDeserializer mapDeserializer = new MapDeserializer<>(this); - return wrapAdapted(adapterInfoOptional, mapDeserializer); - } else if (rawType.isInterface()) { - Class mappedType = getInterfaceMappedType(rawType); - if (mappedType == null) { - throw new JsonbException(Messages.getMessage(MessageKeys.INFER_TYPE_FOR_UNMARSHALL, rawType.getName())); - } - withRuntimeType(mappedType); - withClassModel(getClassModel(mappedType)); - return new ObjectDeserializer<>(this); - } else { - if (adapterInfoOptional.isPresent()) { - withRuntimeType(adapterInfoOptional.get().getToType()); - rawType = ReflectionUtils.getRawType(getRuntimeType()); - } - - withClassModel(getClassModel(rawType)); - - deserializer = new ObjectDeserializer<>(this); - return wrapAdapted(adapterInfoOptional, deserializer); - } - } - throw new JsonbException("unresolved type for deserialization: " + getRuntimeType()); - } - - /** - * Checks if event is a value event. - * - * @param event JSON event to check. - * @return True if one of value events. - */ - public static boolean isJsonValueEvent(JsonParser.Event event) { - switch (event) { - case VALUE_NULL: - case VALUE_FALSE: - case VALUE_TRUE: - case VALUE_NUMBER: - case VALUE_STRING: - return true; - default: - return false; - } - } - - private Optional> getSupportedTypeDeserializer(Class rawType) { - final Optional supportedTypeDeserializerOptional = DefaultSerializers - .findValueSerializerProvider(rawType); - if (supportedTypeDeserializerOptional.isPresent()) { - return Optional.of(supportedTypeDeserializerOptional.get().getDeserializerProvider() - .provideDeserializer(getCustomization())); - } - return Optional.empty(); - } - - @SuppressWarnings("unchecked") - private JsonbDeserializer wrapAdapted(Optional adapterInfoOptional, JsonbDeserializer item) { - final Optional> adaptedDeserializerOptional = adapterInfoOptional.map(adapterInfo -> { - setAdaptedItemCaptor((AdaptedObjectDeserializer) getWrapper(), item); - return (JsonbDeserializer) getWrapper(); - }); - return adaptedDeserializerOptional.orElse(item); - } - - private void setAdaptedItemCaptor(AdaptedObjectDeserializer decoratorItem, JsonbDeserializer adaptedItem) { - decoratorItem.setAdaptedTypeDeserializer(adaptedItem); - } - - private Type resolveRuntimeType() { - Type result = ReflectionUtils.resolveType(getWrapper(), getGenericType() != null ? getGenericType() : getRuntimeType()); - //Try to infer best from JSON event. - if (result == Object.class) { - switch (jsonEvent) { - case VALUE_FALSE: - case VALUE_TRUE: - return Boolean.class; - case VALUE_NUMBER: - return BigDecimal.class; - case VALUE_STRING: - return String.class; - case START_ARRAY: - return ArrayList.class; - case START_OBJECT: - return getJsonbContext().getConfigProperties().getDefaultMapImplType(); - case VALUE_NULL: - return Object.class; - default: - throw new IllegalStateException("Can't infer deserialization type type: " + jsonEvent); - - } - } - return result; - } - - private Class getInterfaceMappedType(Class interfaceType) { - if (interfaceType.isInterface()) { - Class implementationClass = null; - //annotation - if (getCustomization() instanceof PropertyCustomization) { - implementationClass = ((PropertyCustomization) getCustomization()).getImplementationClass(); - } - //JsonbConfig - if (implementationClass == null) { - implementationClass = getJsonbContext().getConfigProperties().getUserTypeMapping().get(interfaceType); - } - if (implementationClass != null) { - if (!interfaceType.isAssignableFrom(implementationClass)) { - throw new JsonbException(Messages.getMessage(MessageKeys.IMPL_CLASS_INCOMPATIBLE, - implementationClass, - interfaceType)); - } - return implementationClass; - } - } - return null; - } - - /** - * Instance is not created in case of array items, because, we don't know how long it should be - * till parser ends parsing. - */ - private JsonbDeserializer createArrayItem(Class componentType) { - if (componentType == byte.class) { - return new ByteArrayDeserializer(this); - } else if (componentType == short.class) { - return new ShortArrayDeserializer(this); - } else if (componentType == int.class) { - return new IntArrayDeserializer(this); - } else if (componentType == long.class) { - return new LongArrayDeserializer(this); - } else if (componentType == float.class) { - return new FloatArrayDeserializer(this); - } else if (componentType == double.class) { - return new DoubleArrayDeserializer(this); - } else if (componentType == boolean.class) { - return new BooleanArrayDeserializer(this); - } else { - return new ObjectArrayDeserializer(this); - } - } - - private boolean isByteArray(Class rawType) { - return rawType.isArray() && rawType.getComponentType() == Byte.TYPE; - } - - private boolean isCharArray(Class rawType) { - return rawType.isArray() && rawType.getComponentType() == Character.TYPE; - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/DoubleArrayDeserializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/DoubleArrayDeserializer.java deleted file mode 100644 index 00b3e5527..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/DoubleArrayDeserializer.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import java.util.ArrayList; -import java.util.List; - -import org.eclipse.yasson.internal.Unmarshaller; - -/** - * Array unmarshaller item implementation for small double. - */ -public class DoubleArrayDeserializer extends AbstractArrayDeserializer { - - private final List items = new ArrayList<>(); - - /** - * Creates new instance of double array deserializer. - * - * @param builder deserializer builder - */ - protected DoubleArrayDeserializer(DeserializerBuilder builder) { - super(builder); - } - - @Override - protected List getItems() { - return items; - } - - @Override - public double[] getInstance(Unmarshaller unmarshaller) { - final int size = items.size(); - final double[] doubleArray = new double[size]; - for (int i = 0; i < size; i++) { - doubleArray[i] = items.get(i); - } - return doubleArray; - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/DoubleArraySerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/DoubleArraySerializer.java deleted file mode 100644 index 4e3bfad64..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/DoubleArraySerializer.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import jakarta.json.bind.serializer.SerializationContext; -import jakarta.json.stream.JsonGenerator; - -/** - * Serializer for arrays of doubles. - */ -public class DoubleArraySerializer extends AbstractArraySerializer { - - /** - * Creates new instance of double array serializer. - * - * @param builder serializer builder - */ - protected DoubleArraySerializer(SerializerBuilder builder) { - super(builder); - } - - @Override - protected void serializeInternal(double[] arr, JsonGenerator generator, SerializationContext ctx) { - for (double obj : arr) { - generator.write(obj); - } - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/DoubleTypeDeserializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/DoubleTypeDeserializer.java deleted file mode 100644 index 088ee3911..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/DoubleTypeDeserializer.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import java.lang.reflect.Type; - -import jakarta.json.bind.JsonbException; - -import org.eclipse.yasson.internal.Unmarshaller; -import org.eclipse.yasson.internal.model.customization.Customization; -import org.eclipse.yasson.internal.properties.MessageKeys; -import org.eclipse.yasson.internal.properties.Messages; - -/** - * Deserializer for {@link Double} type. - */ -public class DoubleTypeDeserializer extends AbstractNumberDeserializer { - - private static final String POSITIVE_INFINITY = "POSITIVE_INFINITY"; - private static final String NEGATIVE_INFINITY = "NEGATIVE_INFINITY"; - private static final String NAN = "NaN"; - - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - DoubleTypeDeserializer(Customization customization) { - super(Double.class, customization); - } - - @Override - protected Double deserialize(String jsonValue, Unmarshaller unmarshaller, Type rtType) { - switch (jsonValue) { - case NAN: - return Double.NaN; - case POSITIVE_INFINITY: - return Double.POSITIVE_INFINITY; - case NEGATIVE_INFINITY: - return Double.NEGATIVE_INFINITY; - default: - return deserializeFormatted(jsonValue, false, unmarshaller.getJsonbContext()) - .map(num -> Double.parseDouble(num.toString())) - .orElseGet(() -> { - try { - return Double.parseDouble(jsonValue); - } catch (NumberFormatException e) { - throw new JsonbException(Messages.getMessage(MessageKeys.DESERIALIZE_VALUE_ERROR, - Double.class)); - } - }); - } - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/DoubleTypeSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/DoubleTypeSerializer.java deleted file mode 100644 index 964e126a3..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/DoubleTypeSerializer.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import jakarta.json.stream.JsonGenerator; - -import org.eclipse.yasson.internal.model.customization.Customization; - -/** - * Serializer for {@link Double} type. - */ -public class DoubleTypeSerializer extends AbstractNumberSerializer { - - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public DoubleTypeSerializer(Customization customization) { - super(customization); - } - - @Override - protected void serializeNonFormatted(Double obj, JsonGenerator generator, String key) { - generator.write(key, obj); - } - - @Override - protected void serializeNonFormatted(Double obj, JsonGenerator generator) { - generator.write(obj); - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/DurationTypeDeserializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/DurationTypeDeserializer.java deleted file mode 100644 index c760660d2..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/DurationTypeDeserializer.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import java.lang.reflect.Type; -import java.time.Duration; - -import org.eclipse.yasson.internal.Unmarshaller; -import org.eclipse.yasson.internal.model.customization.Customization; - -/** - * Deserializer for {@link Duration} type. - */ -public class DurationTypeDeserializer extends AbstractValueTypeDeserializer { - - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public DurationTypeDeserializer(Customization customization) { - super(Duration.class, customization); - } - - @Override - protected Duration deserialize(String jsonValue, Unmarshaller unmarshaller, Type rtType) { - return Duration.parse(jsonValue); - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/DurationTypeSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/DurationTypeSerializer.java deleted file mode 100644 index fad1ca4d2..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/DurationTypeSerializer.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import java.time.Duration; - -import jakarta.json.stream.JsonGenerator; - -import org.eclipse.yasson.internal.Marshaller; -import org.eclipse.yasson.internal.model.customization.Customization; - -/** - * Serializer for {@link Duration} type. - */ -public class DurationTypeSerializer extends AbstractValueTypeSerializer { - - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public DurationTypeSerializer(Customization customization) { - super(customization); - } - - @Override - protected void serialize(Duration obj, JsonGenerator generator, Marshaller marshaller) { - generator.write(obj.toString()); - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/EnumTypeDeserializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/EnumTypeDeserializer.java deleted file mode 100644 index 35a67c320..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/EnumTypeDeserializer.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import java.lang.reflect.Type; - -import org.eclipse.yasson.internal.Unmarshaller; -import org.eclipse.yasson.internal.model.customization.Customization; - -/** - * Deserializer for {@link Enum} type. - */ -public class EnumTypeDeserializer extends AbstractValueTypeDeserializer { - - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public EnumTypeDeserializer(Customization customization) { - super(Enum.class, customization); - } - - @Override - @SuppressWarnings("unchecked") - protected Enum deserialize(String jsonValue, Unmarshaller unmarshaller, Type rtType) { - return Enum.valueOf((Class) rtType, jsonValue); - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/EnumTypeSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/EnumTypeSerializer.java deleted file mode 100644 index ed83c1fc9..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/EnumTypeSerializer.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import jakarta.json.stream.JsonGenerator; - -import org.eclipse.yasson.internal.Marshaller; -import org.eclipse.yasson.internal.model.customization.Customization; - -/** - * Serializer for {@link Enum} type. - */ -public class EnumTypeSerializer extends AbstractValueTypeSerializer { - - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public EnumTypeSerializer(Customization customization) { - super(customization); - } - - @Override - protected void serialize(Enum obj, JsonGenerator generator, Marshaller marshaller) { - generator.write(obj.name()); - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/FloatArrayDeserializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/FloatArrayDeserializer.java deleted file mode 100644 index deced6f36..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/FloatArrayDeserializer.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import java.util.ArrayList; -import java.util.List; - -import org.eclipse.yasson.internal.Unmarshaller; - -/** - * Array unmarshaller item implementation for small float. - */ -public class FloatArrayDeserializer extends AbstractArrayDeserializer { - private final List items = new ArrayList<>(); - - /** - * Creates new instance of float array deserializer. - * - * @param builder deserializer builder - */ - protected FloatArrayDeserializer(DeserializerBuilder builder) { - super(builder); - } - - @Override - protected List getItems() { - return items; - } - - @Override - public float[] getInstance(Unmarshaller unmarshaller) { - final int size = items.size(); - final float[] floatArray = new float[size]; - for (int i = 0; i < size; i++) { - floatArray[i] = items.get(i); - } - return floatArray; - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/FloatArraySerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/FloatArraySerializer.java deleted file mode 100644 index 8e893c9a9..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/FloatArraySerializer.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import java.math.BigDecimal; - -import jakarta.json.bind.serializer.SerializationContext; -import jakarta.json.stream.JsonGenerator; - -/** - * Serializer for arrays of floats. - */ -public class FloatArraySerializer extends AbstractArraySerializer { - - /** - * Creates new instance of float array serializer. - * - * @param builder serializer builder - */ - protected FloatArraySerializer(SerializerBuilder builder) { - super(builder); - } - - @Override - protected void serializeInternal(float[] arr, JsonGenerator generator, SerializationContext ctx) { - for (float obj : arr) { - //floats lose precision, after upcasting to doubles in jsonp - generator.write(new BigDecimal(String.valueOf(obj))); - } - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/FloatTypeDeserializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/FloatTypeDeserializer.java deleted file mode 100644 index f8bc20069..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/FloatTypeDeserializer.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import java.lang.reflect.Type; - -import jakarta.json.bind.JsonbException; - -import org.eclipse.yasson.internal.Unmarshaller; -import org.eclipse.yasson.internal.model.customization.Customization; -import org.eclipse.yasson.internal.properties.MessageKeys; -import org.eclipse.yasson.internal.properties.Messages; - -/** - * Deserializer for {@link Float} type. - */ -public class FloatTypeDeserializer extends AbstractNumberDeserializer { - - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public FloatTypeDeserializer(Customization customization) { - super(Float.class, customization); - } - - @Override - protected Float deserialize(String jsonValue, Unmarshaller unmarshaller, Type rtType) { - return deserializeFormatted(jsonValue, false, unmarshaller.getJsonbContext()) - .map(num -> Float.parseFloat(num.toString())) - .orElseGet(() -> { - try { - return Float.parseFloat(jsonValue); - } catch (NumberFormatException e) { - throw new JsonbException(Messages.getMessage(MessageKeys.DESERIALIZE_VALUE_ERROR, Float.class)); - } - }); - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/FloatTypeSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/FloatTypeSerializer.java deleted file mode 100644 index 735a2e938..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/FloatTypeSerializer.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import java.math.BigDecimal; - -import jakarta.json.stream.JsonGenerator; - -import org.eclipse.yasson.internal.model.customization.Customization; - -/** - * Serializer for {@link Float} type. - */ -public class FloatTypeSerializer extends AbstractNumberSerializer { - - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public FloatTypeSerializer(Customization customization) { - super(customization); - } - - @Override - protected void serializeNonFormatted(Float obj, JsonGenerator generator, String key) { - //floats lose precision, after upcasting to doubles in jsonp - generator.write(key, new BigDecimal(String.valueOf(obj))); - } - - @Override - protected void serializeNonFormatted(Float obj, JsonGenerator generator) { - //floats lose precision, after upcasting to doubles in jsonp - generator.write(new BigDecimal(String.valueOf(obj))); - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/IDeserializerProvider.java b/src/main/java/org/eclipse/yasson/internal/serializer/IDeserializerProvider.java deleted file mode 100644 index 596da7a9c..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/IDeserializerProvider.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import org.eclipse.yasson.internal.model.customization.Customization; - -/** - * Creates instance of deserializer. - */ -@FunctionalInterface -public interface IDeserializerProvider { - - /** - * Provides new instance of deserializer. - * - * @param customization model customization - * @return deserializer - */ - AbstractValueTypeDeserializer provideDeserializer(Customization customization); -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/ISerializerProvider.java b/src/main/java/org/eclipse/yasson/internal/serializer/ISerializerProvider.java deleted file mode 100644 index 305fb2920..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/ISerializerProvider.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import org.eclipse.yasson.internal.model.customization.Customization; - -/** - * Create instance of a serializer. - */ -@FunctionalInterface -public interface ISerializerProvider { - - /** - * Provides new instance of serializer. - * - * @param customization model customization - * @return deserializer - */ - AbstractValueTypeSerializer provideSerializer(Customization customization); -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/IntArrayDeserializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/IntArrayDeserializer.java deleted file mode 100644 index 4c1b3b93b..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/IntArrayDeserializer.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import java.util.ArrayList; -import java.util.List; - -import org.eclipse.yasson.internal.Unmarshaller; - -/** - * Array unmarshaller item implementation for small int. - */ -public class IntArrayDeserializer extends AbstractArrayDeserializer { - - private final List items = new ArrayList<>(); - - /** - * Creates new instance of int array deserializer. - * - * @param builder deserializer builder - */ - protected IntArrayDeserializer(DeserializerBuilder builder) { - super(builder); - } - - @Override - protected List getItems() { - return items; - } - - @Override - public int[] getInstance(Unmarshaller unmarshaller) { - final int size = items.size(); - final int[] intArray = new int[size]; - for (int i = 0; i < size; i++) { - intArray[i] = items.get(i); - } - return intArray; - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/IntArraySerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/IntArraySerializer.java deleted file mode 100644 index 66cd6ad0f..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/IntArraySerializer.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import jakarta.json.bind.serializer.SerializationContext; -import jakarta.json.stream.JsonGenerator; - -/** - * Serializer for arrays of ints. - */ -public class IntArraySerializer extends AbstractArraySerializer { - - /** - * Creates new instance of int array serializer. - * - * @param builder serializer builder - */ - protected IntArraySerializer(SerializerBuilder builder) { - super(builder); - } - - @Override - protected void serializeInternal(int[] arr, JsonGenerator generator, SerializationContext ctx) { - for (int obj : arr) { - generator.write(obj); - } - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/IntegerTypeDeserializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/IntegerTypeDeserializer.java deleted file mode 100644 index ee12d9f02..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/IntegerTypeDeserializer.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import java.lang.reflect.Type; - -import jakarta.json.bind.JsonbException; - -import org.eclipse.yasson.internal.Unmarshaller; -import org.eclipse.yasson.internal.model.customization.Customization; -import org.eclipse.yasson.internal.properties.MessageKeys; -import org.eclipse.yasson.internal.properties.Messages; - -/** - * Deserializer for {@link Integer} type. - */ -public class IntegerTypeDeserializer extends AbstractNumberDeserializer { - - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public IntegerTypeDeserializer(Customization customization) { - super(Integer.class, customization); - } - - @Override - protected Integer deserialize(String jsonValue, Unmarshaller unmarshaller, Type rtType) { - return deserializeFormatted(jsonValue, true, unmarshaller.getJsonbContext()) - .map(num -> Integer.parseInt(num.toString())) - .orElseGet(() -> { - try { - return Integer.parseInt(jsonValue); - } catch (NumberFormatException e) { - throw new JsonbException(Messages.getMessage(MessageKeys.DESERIALIZE_VALUE_ERROR, - Integer.class)); - } - }); - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/IntegerTypeSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/IntegerTypeSerializer.java deleted file mode 100644 index 1b730b46e..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/IntegerTypeSerializer.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import jakarta.json.stream.JsonGenerator; - -import org.eclipse.yasson.internal.model.customization.Customization; - -/** - * Serializer for {@link Integer} type. - */ -public class IntegerTypeSerializer extends AbstractNumberSerializer { - - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public IntegerTypeSerializer(Customization customization) { - super(customization); - } - - @Override - protected void serializeNonFormatted(Integer obj, JsonGenerator generator, String key) { - generator.write(key, obj); - } - - @Override - protected void serializeNonFormatted(Integer obj, JsonGenerator generator) { - generator.write(obj); - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/JsonArrayDeserializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/JsonArrayDeserializer.java deleted file mode 100644 index cb5b20e2b..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/JsonArrayDeserializer.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import jakarta.json.JsonArray; - -import org.eclipse.yasson.internal.JsonbParser; -import org.eclipse.yasson.internal.Unmarshaller; - -/** - * Item for JsonArray. - */ -public class JsonArrayDeserializer extends AbstractJsonpDeserializer { - - private JsonArray jsonArray; - - /** - * Create instance. - * - * @param builder Builder to initialize from. - */ - protected JsonArrayDeserializer(DeserializerBuilder builder) { - super(builder); - } - - @Override - protected void deserializeInternal(JsonbParser parser, Unmarshaller context) { - this.jsonArray = parser.getArray(); - } - - @Override - public JsonArray getInstance(Unmarshaller unmarshaller) { - return jsonArray; - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/JsonArraySerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/JsonArraySerializer.java deleted file mode 100644 index 07b77e6b4..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/JsonArraySerializer.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import jakarta.json.JsonArray; -import jakarta.json.JsonValue; -import jakarta.json.bind.serializer.SerializationContext; -import jakarta.json.stream.JsonGenerator; - -/** - * Serializer for {@link JsonArray}. - */ -public class JsonArraySerializer extends AbstractJsonpSerializer { - - /** - * Creates new instance of json array serializer. - * - * @param builder serializer builder - */ - protected JsonArraySerializer(SerializerBuilder builder) { - super(builder); - } - - @Override - protected void serializeInternal(JsonArray obj, JsonGenerator generator, SerializationContext ctx) { - for (JsonValue value : obj) { - generator.write(value); - } - } - - @Override - protected void writeStart(JsonGenerator generator) { - generator.writeStartArray(); - } - - @Override - protected void writeStart(String key, JsonGenerator generator) { - generator.writeStartArray(key); - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/JsonNumberTypeDeserializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/JsonNumberTypeDeserializer.java deleted file mode 100644 index 89cb918d3..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/JsonNumberTypeDeserializer.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import java.lang.reflect.Type; -import java.math.BigDecimal; - -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonNumber; -import jakarta.json.JsonObject; - -import org.eclipse.yasson.internal.Unmarshaller; -import org.eclipse.yasson.internal.model.customization.Customization; - -/** - * Deserializer for {@link JsonNumber} type. - */ -public class JsonNumberTypeDeserializer extends AbstractValueTypeDeserializer { - - private static final String NUMBER = "number"; - - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public JsonNumberTypeDeserializer(Customization customization) { - super(JsonNumber.class, customization); - } - - @Override - protected JsonNumber deserialize(String jsonValue, Unmarshaller unmarshaller, Type rtType) { - final JsonBuilderFactory factory = unmarshaller.getJsonbContext().getJsonProvider().createBuilderFactory(null); - JsonObject jsonObject; - try { - Integer integer = Integer.parseInt(jsonValue); - - jsonObject = factory.createObjectBuilder() - .add(NUMBER, integer) - .build(); - return jsonObject.getJsonNumber(NUMBER); - } catch (NumberFormatException exception) { - } - try { - Long l = Long.parseLong(jsonValue); - - jsonObject = factory.createObjectBuilder() - .add(NUMBER, l) - .build(); - return jsonObject.getJsonNumber(NUMBER); - } catch (NumberFormatException exception) { - } - - jsonObject = factory.createObjectBuilder() - .add(NUMBER, new BigDecimal(jsonValue)) - .build(); - return jsonObject.getJsonNumber(NUMBER); - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/JsonObjectDeserializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/JsonObjectDeserializer.java deleted file mode 100644 index 702f54441..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/JsonObjectDeserializer.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import jakarta.json.JsonObject; - -import org.eclipse.yasson.internal.JsonbParser; -import org.eclipse.yasson.internal.Unmarshaller; - -/** - * Item for JsonObject. - */ -public class JsonObjectDeserializer extends AbstractJsonpDeserializer { - - private JsonObject jsonObject; - - @Override - protected void deserializeInternal(JsonbParser parser, Unmarshaller context) { - this.jsonObject = parser.getObject(); - } - - /** - * Create instance of current item with its builder. - * - * @param builder {@link DeserializerBuilder} used to build this instance - */ - protected JsonObjectDeserializer(DeserializerBuilder builder) { - super(builder); - } - - @Override - public JsonObject getInstance(Unmarshaller unmarshaller) { - return jsonObject; - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/JsonObjectSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/JsonObjectSerializer.java deleted file mode 100644 index 2c486c399..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/JsonObjectSerializer.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import java.util.Map; - -import jakarta.json.JsonObject; -import jakarta.json.JsonValue; -import jakarta.json.bind.serializer.SerializationContext; -import jakarta.json.stream.JsonGenerator; - -/** - * Serializer for {@link JsonObject} type. - */ -public class JsonObjectSerializer extends AbstractJsonpSerializer { - - /** - * Creates new instance of json object serializer. - * - * @param builder serializer builder - */ - protected JsonObjectSerializer(SerializerBuilder builder) { - super(builder); - } - - @Override - protected void serializeInternal(JsonObject obj, JsonGenerator generator, SerializationContext ctx) { - for (Map.Entry entry : obj.entrySet()) { - generator.write(entry.getKey(), entry.getValue()); - } - } - - @Override - protected void writeStart(JsonGenerator generator) { - generator.writeStartObject(); - } - - @Override - protected void writeStart(String key, JsonGenerator generator) { - generator.writeStartObject(key); - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/JsonStringTypeDeserializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/JsonStringTypeDeserializer.java deleted file mode 100644 index 581138f91..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/JsonStringTypeDeserializer.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import java.lang.reflect.Type; - -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonObject; -import jakarta.json.JsonString; - -import org.eclipse.yasson.internal.Unmarshaller; -import org.eclipse.yasson.internal.model.customization.Customization; - -/** - * Deserializer for {@link JsonString} type. - */ -public class JsonStringTypeDeserializer extends AbstractValueTypeDeserializer { - - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public JsonStringTypeDeserializer(Customization customization) { - super(JsonString.class, customization); - } - - @Override - protected JsonString deserialize(String jsonValue, Unmarshaller unmarshaller, Type rtType) { - final JsonBuilderFactory factory = unmarshaller.getJsonbContext().getJsonProvider().createBuilderFactory(null); - final JsonObject jsonObject = factory.createObjectBuilder() - .add("json", jsonValue) - .build(); - return jsonObject.getJsonString("json"); - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/JsonValueDeserializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/JsonValueDeserializer.java deleted file mode 100644 index eeb654e72..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/JsonValueDeserializer.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import java.lang.reflect.Type; - -import jakarta.json.JsonValue; -import jakarta.json.bind.JsonbException; -import jakarta.json.bind.serializer.DeserializationContext; -import jakarta.json.stream.JsonParser; - -import org.eclipse.yasson.internal.JsonbRiParser; -import org.eclipse.yasson.internal.Unmarshaller; -import org.eclipse.yasson.internal.model.customization.Customization; -import org.eclipse.yasson.internal.properties.MessageKeys; -import org.eclipse.yasson.internal.properties.Messages; - -/** - * Deserializer for {@link JsonValue} containing null, false, true, string and number. - */ -public class JsonValueDeserializer extends AbstractValueTypeDeserializer { - - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public JsonValueDeserializer(Customization customization) { - super(JsonValue.class, customization); - } - - @Override - public JsonValue deserialize(JsonParser parser, DeserializationContext ctx, Type rtType) { - final JsonParser.Event next = ((JsonbRiParser) parser).getLastEvent(); - switch (next) { - case VALUE_TRUE: - return JsonValue.TRUE; - case VALUE_FALSE: - return JsonValue.FALSE; - case VALUE_NULL: - return JsonValue.NULL; - case VALUE_STRING: - case VALUE_NUMBER: - return parser.getValue(); - default: - throw new JsonbException(Messages.getMessage(MessageKeys.INTERNAL_ERROR, "Unknown JSON value: " + next)); - } - } - - @Override - protected JsonValue deserialize(String jsonValue, Unmarshaller unmarshaller, Type rtType) { - throw new UnsupportedOperationException(); - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/JsonValueSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/JsonValueSerializer.java deleted file mode 100644 index aa16c5e0e..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/JsonValueSerializer.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import jakarta.json.JsonValue; -import jakarta.json.stream.JsonGenerator; - -import org.eclipse.yasson.internal.Marshaller; -import org.eclipse.yasson.internal.model.customization.Customization; - -/** - * Serializer for {@link JsonValue} type. - */ -public class JsonValueSerializer extends AbstractValueTypeSerializer { - - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public JsonValueSerializer(Customization customization) { - super(customization); - } - - @Override - protected void serialize(JsonValue obj, JsonGenerator generator, Marshaller marshaller) { - generator.write(obj); - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/KeyWriter.java b/src/main/java/org/eclipse/yasson/internal/serializer/KeyWriter.java new file mode 100644 index 000000000..d359f6577 --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/serializer/KeyWriter.java @@ -0,0 +1,44 @@ +/* + * 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.serializer; + +import jakarta.json.stream.JsonGenerator; + +import org.eclipse.yasson.internal.SerializationContextImpl; + +/** + * Key name writer. Writes key name of the property if present. + */ +public class KeyWriter implements ModelSerializer { + + private final ModelSerializer delegate; + + /** + * Create new instance. + * + * @param delegate delegate to be called after the key is written + */ + public KeyWriter(ModelSerializer delegate) { + this.delegate = delegate; + } + + @Override + public void serialize(Object value, JsonGenerator generator, SerializationContextImpl context) { + if (context.getKey() != null) { + generator.writeKey(context.getKey()); + context.setKey(null); + } + delegate.serialize(value, generator, context); + } + +} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/LongArrayDeserializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/LongArrayDeserializer.java deleted file mode 100644 index 0df2d0d4d..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/LongArrayDeserializer.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import java.util.ArrayList; -import java.util.List; - -import org.eclipse.yasson.internal.Unmarshaller; - -/** - * Array unmarshaller item implementation for small long. - */ -public class LongArrayDeserializer extends AbstractArrayDeserializer { - - private final List items = new ArrayList<>(); - - /** - * Creates new array of long array deserializer. - * - * @param builder deserializer builder - */ - protected LongArrayDeserializer(DeserializerBuilder builder) { - super(builder); - } - - @Override - protected List getItems() { - return items; - } - - @Override - public long[] getInstance(Unmarshaller unmarshaller) { - final int size = items.size(); - final long[] longArray = new long[size]; - for (int i = 0; i < size; i++) { - longArray[i] = items.get(i); - } - return longArray; - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/LongArraySerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/LongArraySerializer.java deleted file mode 100644 index 5f6ec46ed..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/LongArraySerializer.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import jakarta.json.bind.serializer.SerializationContext; -import jakarta.json.stream.JsonGenerator; - -/** - * Serializer for arrays of longs. - */ -public class LongArraySerializer extends AbstractArraySerializer { - - /** - * Creates new array of long array serializer. - * - * @param builder serializer builder - */ - protected LongArraySerializer(SerializerBuilder builder) { - super(builder); - } - - @Override - protected void serializeInternal(long[] arr, JsonGenerator generator, SerializationContext ctx) { - for (long obj : arr) { - generator.write(obj); - } - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/LongTypeDeserializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/LongTypeDeserializer.java deleted file mode 100644 index b3ffc8e8a..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/LongTypeDeserializer.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import java.lang.reflect.Type; - -import jakarta.json.bind.JsonbException; - -import org.eclipse.yasson.internal.Unmarshaller; -import org.eclipse.yasson.internal.model.customization.Customization; -import org.eclipse.yasson.internal.properties.MessageKeys; -import org.eclipse.yasson.internal.properties.Messages; - -/** - * Deserializer for {@link Long} type. - */ -public class LongTypeDeserializer extends AbstractNumberDeserializer { - - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public LongTypeDeserializer(Customization customization) { - super(Long.class, customization); - } - - @Override - protected Long deserialize(String jsonValue, Unmarshaller unmarshaller, Type rtType) { - return deserializeFormatted(jsonValue, true, unmarshaller.getJsonbContext()) - .map(num -> Long.parseLong(num.toString())) - .orElseGet(() -> { - try { - return Long.parseLong(jsonValue); - } catch (NumberFormatException e) { - throw new JsonbException(Messages.getMessage(MessageKeys.DESERIALIZE_VALUE_ERROR, Long.class)); - } - }); - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/LongTypeSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/LongTypeSerializer.java deleted file mode 100644 index 893903039..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/LongTypeSerializer.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import jakarta.json.stream.JsonGenerator; - -import org.eclipse.yasson.internal.model.customization.Customization; - -/** - * Serializer for {@link Long} type. - */ -public class LongTypeSerializer extends AbstractNumberSerializer { - - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public LongTypeSerializer(Customization customization) { - super(customization); - } - - @Override - protected void serializeNonFormatted(Long obj, JsonGenerator generator, String key) { - generator.write(key, obj); - } - - @Override - protected void serializeNonFormatted(Long obj, JsonGenerator generator) { - generator.write(obj); - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/MapDeserializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/MapDeserializer.java deleted file mode 100644 index db020097b..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/MapDeserializer.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright (c) 2015, 2021 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.serializer; - -import java.io.StringReader; -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; -import java.util.HashMap; -import java.util.Map; -import java.util.NavigableMap; -import java.util.SortedMap; -import java.util.TreeMap; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.ConcurrentSkipListMap; - -import jakarta.json.bind.serializer.JsonbDeserializer; -import jakarta.json.stream.JsonParser; - -import org.eclipse.yasson.internal.JsonbParser; -import org.eclipse.yasson.internal.JsonbRiParser; -import org.eclipse.yasson.internal.ReflectionUtils; -import org.eclipse.yasson.internal.Unmarshaller; - -/** - * Item implementation for {@link java.util.Map} fields. - * According to JSON specification object can have only string keys. - * Nevertheless the implementation lets the key be a basic object that was - * serialized into a string representation. Therefore the key is also parsed to - * convert it into its parametrized type. - * - * @param map type - */ -public class MapDeserializer> extends AbstractContainerDeserializer implements EmbeddedItem { - - /** - * Type of the key in the map. - */ - private final Type mapKeyRuntimeType; - - /** - * Type of value in the map. - */ - private final Type mapValueRuntimeType; - - private final T instance; - - /** - * Create instance of current item with its builder. - * - * @param builder {@link DeserializerBuilder} used to build this instance - */ - protected MapDeserializer(DeserializerBuilder builder) { - super(builder); - mapKeyRuntimeType = getRuntimeType() instanceof ParameterizedType - ? ReflectionUtils.resolveType(this, ((ParameterizedType) getRuntimeType()).getActualTypeArguments()[0]) - : Object.class; - mapValueRuntimeType = getRuntimeType() instanceof ParameterizedType - ? ReflectionUtils.resolveType(this, ((ParameterizedType) getRuntimeType()).getActualTypeArguments()[1]) - : Object.class; - - this.instance = createInstance(builder); - } - - @SuppressWarnings("unchecked") - private T createInstance(DeserializerBuilder builder) { - Class rawType = ReflectionUtils.getRawType(getRuntimeType()); - return rawType.isInterface() - ? (T) getMapImpl(rawType, builder) - : (T) builder.getJsonbContext().getInstanceCreator().createInstance(rawType); - } - - private Map getMapImpl(Class ifcType, DeserializerBuilder builder) { - if (ConcurrentMap.class.isAssignableFrom(ifcType)) { - if (SortedMap.class.isAssignableFrom(ifcType) || NavigableMap.class.isAssignableFrom(ifcType)) { - return new ConcurrentSkipListMap<>(); - } else { - return new ConcurrentHashMap<>(); - } - } - // SortedMap, NavigableMap - if (SortedMap.class.isAssignableFrom(ifcType)) { - Class defaultMapImplType = builder.getJsonbContext().getConfigProperties().getDefaultMapImplType(); - return SortedMap.class.isAssignableFrom(defaultMapImplType) - ? (Map) builder.getJsonbContext().getInstanceCreator().createInstance(defaultMapImplType) - : new TreeMap<>(); - } - return new HashMap<>(); - } - - @Override - public T getInstance(Unmarshaller unmarshaller) { - return instance; - } - - @Override - public void appendResult(Object result, Unmarshaller context) { - // try to deserialize the string key into its type, JaxbException if not possible - final Object key = context.deserialize(mapKeyRuntimeType, new JsonbRiParser( - context.getJsonbContext().getJsonProvider().createParser( - new StringReader("\"" + getParserContext().getLastKeyName() + "\"")))); - appendCaptor(key, convertNullToOptionalEmpty(mapValueRuntimeType, result)); - } - - @SuppressWarnings("unchecked") - private void appendCaptor(K key, V value) { - ((Map) getInstance(null)).put(key, value); - } - - @Override - protected void deserializeNext(JsonParser parser, Unmarshaller context) { - final JsonbDeserializer deserializer = newCollectionOrMapItem(mapValueRuntimeType, context.getJsonbContext()); - appendResult(deserializer.deserialize(parser, context, mapValueRuntimeType), context); - } - - @Override - protected JsonbRiParser.LevelContext moveToFirst(JsonbParser parser) { - parser.moveTo(JsonParser.Event.START_OBJECT); - return parser.getCurrentLevel(); - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/MapEntriesArrayDeserializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/MapEntriesArrayDeserializer.java deleted file mode 100644 index 95204e939..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/MapEntriesArrayDeserializer.java +++ /dev/null @@ -1,496 +0,0 @@ -/* - * Copyright (c) 2019, 2020 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.serializer; - -import java.lang.reflect.Type; -import java.util.Map; - -import jakarta.json.bind.JsonbException; -import jakarta.json.bind.serializer.DeserializationContext; -import jakarta.json.bind.serializer.JsonbDeserializer; -import jakarta.json.stream.JsonParser; - -import org.eclipse.yasson.internal.JsonbParser; -import org.eclipse.yasson.internal.Unmarshaller; -import org.eclipse.yasson.internal.properties.MessageKeys; -import org.eclipse.yasson.internal.properties.Messages; - -/** - * De-serialize JSON array of map entries JSON objects as {@link Map}. - * JSON array of map entries JSON objects: - *
- * [
- *     {
- *         "key": JsonValue,
- *         "value": JsonValue
- *     }, ...
- * ]
- * 
- * - * @param {@link Map} key type to serialize - * @param {@link Map} value type to serialize - */ -public class MapEntriesArrayDeserializer extends AbstractItem> implements JsonbDeserializer> { - - /** - * Map entries parser internal state. - */ - private enum State { - /** - * Expecting the beginning of next Map entry JSON object. - */ - NEXT_ENTRY, - /** - * Expecting Map entry key ("key" or "value"). - */ - ENTRY_KEY, - /** - * Expecting Map entry value related to key. - */ - ENTRY_KEY_OBJECT, - /** - * Expecting Map entry value related to value. - */ - ENTRY_VALUE_OBJECT, - /** - * Expecting the end of current Map entry JSON object. - */ - ARRAY_END - } - - // Finite-state machine transition table: - // -------------------------------------- - // NEXT_ENTRY: - // * START_OBJECT -> ENTRY_KEY - // * END_ARRAY -> ARRAY_END (terminal state, exit parser) - // ENTRY_KEY: - // * KEY_NAME('key) -> ENTRY_KEY_OBJECT - // * KEY_NAME('value) -> ENTRY_VALUE_OBJECT - // * END_OBJECT -> NEXT_ENTRY - // ENTRY_KEY_OBJECT: - // * START_OBJECT -> external parser -> ENTRY_KEY - // * START_ARRAY -> external parser -> ENTRY_KEY - // * VALUE_STRING -> external parser -> ENTRY_KEY - // * VALUE_NUMBER -> external parser -> ENTRY_KEY - // * VALUE_TRUE -> external parser -> ENTRY_KEY - // * VALUE_FALSE -> external parser -> ENTRY_KEY - // * VALUE_NULL -> external parser -> ENTRY_KEY - // ENTRY_VALUE_OBJECT: - // * START_OBJECT -> external parser -> ENTRY_KEY - // * START_ARRAY -> external parser -> ENTRY_KEY - // * VALUE_STRING -> external parser -> ENTRY_KEY - // * VALUE_NUMBER -> external parser -> ENTRY_KEY - // * VALUE_TRUE -> external parser -> ENTRY_KEY - // * VALUE_FALSE -> external parser -> ENTRY_KEY - // * VALUE_NULL -> external parser -> ENTRY_KEY - // ARRAY_END: No additional JSON token processing is allowed in this state. - // JSON array of map entries parser must finish immediately. - // - // External parser shall process whole JSON value following 'key' or 'value' MapEntry JSON Object - // attribute identifiers. Finite-state machine just moves to ENTRY_KEY state to process next MapEntry - // attribute or to finish current MapEntry parsing when END_OBJECT token was received. - - // JSON tokens are mapped to event method calls defined in ContainerDeserializer: - // * START_ARRAY -> startArray - // * START_OBJECT -> startObject - // * KEY_NAME -> keyName - // * VALUE_STRING -> simpleValue - // * VALUE_NUMBER -> simpleValue - // * VALUE_TRUE -> simpleValue - // * VALUE_FALSE -> simpleValue - // * VALUE_NULL -> valueNull - // * END_ARRAY -> endArray - // * END_OBJECT -> endObject - // so JSON token dispatching is already implemented in ContainerDeserializer interface. - // Each method needs just current state dispatcher (switch statement) to implement finite-state machine - // transition function T(token, state) -> state - - /** - * Internal container de-serializer context. - */ - static class Context { - - /** - * Whether to continue with parsing on this level. - */ - private boolean parse; - - /** - * JSON parser. - */ - private final JsonParser parser; - - /** - * Current de-serialization context. - */ - private final Unmarshaller unmarshallerContext; - - /** - * Creates an instance of parser context. - * - * @param parser JSON parser - * @param parserContext state holder for current json structure level - * @param unmarshallerContext JSON-B unmarshaller - */ - Context(JsonParser parser, Unmarshaller unmarshallerContext) { - this.parser = parser; - this.unmarshallerContext = unmarshallerContext; - this.parse = true; - } - - /** - * Check whether to continue with parsing on this level. - * - * @return parsing shall continue when {@code true} or shall finish when {@code false} - */ - private boolean parse() { - return parse; - } - - /** - * Order parser to finish. - * - * Parser will finish before reading next JSON token. - */ - public void finish() { - this.parse = false; - } - - /** - * Get JSON parser. - * - * @return JSON parser - */ - public JsonParser getParser() { - return parser; - } - - /** - * Get JSON-B unmarshaller. - * - * @return JSON-B unmarshaller - */ - public Unmarshaller getUnmarshallerContext() { - return unmarshallerContext; - } - - } - - /** - * Default property name for map entry key. - */ - private static final String DEFAULT_KEY_ENTRY_NAME = "key"; - - /** - * Default property name for map entry value. - */ - private static final String DEFAULT_VALUE_ENTRY_NAME = "value"; - - /** - * Instance of Map to be returned. - */ - private final Map instance; - - /** - * Type of map key. - */ - private final Type mapKeyType; - - /** - * Type of map value. - */ - private final Type mapValueType; - - /** - * Map entries parser internal state. - */ - private State state; - - /** - * Map entry key. - */ - private K key; - - /** - * Map entry value. - */ - private V value; - - /** - * Property name for map entry key. - */ - private final String keyEntryName; - - /** - * Property name for map entry value. - */ - private final String valueEntryName; - - /** - * Creates an instance of {@code Map} entries array de-serializer. - * - * @param builder de-serializer builder - */ - MapEntriesArrayDeserializer(DeserializerBuilder builder) { - super(builder); - final Type mapType = getRuntimeType(); - this.mapKeyType = ContainerDeserializerUtils.mapKeyType(this, mapType); - this.mapValueType = ContainerDeserializerUtils.mapValueType(this, mapType); - this.instance = ContainerDeserializerUtils.createMapInstance(builder, mapType); - this.state = State.NEXT_ENTRY; - this.keyEntryName = DEFAULT_KEY_ENTRY_NAME; - this.valueEntryName = DEFAULT_VALUE_ENTRY_NAME; - } - - /** - * De-serialize container stored as JSON structure. - * Reads JSON tokens from JSON parser and calls corresponding handler method for each of the tokens. - * Implementing class shall process those tokens and build container instance of {@code T} to be returned. - * - * @param parser JSON parser - * @param context de-serialization context - * @param rtType type of returned instance - * @return {@code Map} instance with content of source JSON structure - */ - @Override - public Map deserialize(final JsonParser parser, DeserializationContext context, Type rtType) { - final Context ctx = new Context(parser, (Unmarshaller) context); - ((JsonbParser) ctx.parser).moveTo(JsonParser.Event.START_ARRAY); - while (parser.hasNext() && ctx.parse()) { - final JsonParser.Event event = parser.next(); - switch (event) { - case START_ARRAY: - startArray(ctx, event); - break; - case START_OBJECT: - startObject(ctx, event); - break; - case KEY_NAME: - keyName(ctx, event); - break; - case VALUE_STRING: - case VALUE_NUMBER: - case VALUE_TRUE: - case VALUE_FALSE: - simpleValue(ctx, event); - break; - case VALUE_NULL: - valueNull(ctx, event); - break; - case END_ARRAY: - endArray(ctx, event); - break; - case END_OBJECT: - endObject(ctx, event); - break; - default: - throw new JsonbException(Messages.getMessage(MessageKeys.NOT_VALUE_TYPE, event)); - } - } - return instance; - } - - /** - * De-serialize JSON structure following beginning of JSON Array ('['). - * - * @param ctx parser context - * @param event JSON parser token (event) - */ - public void startArray(Context ctx, JsonParser.Event event) { - switch (state) { - case ENTRY_KEY_OBJECT: - key = deserializeContent(ctx, mapKeyType, event); - break; - case ENTRY_VALUE_OBJECT: - value = deserializeContent(ctx, mapValueType, event); - break; - default: - handleSyntaxError(state, event); - } - state = State.ENTRY_KEY; - } - - /** - * De-serialize JSON structure following beginning of JSON Object ('{'). - * - * @param ctx parser context - * @param event JSON parser token (event) - */ - private void startObject(Context ctx, JsonParser.Event event) { - switch (state) { - case NEXT_ENTRY: - clearMapEntry(); - break; - case ENTRY_KEY_OBJECT: - key = deserializeContent(ctx, mapKeyType, event); - break; - case ENTRY_VALUE_OBJECT: - value = deserializeContent(ctx, mapValueType, event); - break; - default: - handleSyntaxError(state, event); - } - state = State.ENTRY_KEY; - } - - /** - * De-serialize Map.Entry key values ("key" or "value") and select proper state transition to deserialize - * following key or value data. - * - * @param ctx parser context - * @param event JSON parser token (event) - */ - private void keyName(Context ctx, JsonParser.Event event) { - if (state == State.ENTRY_KEY) { - final String key = ctx.getParser().getString(); - if (keyEntryName.equals(key)) { - state = State.ENTRY_KEY_OBJECT; - } else if (valueEntryName.equals(key)) { - state = State.ENTRY_VALUE_OBJECT; - } else { - throw new JsonbException("Invalid Map entry key: " + key); - } - } else { - handleSyntaxError(state, event); - } - } - - /** - * De-serialize simple JSON value (primitive types, String). - * - * @param ctx parser context - * @param event JSON parser token (event) - */ - private void simpleValue(Context ctx, JsonParser.Event event) { - switch (state) { - case ENTRY_KEY_OBJECT: - key = deserializeContent(ctx, mapKeyType, event); - break; - case ENTRY_VALUE_OBJECT: - value = deserializeContent(ctx, mapValueType, event); - break; - default: - handleSyntaxError(state, event); - } - state = State.ENTRY_KEY; - } - - /** - * De-serialize JSON value {@code null}. - * - * @param ctx parser context - * @param event JSON parser token (event) - */ - private void valueNull(Context ctx, JsonParser.Event event) { - switch (state) { - case ENTRY_KEY_OBJECT: - case ENTRY_VALUE_OBJECT: - break; - default: - handleSyntaxError(state, event); - } - state = State.ENTRY_KEY; - } - - /** - * De-serialize end of JSON Array when '[' character is received. - * This is the last step of Map processing. Reading of JSON tokens from parser on this level shall finish. - * - * @param ctx parser context - * @param event JSON parser token (event) - */ - private void endArray(Context ctx, JsonParser.Event event) { - if (state == State.NEXT_ENTRY) { - ctx.finish(); - } else { - handleSyntaxError(state, event); - } - state = State.ARRAY_END; - } - - /** - * De-serialize end of Map.Entry JSON Object when '{' character is received. - * This is the last step of current Map.Entry processing. - * Key and value data were already processed so they are stored into the Map now. - * - * @param ctx parser context - * @param event JSON parser token (event) - */ - private void endObject(Context ctx, JsonParser.Event event) { - if (state == State.ENTRY_KEY) { - instance.put(key, value); - } else { - handleSyntaxError(state, event); - } - state = State.NEXT_ENTRY; - } - - // It's switch called from switch, but it simplified proper error message selection depending - // on current state and token. - - /** - * Throw more specific exception for map deserialization JSON parser syntax errors. - * - * @param state current state - * @param event current JSON token - */ - private static void handleSyntaxError(State state, JsonParser.Event event) { - switch (state) { - // Error handling for individual states and undefined transition from them. - case NEXT_ENTRY: - throw new JsonbException("Map deserialization error: got " + event.name() - + " when expecting beginning of map entry JSON object or end of whole map entries " - + "array"); - case ENTRY_KEY: - throw new JsonbException("Map deserialization error: got " + event.name() - + " when expecting map entry attribute name 'key' or 'value' or end of map entry " - + "JSON object"); - case ENTRY_KEY_OBJECT: - throw new JsonbException("Map deserialization error: got " + event.name() - + " when expecting map entry attribute value related to target map entry key"); - case ENTRY_VALUE_OBJECT: - throw new JsonbException("Map deserialization error: got " + event.name() - + " when expecting map entry attribute value related to target map entry value"); - // Following cases are theoretically unreachable, but let's have full states list to handle coding error - case ARRAY_END: - throw new JsonbException("Map deserialization error: got " + event.name() - + " when current map deserialization was already finished"); - default: - throw new IllegalStateException("Unknown map deserialization parser state: " + state.name()); - } - } - - /** - * Deserialize key or value content using proper de-serializer. - * - * @param ctx parser context - * @param contentType type of content to be de-serialized - * @param event JSON parser token (event) - * @return de-serialized key or value content to be stored into {@code Map} - */ - @SuppressWarnings("unchecked") - private T deserializeContent(Context ctx, Type contentType, JsonParser.Event event) { - final JsonbDeserializer deserializer = ContainerDeserializerUtils - .newCollectionOrMapItem(this, contentType, ctx.getUnmarshallerContext().getJsonbContext(), event); - return (T) deserializer.deserialize(ctx.getParser(), ctx.getUnmarshallerContext(), contentType); - } - - /** - * Clear internal Map.Entry storage before processing next entry. - */ - private void clearMapEntry() { - key = null; - value = null; - } - -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/MapSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/MapSerializer.java index e5b8d8ef7..9b283fbd3 100644 --- a/src/main/java/org/eclipse/yasson/internal/serializer/MapSerializer.java +++ b/src/main/java/org/eclipse/yasson/internal/serializer/MapSerializer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2021 Oracle and/or its affiliates. All rights reserved. + * 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 @@ -12,237 +12,134 @@ package org.eclipse.yasson.internal.serializer; -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; -import java.util.Iterator; import java.util.Map; -import java.util.Optional; -import jakarta.json.bind.serializer.SerializationContext; import jakarta.json.stream.JsonGenerator; -import org.eclipse.yasson.internal.ReflectionUtils; +import org.eclipse.yasson.internal.SerializationContextImpl; +import org.eclipse.yasson.internal.serializer.types.TypeSerializers; /** - * Serialize {@link Map}. - * - * @param {@link Map} key type to serialize - * @param {@link Map} value type to serialize + * Map container serializer. */ -public class MapSerializer extends AbstractContainerSerializer> implements EmbeddedItem { - - /** - * Internal Map serializing delegate interface. - * - * @param {@link Map} key type to serialize - * @param {@link Map} value type to serialize - */ - interface Delegate { - - /** - * Process container before serialization begins. - * Does nothing by default. - * - * @param obj item to be serialized - */ - default void beforeSerialize(Map obj) { - } +abstract class MapSerializer implements ModelSerializer { - /** - * Write start of an object or an array without a key. - * - * @param generator JSON format generator - */ - void writeStart(JsonGenerator generator); - - /** - * Write start of an object or an array with a key. - * - * @param key JSON key name. - * @param generator JSON format generator - */ - void writeStart(String key, JsonGenerator generator); - - /** - * Writes end of an object or an array. - * - * @param generator JSON format generator - */ - default void writeEnd(JsonGenerator generator) { - generator.writeEnd(); - } + private final ModelSerializer keySerializer; + private final ModelSerializer valueSerializer; - /** - * Serialize content of provided container. - * - * @param obj container to be serialized - * @param generator JSON format generator - * @param ctx JSON serialization context - */ - void serializeContainer(Map obj, JsonGenerator generator, SerializationContext ctx); + MapSerializer(ModelSerializer keySerializer, ModelSerializer valueSerializer) { + this.keySerializer = keySerializer; + this.valueSerializer = valueSerializer; + } + + ModelSerializer getKeySerializer() { + return keySerializer; + } + ModelSerializer getValueSerializer() { + return valueSerializer; } - /** - * Whether to serialize null values too. - */ - private final boolean nullable; - - private final boolean forceMapArraySerializerForNullKeys; - - /** - * Instance that is responsible for serialization. - */ - private Delegate serializer; - - /** - * Flag to know if the process is for the key (0) or the value (1). - */ - private int actualTypeArgument; - - /** - * Creates an instance of {@link Map} serialization. - * - * @param builder current instance of {@link SerializerBuilder} - */ - protected MapSerializer(SerializerBuilder builder) { - super(builder); - actualTypeArgument = 0; - nullable = builder.getJsonbContext().getConfigProperties().getConfigNullable(); - forceMapArraySerializerForNullKeys = builder.getJsonbContext().getConfigProperties().isForceMapArraySerializerForNullKeys(); - serializer = null; + static MapSerializer create(Class keyClass, ModelSerializer keySerializer, ModelSerializer valueSerializer) { + if (TypeSerializers.isSupportedMapKey(keyClass)) { + return new StringKeyMapSerializer(keySerializer, valueSerializer); + } else if (Object.class.equals(keyClass)) { + return new DynamicMapSerializer(keySerializer, valueSerializer); + } + return new ObjectKeyMapSerializer(keySerializer, valueSerializer); } - /** - * Check {@link Map} before serialization. - * Decide whether provided {@link Map} can be serialized as {@code JsonObject} or as {@code JsonArray} of map entries. - * - * @param obj {@link Map} to be serialized - */ - @Override - protected void beforeSerialize(Map obj) { - if (serializer == null) { - // All keys can be serialized as String - boolean allStrings = true; - // if forceMapArraySerializerForNullKeys is set do not allow map serializer on first null - boolean first = !forceMapArraySerializerForNullKeys; - Class cls = null; - // Cycle shall exit on first negative check - for (Iterator i = obj.keySet().iterator(); allStrings && i.hasNext(); ) { - Object key = i.next(); - // 2nd and later pass: check whether all Map keys are of the same type - if (cls != null) { + private static final class DynamicMapSerializer extends MapSerializer { + + private final StringKeyMapSerializer stringMap; + private final ObjectKeyMapSerializer objectMap; + private MapSerializer serializer; + + DynamicMapSerializer(ModelSerializer keySerializer, + ModelSerializer valueSerializer) { + super(keySerializer, valueSerializer); + stringMap = new StringKeyMapSerializer(keySerializer, valueSerializer); + objectMap = new ObjectKeyMapSerializer(keySerializer, valueSerializer); + } + + @SuppressWarnings("unchecked") + @Override + public void serialize(Object value, JsonGenerator generator, SerializationContextImpl context) { + if (serializer == null) { + //We have to be sure that Map with Object as a key contains only supported values for key:value format map. + Map map = (Map) value; + boolean suitable = true; + for (Object key : map.keySet()) { if (key == null) { - allStrings = false; - } else { - allStrings = cls.equals(key.getClass()); + if (context.getJsonbContext().getConfigProperties().isForceMapArraySerializerForNullKeys()) { + suitable = false; + break; + } + continue; } - // 1st pass: check whether key type is supported for Map to JSON Object serialization - } else if (key instanceof String || key instanceof Number || key instanceof Enum) { - cls = key.getClass(); - first = false; - // 1st pass: check whether key is null, which is also supported for Map to JSON Object serialization - // Map shall contain only single mapping for null value and nothing else - } else if (key == null && first) { - first = false; - } else { - allStrings = false; + Class keyClass = key.getClass(); + if (TypeSerializers.isSupportedMapKey(keyClass)) { + continue; + } + //No other checks needed. Map is not suitable for normal key:value map. Wrapping object needs to be used. + suitable = false; + break; } + serializer = suitable ? stringMap : objectMap; } - // Set proper serializing algorithm - if (allStrings) { - serializer = new MapToObjectSerializer<>(this); - } else { - serializer = new MapToEntriesArraySerializer<>(this); - } + serializer.serialize(value, generator, context); } - } - /** - * Serialize content of provided {@link Map}. - * Passing execution to delegate instance. - * - * @param obj {@link Map} to be serialized - * @param generator JSON format generator - * @param ctx JSON serialization context - */ - @Override - protected void serializeInternal(Map obj, JsonGenerator generator, SerializationContext ctx) { - serializer.serializeContainer(obj, generator, ctx); } - /** - * Write start of {@link Map} serialization. - * Passing execution to delegate instance. - * - * @param generator JSON format generator - */ - @Override - protected void writeStart(JsonGenerator generator) { - serializer.writeStart(generator); - } + private static final class StringKeyMapSerializer extends MapSerializer { - /** - * Write start of {@link Map} serialization. - * Passing execution to delegate instance. - * - * @param key JSON key name - * @param generator JSON format generator - */ - @Override - protected void writeStart(String key, JsonGenerator generator) { - serializer.writeStart(key, generator); - } + StringKeyMapSerializer(ModelSerializer keySerializer, + ModelSerializer valueSerializer) { + super(keySerializer, valueSerializer); + } - /** - * Write end of {@link Map} serialization. - * Passing execution to delegate instance. - * - * @param generator JSON format generator - */ - @Override - protected void writeEnd(JsonGenerator generator) { - serializer.writeEnd(generator); - } + @SuppressWarnings("unchecked") + @Override + public void serialize(Object value, JsonGenerator generator, SerializationContextImpl context) { + Map map = (Map) value; + generator.writeStartObject(); + map.forEach((key, val) -> { + getKeySerializer().serialize(key, generator, context); + getValueSerializer().serialize(val, generator, context); + }); + generator.writeEnd(); + } - /** - * Return an information whether to serialize {@code null} values too. - * - * @return {@code null} values shall be serialized too when {@code true} - */ - protected boolean isNullable() { - return nullable; } - /** - * Flag to serialize the key in the map. - */ - protected void serializeKey() { - this.actualTypeArgument = 0; - } + private static final class ObjectKeyMapSerializer extends MapSerializer { - /** - * Flag to serialize the value in the map. - */ - protected void serializeValue() { - this.actualTypeArgument = 1; - } + ObjectKeyMapSerializer(ModelSerializer keySerializer, + ModelSerializer valueSerializer) { + super(keySerializer, valueSerializer); + } - /** - * In a map the type can refer to the key or the value type depending which - * one is currently being processed. The field actualTypeArgument - * controls which one is being serialized at the moment. - * - * @param valueType The value type which should be of type Map<K,V> - * @return The type for the key or the value - */ - @Override - protected Type getValueType(Type valueType) { - if (valueType instanceof ParameterizedType && ((ParameterizedType) valueType).getActualTypeArguments().length > actualTypeArgument) { - Optional runtimeTypeOptional = ReflectionUtils - .resolveOptionalType(this, ((ParameterizedType) valueType).getActualTypeArguments()[actualTypeArgument]); - return runtimeTypeOptional.orElse(Object.class); + @SuppressWarnings("unchecked") + @Override + public void serialize(Object value, JsonGenerator generator, SerializationContextImpl context) { + Map map = (Map) value; + generator.writeStartArray(); + map.forEach((key, val) -> { + generator.writeStartObject(); + generator.writeKey("key"); + if (key == null) { + generator.writeNull(); + } else { + getKeySerializer().serialize(key, generator, context); + } + generator.writeKey("value"); + getValueSerializer().serialize(val, generator, context); + generator.writeEnd(); + }); + generator.writeEnd(); } - return Object.class; + } + } diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/MapToEntriesArraySerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/MapToEntriesArraySerializer.java deleted file mode 100644 index 7feec2603..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/MapToEntriesArraySerializer.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (c) 2019, 2021 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.serializer; - -import java.util.Map; - -import jakarta.json.bind.serializer.SerializationContext; -import jakarta.json.stream.JsonGenerator; - -/** - * Serialize {@link Map} with {@link Object} keys as an array of map entries JSON Objects: - *
- * [
- *     {
- *         "key": JsonValue,
- *         "value": JsonValue
- *     }, ...
- * ]
- * 
- * - * @param {@link Map} key type to serialize - * @param {@link Map} value type to serialize - */ -public class MapToEntriesArraySerializer implements MapSerializer.Delegate { - - /** - * Default {@code JsonObject} property name for map entry key. - */ - private static final String DEFAULT_KEY_ENTRY_NAME = "key"; - - /** - * Default {@code JsonObject} property name for map entry value. - */ - private static final String DEFAULT_VALUE_ENTRY_NAME = "value"; - - /** - * Reference to {@link Map} serialization entry point. Contains serialization setup information. - */ - private final MapSerializer serializer; - - /** - * {@code JsonObject} property name for map entry key. - */ - private final String keyEntryName; - - /** - * {@code JsonObject} property name for map entry value. - */ - private final String valueEntryName; - - /** - * Creates new map to entries array serializer. - * - * @param serializer map serializer - */ - protected MapToEntriesArraySerializer(MapSerializer serializer) { - this.serializer = serializer; - this.keyEntryName = DEFAULT_KEY_ENTRY_NAME; - this.valueEntryName = DEFAULT_VALUE_ENTRY_NAME; - } - - /** - * Write start of {@link Map} serialization. - * Opens {@code JsonArray} block. - * - * @param generator JSON format generator - */ - @Override - public void writeStart(JsonGenerator generator) { - generator.writeStartArray(); - } - - /** - * Write start of {@link Map} serialization. - * Opens {@code JsonArray} block. - * - * @param key JSON key name - * @param generator JSON format generator - */ - @Override - public void writeStart(String key, JsonGenerator generator) { - generator.writeStartArray(); - } - - /** - * Serialize content of provided {@link Map}. - * Content of provided {@link Map} is written into {@code JsonArray} of {@code JsonObject}s representing individual - * map entries. - * - * @param obj {@link Map} to be serialized - * @param generator JSON format generator - * @param ctx JSON serialization context - */ - @Override - public void serializeContainer(Map obj, JsonGenerator generator, SerializationContext ctx) { - obj.forEach((key, value) -> { - generator.writeStartObject(); - generator.writeKey(keyEntryName); - serializer.serializeKey(); - serializer.serializeItem(key, generator, ctx); - generator.writeKey(valueEntryName); - serializer.serializeValue(); - serializer.serializeItem(value, generator, ctx); - generator.writeEnd(); - }); - } - -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/MapToObjectSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/MapToObjectSerializer.java deleted file mode 100644 index f77c46b65..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/MapToObjectSerializer.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (c) 2019, 2021 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.serializer; - -import java.util.Map; - -import jakarta.json.bind.serializer.SerializationContext; -import jakarta.json.stream.JsonGenerator; - -/** - * Serialize {@link Map} with {@link String} keys as JSON Object: - *
- * {
- *     "key1": JsonValue,
- *     "key2": JsonValue,
- *     ...
- * }
- * 
- * - * @param {@link Map} key type to serialize - * @param {@link Map} value type to serialize - */ -public class MapToObjectSerializer implements MapSerializer.Delegate { - - /** - * Reference to {@link Map} serialization entry point. Contains serialization setup information. - */ - private final MapSerializer serializer; - - /** - * Creates an instance of {@link Map} serialization to {@code JsonObject}. - * - * @param serializer reference to {@link Map} serialization entry point - */ - protected MapToObjectSerializer(MapSerializer serializer) { - this.serializer = serializer; - } - - /** - * Write start of {@link Map} serialization. - * Opens {@code JsonObject} block. - * - * @param generator JSON format generator - */ - @Override - public void writeStart(JsonGenerator generator) { - generator.writeStartObject(); - } - - /** - * Write start of {@link Map} serialization. - * Opens {@code JsonObject} block. - * - * @param key JSON key name - * @param generator JSON format generator - */ - @Override - public void writeStart(String key, JsonGenerator generator) { - generator.writeStartObject(key); - } - - /** - * Serialize content of provided {@link Map}. - * Content of provided {@link Map} is written into {@code JsonObject} block. Map keys are written - * as {@code JsonObject} property name {@link String}s. - * - * @param obj {@link Map} to be serialized - * @param generator JSON format generator - * @param ctx JSON serialization context - */ - @Override - public void serializeContainer(Map obj, JsonGenerator generator, SerializationContext ctx) { - for (Map.Entry entry : obj.entrySet()) { - final String keyString; - K key = entry.getKey(); - if (key instanceof Enum) { - keyString = ((Enum) key).name(); - } else { - keyString = String.valueOf(key); - } - final Object value = entry.getValue(); - if (value == null) { - if (serializer.isNullable()) { - generator.writeNull(keyString); - } - continue; - } - generator.writeKey(keyString); - serializer.serializeValue(); - serializer.serializeItem(value, generator, ctx); - } - } - -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/ModelSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/ModelSerializer.java new file mode 100644 index 000000000..60ea4a650 --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/serializer/ModelSerializer.java @@ -0,0 +1,36 @@ +/* + * 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.serializer; + +import jakarta.json.stream.JsonGenerator; + +import org.eclipse.yasson.internal.SerializationContextImpl; + +/** + * Type serializer. + *
+ * All the instances are required to be reusable and without any states + * stored in the class fields. + */ +public interface ModelSerializer { + + /** + * Serialize provided value or delegate serialization to the next serializer. + * + * @param value value to be serialized + * @param generator json generator + * @param context serialization context + */ + void serialize(Object value, JsonGenerator generator, SerializationContextImpl context); + +} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/NullDeserializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/NullDeserializer.java deleted file mode 100644 index 89862c92e..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/NullDeserializer.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2019, 2020 Payara Services 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.serializer; - -import java.lang.reflect.Type; - -import jakarta.json.bind.serializer.DeserializationContext; -import jakarta.json.bind.serializer.JsonbDeserializer; -import jakarta.json.stream.JsonParser; - -/** - * Deserializer of null value. - */ -public enum NullDeserializer implements JsonbDeserializer { - /** - * Singleton of null deserializer. - */ - INSTANCE; - - @Override - public Object deserialize(JsonParser parser, DeserializationContext ctx, Type rtType) { - return null; - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/NullSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/NullSerializer.java index 3ae36a7eb..a94427b71 100644 --- a/src/main/java/org/eclipse/yasson/internal/serializer/NullSerializer.java +++ b/src/main/java/org/eclipse/yasson/internal/serializer/NullSerializer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020 Payara Services and/or its affiliates. All rights reserved. + * 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 @@ -13,15 +13,88 @@ package org.eclipse.yasson.internal.serializer; import jakarta.json.bind.serializer.JsonbSerializer; -import jakarta.json.bind.serializer.SerializationContext; import jakarta.json.stream.JsonGenerator; +import org.eclipse.yasson.internal.JsonbContext; +import org.eclipse.yasson.internal.SerializationContextImpl; +import org.eclipse.yasson.internal.model.customization.Customization; + /** - * Serializer of null value. + * Null value serializer. Determines proper behavior when the serialized value is null. */ -public class NullSerializer implements JsonbSerializer { +public class NullSerializer implements ModelSerializer { + + private final ModelSerializer delegate; + private final ModelSerializer nullSerializer; + private final ModelSerializer rootNullSerializer; + + /** + * Create new instance. + * + * @param delegate non-null value delegate + * @param customization component customization + * @param jsonbContext jsonb context + */ + public NullSerializer(ModelSerializer delegate, + Customization customization, + JsonbContext jsonbContext) { + this.delegate = delegate; + if (customization.isNillable()) { + nullSerializer = new NullWritingEnabled(); + } else { + nullSerializer = new NullWritingDisabled(); + } + JsonbSerializer userDefinedNullSerializer = jsonbContext.getConfigProperties().getNullSerializer(); + if (userDefinedNullSerializer != null) { + rootNullSerializer = (value, generator, context) -> userDefinedNullSerializer.serialize(null, generator, context); + } else { + rootNullSerializer = nullSerializer; + } + } + @Override - public void serialize(Object obj, JsonGenerator generator, SerializationContext ctx) { - generator.writeNull(); + public void serialize(Object value, JsonGenerator generator, SerializationContextImpl context) { + if (value == null) { + if (context.isRoot()) { + context.setRoot(false); + rootNullSerializer.serialize(null, generator, context); + } else { + nullSerializer.serialize(null, generator, context); + } + context.setKey(null); + } else { + context.setRoot(false); + delegate.serialize(value, generator, context); + } + } + + private static final class NullWritingEnabled implements ModelSerializer { + + @Override + public void serialize(Object value, JsonGenerator generator, SerializationContextImpl context) { + if (context.getKey() == null) { + generator.writeNull(); + } else { + generator.writeNull(context.getKey()); + } + } + + } + + private static class NullWritingDisabled implements ModelSerializer { + + @Override + public void serialize(Object value, JsonGenerator generator, SerializationContextImpl context) { + if (context.isContainerWithNulls()) { + if (context.getKey() == null) { + generator.writeNull(); + } else { + generator.writeNull(context.getKey()); + } + } + context.setKey(null); + //Do nothing + } + } } diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/NullVisibilitySwitcher.java b/src/main/java/org/eclipse/yasson/internal/serializer/NullVisibilitySwitcher.java new file mode 100644 index 000000000..618961aa3 --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/serializer/NullVisibilitySwitcher.java @@ -0,0 +1,43 @@ +/* + * 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.serializer; + +import jakarta.json.stream.JsonGenerator; + +import org.eclipse.yasson.internal.SerializationContextImpl; + +/** + * Switching mechanism for default null value visibility in the JSON. + * + * Some constructs such as arrays, collections etc. require to have nulls serialized into the JSON by default. + * This class switches from the default parent null visibility to the current construct visibility. As soon as the current + * construct is serialized, visibility is switched back to the parent ones. + */ +class NullVisibilitySwitcher implements ModelSerializer { + + private final boolean nullsEnabled; + private final ModelSerializer delegate; + + NullVisibilitySwitcher(boolean nullsEnabled, ModelSerializer delegate) { + this.nullsEnabled = nullsEnabled; + this.delegate = delegate; + } + + @Override + public void serialize(Object value, JsonGenerator generator, SerializationContextImpl context) { + boolean previous = context.isContainerWithNulls(); + context.setContainerWithNulls(nullsEnabled); + delegate.serialize(value, generator, context); + context.setContainerWithNulls(previous); + } +} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/NumberTypeDeserializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/NumberTypeDeserializer.java deleted file mode 100644 index c7f3175b5..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/NumberTypeDeserializer.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import java.lang.reflect.Type; -import java.math.BigDecimal; - -import org.eclipse.yasson.internal.Unmarshaller; -import org.eclipse.yasson.internal.model.customization.Customization; - -/** - * Deserializer for {@link Number} type. - */ -public class NumberTypeDeserializer extends AbstractValueTypeDeserializer { - - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public NumberTypeDeserializer(Customization customization) { - super(Number.class, customization); - } - - @Override - protected Number deserialize(String jsonValue, Unmarshaller unmarshaller, Type rtType) { - return new BigDecimal(jsonValue); - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/NumberTypeSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/NumberTypeSerializer.java deleted file mode 100644 index c5c0182b8..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/NumberTypeSerializer.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import java.math.BigDecimal; - -import jakarta.json.stream.JsonGenerator; - -import org.eclipse.yasson.internal.Marshaller; -import org.eclipse.yasson.internal.model.customization.Customization; - -/** - * Serializer for {@link Number} type. - */ -public class NumberTypeSerializer extends AbstractValueTypeSerializer { - - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public NumberTypeSerializer(Customization customization) { - super(customization); - } - - @Override - protected void serialize(Number obj, JsonGenerator generator, Marshaller marshaller) { - BigDecimal bigDecimalValue = new BigDecimal(String.valueOf(obj)); - generator.write(bigDecimalValue); - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/ObjectArrayDeserializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/ObjectArrayDeserializer.java deleted file mode 100644 index 9cbdd147e..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/ObjectArrayDeserializer.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2015, 2020 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.serializer; - -import java.lang.reflect.Array; -import java.util.ArrayList; -import java.util.List; - -import org.eclipse.yasson.internal.Unmarshaller; - -/** - * Item for handling arrays of objects. - * - * @param object type - */ -public class ObjectArrayDeserializer extends AbstractArrayDeserializer { - - private final List items = new ArrayList<>(); - - private T[] arrayInstance; - - /** - * Creates new instance of object array deserializer. - * - * @param builder deserializer builder - */ - protected ObjectArrayDeserializer(DeserializerBuilder builder) { - super(builder); - } - - @Override - protected List getItems() { - return items; - } - - @SuppressWarnings("unchecked") - @Override - public T[] getInstance(Unmarshaller unmarshaller) { - if (arrayInstance == null || arrayInstance.length != items.size()) { - arrayInstance = (T[]) Array.newInstance(getComponentClass(), items.size()); - } - return items.toArray(arrayInstance); - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/ObjectArraySerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/ObjectArraySerializer.java deleted file mode 100644 index 5f9434b00..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/ObjectArraySerializer.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import jakarta.json.bind.serializer.SerializationContext; -import jakarta.json.stream.JsonGenerator; - -/** - * Serializer for arrays of arbitrary objects. - * - * @param object type - */ -public class ObjectArraySerializer extends AbstractArraySerializer { - - /** - * Creates new Object array serializer. - * - * @param builder serialization builder - */ - protected ObjectArraySerializer(SerializerBuilder builder) { - super(builder); - } - - @Override - protected void serializeInternal(T[] arr, JsonGenerator generator, SerializationContext ctx) { - for (T obj : arr) { - serializeItem(obj, generator, ctx); - } - } - -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/ObjectDeserializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/ObjectDeserializer.java deleted file mode 100644 index 2d2e7cb89..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/ObjectDeserializer.java +++ /dev/null @@ -1,247 +0,0 @@ -/* - * Copyright (c) 2015, 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.serializer; - -import java.lang.reflect.Constructor; -import java.lang.reflect.Type; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - -import jakarta.json.bind.JsonbException; -import jakarta.json.bind.serializer.JsonbDeserializer; -import jakarta.json.stream.JsonParser; - -import org.eclipse.yasson.internal.ClassMultiReleaseExtension; -import org.eclipse.yasson.internal.JsonbContext; -import org.eclipse.yasson.internal.JsonbParser; -import org.eclipse.yasson.internal.JsonbRiParser; -import org.eclipse.yasson.internal.ReflectionUtils; -import org.eclipse.yasson.internal.Unmarshaller; -import org.eclipse.yasson.internal.model.CreatorModel; -import org.eclipse.yasson.internal.model.JsonbCreator; -import org.eclipse.yasson.internal.model.PropertyModel; -import org.eclipse.yasson.internal.properties.MessageKeys; -import org.eclipse.yasson.internal.properties.Messages; - -/** - * Item for handling all types of unknown objects by reflection, parsing their fields, according to json key name. - * - * @param object type - */ -class ObjectDeserializer extends AbstractContainerDeserializer { - - /** - * Last property model cache to avoid lookup by jsonKey on every access. - */ - private static class LastPropertyModel { - - private final String jsonKeyName; - private final PropertyModel propertyModel; - - LastPropertyModel(String jsonKeyName, PropertyModel propertyModel) { - this.jsonKeyName = jsonKeyName; - this.propertyModel = propertyModel; - } - - public String getJsonKeyName() { - return jsonKeyName; - } - - public PropertyModel getPropertyModel() { - return propertyModel; - } - } - - private Map values = new LinkedHashMap<>(); - - private T instance; - - private LastPropertyModel lastPropertyModel; - - /** - * Creates instance of an item. - * - * @param builder builder to build from - */ - protected ObjectDeserializer(DeserializerBuilder builder) { - super(builder); - } - - /** - * Due to support of custom (parametrized) constructors and factory methods, values are held in map, - * which is transferred into instance values by calling getInstance. - * - * @param unmarshaller Current deserialization context. - * @return An instance of deserializing item. - */ - @Override - @SuppressWarnings("unchecked") - public T getInstance(Unmarshaller unmarshaller) { - if (instance != null) { - return instance; - } - final Class rawType = ReflectionUtils.getRawType(getRuntimeType()); - final JsonbCreator creator = getClassModel().getClassCustomization().getCreator(); - if (creator != null) { - instance = createInstance((Class) rawType, creator); - } else { - Constructor defaultConstructor = (Constructor) getClassModel().getDefaultConstructor(); - if (defaultConstructor == null) { - throw ClassMultiReleaseExtension.exceptionToThrow(rawType) - .orElse(new JsonbException(Messages.getMessage(MessageKeys.NO_DEFAULT_CONSTRUCTOR, rawType))); - } - instance = ReflectionUtils.createNoArgConstructorInstance(defaultConstructor); - } - //values must be set in order, in which they appears in JSON by spec - values.forEach((key, wrapper) -> { - //skip creator values - if (wrapper.getCreatorModel() != null) { - return; - } - final PropertyModel propertyModel = wrapper.getPropertyModel(); - propertyModel.setValue(instance, wrapper.getValue()); - }); - - return instance; - } - - /** - * Creates instance with custom jsonb creator (parameterized constructor or factory method). - */ - private T createInstance(Class rawType, JsonbCreator creator) { - final T instance; - final List paramValues = new ArrayList<>(); - for (CreatorModel param : creator.getParams()) { - final ValueWrapper valueWrapper = values.get(param.getName()); - //required by spec - if (valueWrapper == null) { - throw new JsonbException(Messages.getMessage(MessageKeys.JSONB_CREATOR_MISSING_PROPERTY, param.getName())); - } - paramValues.add(valueWrapper.getValue()); - } - instance = creator.call(paramValues.toArray(), rawType); - return instance; - } - - /** - * Set populated instance of current object to its unfinished wrapper values map. - * - * @param result An instance result of an item. - * @param context Current unmarshalling context. - */ - @Override - public void appendResult(Object result, Unmarshaller context) { - final PropertyModel model = getModel(); - //missing property for null values - if (model == null) { - return; - } - values.put(model.getReadName(), - new ValueWrapper(model, convertNullToOptionalEmpty(model.getPropertyDeserializationType(), result))); - } - - @Override - protected void deserializeNext(JsonParser parser, Unmarshaller context) { - - final JsonbCreator creator = getClassModel().getClassCustomization().getCreator(); - //first check jsonb creator param, since it can be different from property name - if (creator != null) { - final CreatorModel param = creator.findByName(getParserContext().getLastKeyName()); - if (param != null) { - final JsonbDeserializer deserializer = newUnmarshallerItemBuilder(context.getJsonbContext()) - .withType(param.getType()) - .withCustomization(param.getCustomization()) - .build(); - Object result = deserializer.deserialize(parser, context, param.getType()); - values.put(param.getName(), new ValueWrapper(param, result)); - return; - } - } - - //identify field model of currently processed class model - PropertyModel newPropertyModel = getModel(); - if (newPropertyModel != null && newPropertyModel.isWritable()) { - //create current item instance of identified object field - final JsonbDeserializer deserializer = newUnmarshallerItemBuilder(context.getJsonbContext()) - .withCustomization(newPropertyModel.getCustomization()) - .withType(newPropertyModel.getPropertyDeserializationType()) - .build(); - - Type resolvedType = ReflectionUtils.resolveType(this, newPropertyModel.getPropertyDeserializationType()); - Object result = deserializer.deserialize(parser, context, resolvedType); - values.put(newPropertyModel.getPropertyName(), new ValueWrapper(newPropertyModel, result)); - return; - } - skipJsonProperty((JsonbParser) parser, context.getJsonbContext()); - } - - /** - * Rise an exception, or ignore JSON property, which is missing in class model. - */ - private void skipJsonProperty(JsonbParser parser, JsonbContext jsonbContext) { - if (jsonbContext.getConfigProperties().getConfigFailOnUnknownProperties()) { - throw new JsonbException(Messages.getMessage(MessageKeys.UNKNOWN_JSON_PROPERTY, - getParserContext().getLastKeyName(), - getRuntimeType())); - } - parser.skipJsonStructure(); - } - - @Override - protected JsonbRiParser.LevelContext moveToFirst(JsonbParser parser) { - parser.moveTo(JsonParser.Event.START_OBJECT); - return parser.getCurrentLevel(); - } - - protected PropertyModel getModel() { - final String lastKeyName = getParserContext().getLastKeyName(); - if (lastPropertyModel != null && lastPropertyModel.getJsonKeyName().equals(lastKeyName)) { - return lastPropertyModel.getPropertyModel(); - } - lastPropertyModel = new LastPropertyModel(lastKeyName, getClassModel().findPropertyModelByJsonReadName(lastKeyName)); - return lastPropertyModel.getPropertyModel(); - } - - private static class ValueWrapper { - - private final CreatorModel creatorModel; - private final PropertyModel propertyModel; - private final Object value; - - ValueWrapper(CreatorModel creator, Object value) { - this.creatorModel = creator; - this.value = value; - propertyModel = null; - } - - ValueWrapper(PropertyModel propertyModel, Object value) { - this.propertyModel = propertyModel; - this.value = value; - creatorModel = null; - } - - public CreatorModel getCreatorModel() { - return creatorModel; - } - - public PropertyModel getPropertyModel() { - return propertyModel; - } - - public Object getValue() { - return value; - } - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/ObjectSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/ObjectSerializer.java index 94d6a6e4a..336a7824d 100644 --- a/src/main/java/org/eclipse/yasson/internal/serializer/ObjectSerializer.java +++ b/src/main/java/org/eclipse/yasson/internal/serializer/ObjectSerializer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2020 Oracle and/or its affiliates. All rights reserved. + * 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 @@ -12,127 +12,38 @@ package org.eclipse.yasson.internal.serializer; -import java.lang.reflect.Type; -import java.util.Optional; -import java.util.OptionalDouble; -import java.util.OptionalInt; -import java.util.OptionalLong; +import java.util.LinkedHashMap; import jakarta.json.bind.JsonbException; -import jakarta.json.bind.serializer.JsonbSerializer; -import jakarta.json.bind.serializer.SerializationContext; import jakarta.json.stream.JsonGenerator; -import org.eclipse.yasson.internal.Marshaller; -import org.eclipse.yasson.internal.ReflectionUtils; -import org.eclipse.yasson.internal.model.ClassModel; -import org.eclipse.yasson.internal.model.PropertyModel; +import org.eclipse.yasson.internal.SerializationContextImpl; import org.eclipse.yasson.internal.properties.MessageKeys; import org.eclipse.yasson.internal.properties.Messages; /** - * Serializes arbitrary object by reading its properties. - * - * @param object type + * Object container serializer. */ -public class ObjectSerializer extends AbstractContainerSerializer { +class ObjectSerializer implements ModelSerializer { - /** - * Creates a new instance. - * - * @param builder Builder to initialize the instance. - */ - public ObjectSerializer(SerializerBuilder builder) { - super(builder); - } + private final LinkedHashMap propertySerializers; - /** - * Creates a new instance. - * - * @param wrapper wrapped item - * @param runtimeType class type - * @param classModel model of the class - */ - public ObjectSerializer(CurrentItem wrapper, Type runtimeType, ClassModel classModel) { - super(wrapper, runtimeType, classModel); - } - - @Override - protected void serializeInternal(T object, JsonGenerator generator, SerializationContext ctx) { - Marshaller context = (Marshaller) ctx; - try { - if (context.addProcessedObject(object)) { - final PropertyModel[] allProperties = context.getMappingContext().getOrCreateClassModel(object.getClass()) - .getSortedProperties(); - for (PropertyModel model : allProperties) { - try { - marshallProperty(object, generator, context, model); - } catch (Exception e) { - throw new JsonbException(Messages.getMessage(MessageKeys.SERIALIZE_PROPERTY_ERROR, model.getWriteName(), - object.getClass().getCanonicalName()), e); - } - } - } else { - throw new JsonbException(Messages.getMessage(MessageKeys.RECURSIVE_REFERENCE, object.getClass())); - } - } finally { - context.removeProcessedObject(object); - } + ObjectSerializer(LinkedHashMap propertySerializers) { + this.propertySerializers = propertySerializers; } @Override - protected void writeStart(JsonGenerator generator) { + public void serialize(Object value, JsonGenerator generator, SerializationContextImpl context) { generator.writeStartObject(); - } - - @Override - protected void writeStart(String key, JsonGenerator generator) { - generator.writeStartObject(key); - } - - private void marshallProperty(T object, JsonGenerator generator, SerializationContext ctx, PropertyModel propertyModel) { - Marshaller marshaller = (Marshaller) ctx; - - if (propertyModel.isReadable()) { - final Object propertyValue = propertyModel.getValue(object); - if (propertyValue == null || isEmptyOptional(propertyValue)) { - if (propertyModel.getCustomization().isNillable()) { - generator.writeNull(propertyModel.getWriteName()); - } - return; - } - - generator.writeKey(propertyModel.getWriteName()); - - final JsonbSerializer propertyCachedSerializer = propertyModel.getPropertySerializer(); - if (propertyCachedSerializer != null) { - serializerCaptor(propertyCachedSerializer, propertyValue, generator, ctx); - return; + propertySerializers.forEach((key, serializer) -> { + try { + context.setKey(key); + serializer.serialize(value, generator, context); + } catch (Exception e) { + throw new JsonbException(Messages.getMessage(MessageKeys.SERIALIZE_PROPERTY_ERROR, key, + value.getClass().getCanonicalName()), e); } - - Optional runtimeTypeOptional = ReflectionUtils - .resolveOptionalType(this, propertyModel.getPropertySerializationType()); - Type genericType = runtimeTypeOptional.orElse(null); - final JsonbSerializer serializer = new SerializerBuilder(marshaller.getJsonbContext()) - .withWrapper(this) - .withObjectClass(propertyValue.getClass()) - .withCustomization(propertyModel.getCustomization()) - .withType(genericType).build(); - serializerCaptor(serializer, propertyValue, generator, ctx); - } - } - - private boolean isEmptyOptional(Object object) { - if (object instanceof Optional) { - return !((Optional) object).isPresent(); - } else if (object instanceof OptionalInt) { - return !((OptionalInt) object).isPresent(); - } else if (object instanceof OptionalLong) { - return !((OptionalLong) object).isPresent(); - } else if (object instanceof OptionalDouble) { - return !((OptionalDouble) object).isPresent(); - } - return false; + }); + generator.writeEnd(); } - } diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/ObjectSerializerProvider.java b/src/main/java/org/eclipse/yasson/internal/serializer/ObjectSerializerProvider.java deleted file mode 100644 index da86017dd..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/ObjectSerializerProvider.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import jakarta.json.bind.serializer.JsonbSerializer; - -import org.eclipse.yasson.internal.model.JsonbPropertyInfo; - -/** - * Object serializer provider. - */ -public class ObjectSerializerProvider implements ContainerSerializerProvider { - - @Override - public JsonbSerializer provideSerializer(JsonbPropertyInfo propertyInfo) { - return new ObjectSerializer<>(propertyInfo.getWrapper(), propertyInfo.getRuntimeType(), propertyInfo.getClassModel()); - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/OptionalDoubleTypeDeserializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/OptionalDoubleTypeDeserializer.java deleted file mode 100644 index 7b6d6ec07..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/OptionalDoubleTypeDeserializer.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2016, 2020 Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2019, 2020 Payara Foundation 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.serializer; - -import java.lang.reflect.Type; -import java.util.OptionalDouble; - -import jakarta.json.bind.JsonbException; -import jakarta.json.bind.serializer.DeserializationContext; -import jakarta.json.stream.JsonParser; - -import org.eclipse.yasson.internal.JsonbParser; -import org.eclipse.yasson.internal.Unmarshaller; -import org.eclipse.yasson.internal.model.customization.Customization; -import org.eclipse.yasson.internal.properties.MessageKeys; -import org.eclipse.yasson.internal.properties.Messages; - -/** - * Deserializer for {@link OptionalDouble} type. - */ -public class OptionalDoubleTypeDeserializer extends AbstractValueTypeDeserializer { - - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public OptionalDoubleTypeDeserializer(Customization customization) { - super(OptionalDouble.class, customization); - } - - @Override - public OptionalDouble deserialize(JsonParser parser, DeserializationContext ctx, Type rtType) { - final JsonParser.Event next = ((JsonbParser) parser).moveToValue(); - if (next == JsonParser.Event.VALUE_NULL) { - return OptionalDouble.empty(); - } - String value = parser.getString(); - return deserialize(value, (Unmarshaller) ctx, rtType); - } - - @Override - protected OptionalDouble deserialize(String jsonValue, Unmarshaller unmarshaller, Type rtType) { - try { - return OptionalDouble.of(Double.parseDouble(jsonValue)); - } catch (NumberFormatException e) { - throw new JsonbException(Messages.getMessage(MessageKeys.DESERIALIZE_VALUE_ERROR, OptionalDouble.class)); - } - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/OptionalDoubleTypeSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/OptionalDoubleTypeSerializer.java deleted file mode 100644 index d2d8e1e44..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/OptionalDoubleTypeSerializer.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2016, 2020 Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2019, 2020 Payara Foundation 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.serializer; - -import java.util.OptionalDouble; - -import jakarta.json.stream.JsonGenerator; - -import org.eclipse.yasson.internal.Marshaller; -import org.eclipse.yasson.internal.model.customization.Customization; - -import static org.eclipse.yasson.internal.serializer.OptionalObjectSerializer.handleEmpty; - -/** - * Serializer for {@link OptionalDouble} type. - */ -public class OptionalDoubleTypeSerializer extends AbstractValueTypeSerializer { - - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public OptionalDoubleTypeSerializer(Customization customization) { - super(customization); - } - - @Override - protected void serialize(OptionalDouble obj, JsonGenerator generator, Marshaller marshaller) { - if (!handleEmpty(obj, OptionalDouble::isPresent, getCustomization(), generator, marshaller)) { - generator.write(obj.getAsDouble()); - } - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/OptionalIntTypeDeserializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/OptionalIntTypeDeserializer.java deleted file mode 100644 index 3611fa8e2..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/OptionalIntTypeDeserializer.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import java.lang.reflect.Type; -import java.util.OptionalInt; - -import jakarta.json.bind.JsonbException; -import jakarta.json.bind.serializer.DeserializationContext; -import jakarta.json.stream.JsonParser; - -import org.eclipse.yasson.internal.JsonbParser; -import org.eclipse.yasson.internal.Unmarshaller; -import org.eclipse.yasson.internal.model.customization.Customization; -import org.eclipse.yasson.internal.properties.MessageKeys; -import org.eclipse.yasson.internal.properties.Messages; - -/** - * Deserializer for {@link OptionalInt} type. - */ -public class OptionalIntTypeDeserializer extends AbstractValueTypeDeserializer { - - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public OptionalIntTypeDeserializer(Customization customization) { - super(OptionalInt.class, customization); - } - - @Override - public OptionalInt deserialize(JsonParser parser, DeserializationContext ctx, Type rtType) { - final JsonParser.Event next = ((JsonbParser) parser).moveToValue(); - if (next == JsonParser.Event.VALUE_NULL) { - return OptionalInt.empty(); - } - final String value = parser.getString(); - return deserialize(value, (Unmarshaller) ctx, rtType); - } - - @Override - protected OptionalInt deserialize(String jsonValue, Unmarshaller unmarshaller, Type rtType) { - try { - return OptionalInt.of(Integer.parseInt(jsonValue)); - } catch (NumberFormatException e) { - throw new JsonbException(Messages.getMessage(MessageKeys.DESERIALIZE_VALUE_ERROR, OptionalInt.class)); - } - } - -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/OptionalIntTypeSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/OptionalIntTypeSerializer.java deleted file mode 100644 index a3c6b891f..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/OptionalIntTypeSerializer.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2016, 2020 Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2019, 2020 Payara Foundation 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.serializer; - -import java.util.OptionalInt; - -import jakarta.json.stream.JsonGenerator; - -import org.eclipse.yasson.internal.Marshaller; -import org.eclipse.yasson.internal.model.customization.Customization; - -import static org.eclipse.yasson.internal.serializer.OptionalObjectSerializer.handleEmpty; - -/** - * Serializer for {@link OptionalInt} type. - */ -public class OptionalIntTypeSerializer extends AbstractValueTypeSerializer { - - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public OptionalIntTypeSerializer(Customization customization) { - super(customization); - } - - @Override - protected void serialize(OptionalInt obj, JsonGenerator generator, Marshaller marshaller) { - if (!handleEmpty(obj, OptionalInt::isPresent, getCustomization(), generator, marshaller)) { - generator.write(obj.getAsInt()); - } - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/OptionalLongTypeDeserializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/OptionalLongTypeDeserializer.java deleted file mode 100644 index 65cce3f1d..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/OptionalLongTypeDeserializer.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import java.lang.reflect.Type; -import java.util.OptionalLong; - -import jakarta.json.bind.JsonbException; -import jakarta.json.bind.serializer.DeserializationContext; -import jakarta.json.stream.JsonParser; - -import org.eclipse.yasson.internal.JsonbParser; -import org.eclipse.yasson.internal.Unmarshaller; -import org.eclipse.yasson.internal.model.customization.Customization; -import org.eclipse.yasson.internal.properties.MessageKeys; -import org.eclipse.yasson.internal.properties.Messages; - -/** - * Deserializer for {@link OptionalLong} type. - */ -public class OptionalLongTypeDeserializer extends AbstractValueTypeDeserializer { - - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public OptionalLongTypeDeserializer(Customization customization) { - super(OptionalLong.class, customization); - } - - @Override - public OptionalLong deserialize(JsonParser parser, DeserializationContext ctx, Type rtType) { - final JsonParser.Event next = ((JsonbParser) parser).moveToValue(); - if (next == JsonParser.Event.VALUE_NULL) { - return OptionalLong.empty(); - } - return deserialize(parser.getString(), (Unmarshaller) ctx, rtType); - } - - @Override - protected OptionalLong deserialize(String jsonValue, Unmarshaller unmarshaller, Type rtType) { - try { - return OptionalLong.of(Long.parseLong(jsonValue)); - } catch (NumberFormatException e) { - throw new JsonbException(Messages.getMessage(MessageKeys.DESERIALIZE_VALUE_ERROR, OptionalLong.class)); - } - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/OptionalLongTypeSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/OptionalLongTypeSerializer.java deleted file mode 100644 index d05ce4a7d..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/OptionalLongTypeSerializer.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2016, 2020 Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2019, 2020 Payara Foundation 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.serializer; - -import java.util.OptionalLong; - -import jakarta.json.stream.JsonGenerator; - -import org.eclipse.yasson.internal.Marshaller; -import org.eclipse.yasson.internal.model.customization.Customization; - -import static org.eclipse.yasson.internal.serializer.OptionalObjectSerializer.handleEmpty; - -/** - * Serializer for {@link OptionalLong} type. - */ -public class OptionalLongTypeSerializer extends AbstractValueTypeSerializer { - - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public OptionalLongTypeSerializer(Customization customization) { - super(customization); - } - - @Override - protected void serialize(OptionalLong obj, JsonGenerator generator, Marshaller marshaller) { - if (!handleEmpty(obj, OptionalLong::isPresent, getCustomization(), generator, marshaller)) { - generator.write(obj.getAsLong()); - } - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/OptionalObjectDeserializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/OptionalObjectDeserializer.java deleted file mode 100644 index cda711c39..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/OptionalObjectDeserializer.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2016, 2020 Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2019, 2020 Payara Foundation 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.serializer; - -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; -import java.util.Optional; - -import jakarta.json.bind.serializer.DeserializationContext; -import jakarta.json.bind.serializer.JsonbDeserializer; -import jakarta.json.stream.JsonParser; - -import org.eclipse.yasson.internal.JsonbContext; -import org.eclipse.yasson.internal.JsonbParser; -import org.eclipse.yasson.internal.ProcessingContext; - -/** - * Deserialize optional object. - */ -public class OptionalObjectDeserializer implements JsonbDeserializer> { - - private final CurrentItem wrapper; - - private final Type optionalValueType; - - /** - * Creates new optional object deserializer. - * - * @param deserializerBuilder deserializer builder - */ - public OptionalObjectDeserializer(DeserializerBuilder deserializerBuilder) { - this.wrapper = deserializerBuilder.getWrapper(); - this.optionalValueType = resolveOptionalType(deserializerBuilder.getRuntimeType()); - } - - @Override - public Optional deserialize(JsonParser parser, DeserializationContext ctx, Type rtType) { - JsonbContext jsonbContext = ((ProcessingContext) ctx).getJsonbContext(); - final JsonParser.Event lastEvent = ((JsonbParser) parser).getCurrentLevel().getLastEvent(); - if (lastEvent == JsonParser.Event.VALUE_NULL) { - return Optional.empty(); - } - JsonbDeserializer deserializer = new DeserializerBuilder(jsonbContext).withType(optionalValueType) - .withWrapper(wrapper).withJsonValueType(lastEvent).build(); - return Optional.of(deserializer.deserialize(parser, ctx, optionalValueType)); - } - - private Type resolveOptionalType(Type runtimeType) { - if (runtimeType instanceof ParameterizedType) { - return ((ParameterizedType) runtimeType).getActualTypeArguments()[0]; - } - return Object.class; - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/OptionalObjectSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/OptionalObjectSerializer.java deleted file mode 100644 index bd6499549..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/OptionalObjectSerializer.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright (c) 2016, 2020 Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2019, 2020 Payara Foundation 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.serializer; - -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; -import java.util.Optional; -import java.util.function.Predicate; - -import jakarta.json.bind.serializer.JsonbSerializer; -import jakarta.json.bind.serializer.SerializationContext; -import jakarta.json.stream.JsonGenerator; - -import org.eclipse.yasson.internal.JsonbContext; -import org.eclipse.yasson.internal.Marshaller; -import org.eclipse.yasson.internal.ProcessingContext; -import org.eclipse.yasson.internal.model.ClassModel; -import org.eclipse.yasson.internal.model.customization.Customization; - -/** - * Common serializer logic for java Optionals. - * - * @param instantiated Optional type - */ -public class OptionalObjectSerializer> implements CurrentItem, JsonbSerializer { - private final Customization customization; - - private final CurrentItem wrapper; - - private final Type optionalValueType; - - /** - * Creates a new instance. - * - * @param builder Builder to initialize the instance. - */ - public OptionalObjectSerializer(SerializerBuilder builder) { - this.wrapper = builder.getWrapper(); - this.customization = builder.getCustomization(); - this.optionalValueType = resolveOptionalType(builder.getRuntimeType()); - } - - private Type resolveOptionalType(Type runtimeType) { - if (runtimeType instanceof ParameterizedType) { - return ((ParameterizedType) runtimeType).getActualTypeArguments()[0]; - } - return Object.class; - } - - @Override - public ClassModel getClassModel() { - return null; - } - - @Override - public CurrentItem getWrapper() { - return wrapper; - } - - @Override - public Type getRuntimeType() { - return optionalValueType; - } - - public Customization getCustomization() { - return customization; - } - - @Override - public void serialize(T obj, JsonGenerator generator, SerializationContext ctx) { - JsonbContext jsonbContext = ((ProcessingContext) ctx).getJsonbContext(); - if (handleEmpty(obj, Optional::isPresent, customization, generator, (Marshaller) ctx)) { - return; - } - Object optionalValue = obj.get(); - final JsonbSerializer serializer = new SerializerBuilder(jsonbContext).withObjectClass(optionalValue.getClass()) - .withType(optionalValueType).withWrapper(wrapper).withCustomization(customization).build(); - serialCaptor(serializer, optionalValue, generator, ctx); - } - - static boolean handleEmpty(T value, - Predicate presentCheck, - Customization customization, - JsonGenerator generator, - Marshaller marshaller) { - if (value == null || !presentCheck.test(value)) { - if (customization != null) { - if (customization.isNillable()) { - generator.writeNull(); - return true; - } - } else { - marshaller.getJsonbContext().getConfigProperties().getNullSerializer().serialize(value, generator, marshaller); - } - return true; - } else { - return false; - } - } - - @SuppressWarnings("unchecked") - private void serialCaptor(JsonbSerializer serializer, - T object, - JsonGenerator generator, - SerializationContext context) { - ((JsonbSerializer) serializer).serialize(object, generator, context); - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/OptionalSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/OptionalSerializer.java new file mode 100644 index 000000000..1b6ecf38c --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/serializer/OptionalSerializer.java @@ -0,0 +1,39 @@ +/* + * 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.serializer; + +import java.util.Optional; + +import jakarta.json.stream.JsonGenerator; + +import org.eclipse.yasson.internal.SerializationContextImpl; + +/** + * Optional container serializer. + */ +class OptionalSerializer implements ModelSerializer { + + private final ModelSerializer delegate; + + OptionalSerializer(ModelSerializer delegate) { + this.delegate = delegate; + } + + @SuppressWarnings("unchecked") + @Override + public void serialize(Object value, JsonGenerator generator, SerializationContextImpl context) { + Optional optional = (Optional) value; + delegate.serialize(optional.orElse(null), generator, context); + } + +} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/PathTypeDeserializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/PathTypeDeserializer.java deleted file mode 100644 index 87d231a8e..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/PathTypeDeserializer.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2020 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 - * 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.serializer; - -import java.lang.reflect.Type; -import java.nio.file.Path; -import java.nio.file.Paths; - -import org.eclipse.yasson.internal.Unmarshaller; -import org.eclipse.yasson.internal.model.customization.Customization; - -public class PathTypeDeserializer extends AbstractValueTypeDeserializer { - public PathTypeDeserializer(Customization customization) { - super(Path.class, customization); - } - - @Override - protected Path deserialize(String jsonValue, Unmarshaller unmarshaller, Type rtType) { - return Paths.get(jsonValue); - } -} \ No newline at end of file diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/PathTypeSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/PathTypeSerializer.java deleted file mode 100644 index 4455e282d..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/PathTypeSerializer.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2020 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 - * 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.serializer; - -import java.nio.file.Path; - -import jakarta.json.stream.JsonGenerator; - -import org.eclipse.yasson.internal.Marshaller; -import org.eclipse.yasson.internal.model.customization.Customization; - -public class PathTypeSerializer extends AbstractValueTypeSerializer { - public PathTypeSerializer(Customization customization) { - super(customization); - } - - @Override - protected void serialize(Path obj, JsonGenerator generator, Marshaller marshaller) { - generator.write(obj.toString()); - } -} \ No newline at end of file diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/PeriodTypeDeserializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/PeriodTypeDeserializer.java deleted file mode 100644 index 574ce4e82..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/PeriodTypeDeserializer.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import java.lang.reflect.Type; -import java.time.Period; - -import org.eclipse.yasson.internal.Unmarshaller; -import org.eclipse.yasson.internal.model.customization.Customization; - -/** - * Deserializer for {@link Period} type. - */ -public class PeriodTypeDeserializer extends AbstractValueTypeDeserializer { - - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public PeriodTypeDeserializer(Customization customization) { - super(Period.class, customization); - } - - @Override - protected Period deserialize(String jsonValue, Unmarshaller unmarshaller, Type rtType) { - return Period.parse(jsonValue); - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/PeriodTypeSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/PeriodTypeSerializer.java deleted file mode 100644 index 8c5416ded..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/PeriodTypeSerializer.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import java.time.Period; - -import jakarta.json.stream.JsonGenerator; - -import org.eclipse.yasson.internal.Marshaller; -import org.eclipse.yasson.internal.model.customization.Customization; - -/** - * Serializer for {@link Period} type. - */ -public class PeriodTypeSerializer extends AbstractValueTypeSerializer { - - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public PeriodTypeSerializer(Customization customization) { - super(customization); - } - - @Override - protected void serialize(Period obj, JsonGenerator generator, Marshaller marshaller) { - generator.write(obj.toString()); - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/RecursionChecker.java b/src/main/java/org/eclipse/yasson/internal/serializer/RecursionChecker.java new file mode 100644 index 000000000..32d746cf3 --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/serializer/RecursionChecker.java @@ -0,0 +1,42 @@ +/* + * 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.serializer; + +import jakarta.json.bind.JsonbException; +import jakarta.json.stream.JsonGenerator; + +import org.eclipse.yasson.internal.SerializationContextImpl; +import org.eclipse.yasson.internal.properties.MessageKeys; +import org.eclipse.yasson.internal.properties.Messages; + +/** + * Recursion checker serializer deals with possible instance recursion in instances. + */ +class RecursionChecker implements ModelSerializer { + + private final ModelSerializer delegate; + + RecursionChecker(ModelSerializer delegate) { + this.delegate = delegate; + } + + @Override + public void serialize(Object value, JsonGenerator generator, SerializationContextImpl context) { + if (!context.addProcessedObject(value)) { + throw new JsonbException(Messages.getMessage(MessageKeys.RECURSIVE_REFERENCE, value.getClass())); + } + delegate.serialize(value, generator, context); + context.removeProcessedObject(value); + } + +} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/SerializationModelCreator.java b/src/main/java/org/eclipse/yasson/internal/serializer/SerializationModelCreator.java new file mode 100644 index 000000000..c3de98f76 --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/serializer/SerializationModelCreator.java @@ -0,0 +1,433 @@ +/* + * 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.serializer; + +import java.lang.reflect.GenericArrayType; +import java.lang.reflect.Modifier; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.ListIterator; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Stream; + +import jakarta.json.bind.JsonbException; + +import org.eclipse.yasson.internal.ComponentMatcher; +import org.eclipse.yasson.internal.JsonbContext; +import org.eclipse.yasson.internal.ReflectionUtils; +import org.eclipse.yasson.internal.components.AdapterBinding; +import org.eclipse.yasson.internal.components.SerializerBinding; +import org.eclipse.yasson.internal.model.ClassModel; +import org.eclipse.yasson.internal.model.PropertyModel; +import org.eclipse.yasson.internal.model.customization.ClassCustomization; +import org.eclipse.yasson.internal.model.customization.ComponentBoundCustomization; +import org.eclipse.yasson.internal.model.customization.Customization; +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.types.ObjectTypeSerializer; +import org.eclipse.yasson.internal.serializer.types.TypeSerializers; + +/** + * Create or obtain already created type serializer. + */ +public class SerializationModelCreator { + + private final Map explicitChain = new ConcurrentHashMap<>(); + private final Map dynamicChain = new ConcurrentHashMap<>(); + private final JsonbContext jsonbContext; + + /** + * Create new instance. + * + * @param jsonbContext jsonb context + */ + public SerializationModelCreator(JsonbContext jsonbContext) { + this.jsonbContext = jsonbContext; + } + + /** + * Wrap {@link ModelSerializer} in the common set of serializers. + * + * @param modelSerializer serializer to be wrapped + * @param customization component customization + * @param jsonbContext jsonb context + * @return wrapped serializer + */ + public static ModelSerializer wrapInCommonSet(ModelSerializer modelSerializer, + Customization customization, + JsonbContext jsonbContext) { + return Stream.of(modelSerializer) + .map(KeyWriter::new) + .map(serializer -> new NullSerializer(serializer, customization, jsonbContext)) + .findFirst() + .get(); + } + + /** + * Create new {@link ModelSerializer} of the given type. + * + * @param type type to be serialized + * @param rootValue whether it is a root value + * @param resolveRootAdapter whether to resolve root adapter + * @return type model serializer + */ + public ModelSerializer serializerChain(Type type, boolean rootValue, boolean resolveRootAdapter) { + Class rawType = ReflectionUtils.getRawType(type); + ClassModel classModel = jsonbContext.getMappingContext().getOrCreateClassModel(rawType); + LinkedList chain = new LinkedList<>(); + return serializerChain(chain, type, classModel.getClassCustomization(), rootValue, false, resolveRootAdapter); + } + + /** + * Create new {@link ModelSerializer} of the given type. + * + * @param chain chain of types used before the one currently processed + * @param type type to be serialized + * @param propertyCustomization component customization + * @param rootValue whether it is a root value + * @param isKey whether it is a key + * @return type model serializer + */ + public ModelSerializer serializerChainRuntime(LinkedList chain, + Type type, + Customization propertyCustomization, + boolean rootValue, + boolean isKey) { + if (chain.contains(type)) { + return new CyclicReferenceSerializer(type); + } + //If the class instance and class of the field are the same and there has been generics specified for this field, + //we need to use those instead of raw type. + Class rawType = ReflectionUtils.getRawType(type); + Class rawLast = ReflectionUtils.getRawType(chain.getLast()); + if (rawLast.equals(rawType)) { + return serializerChainInternal(chain, chain.getLast(), propertyCustomization, rootValue, isKey, true); + } + return serializerChainInternal(chain, type, propertyCustomization, rootValue, isKey, true); + } + + private ModelSerializer serializerChain(LinkedList chain, + Type type, + Customization propertyCustomization, + boolean rootValue, + boolean isKey, + boolean resolveRootAdapter) { + if (chain.contains(type)) { + return new CyclicReferenceSerializer(type); + } + try { + chain.add(type); + return serializerChainInternal(chain, type, propertyCustomization, rootValue, isKey, resolveRootAdapter); + } finally { + chain.removeLast(); + } + } + + private ModelSerializer serializerChainInternal(LinkedList chain, + Type type, + Customization propertyCustomization, + boolean rootValue, + boolean isKey, + boolean resolveRootAdapter) { + if (explicitChain.containsKey(type)) { + return explicitChain.get(type); + } + Class rawType = ReflectionUtils.getRawType(type); + Optional serializerBinding = userSerializer(type, + (ComponentBoundCustomization) propertyCustomization); + if (serializerBinding.isPresent()) { + return serializerBinding.get(); + } + if (resolveRootAdapter) { + Optional maybeAdapter = adapterBinding(type, (ComponentBoundCustomization) propertyCustomization); + if (maybeAdapter.isPresent()) { + AdapterBinding adapterBinding = maybeAdapter.get(); + Type toType = adapterBinding.getToType(); + Class rawToType = ReflectionUtils.getRawType(toType); + ModelSerializer typeSerializer = TypeSerializers + .getTypeSerializer(rawToType, propertyCustomization, jsonbContext); + if (typeSerializer == null) { + typeSerializer = serializerChain(toType, rootValue, !type.equals(toType)); + } + AdapterSerializer adapterSerializer = new AdapterSerializer(adapterBinding, typeSerializer); + RecursionChecker recursionChecker = new RecursionChecker(adapterSerializer); + NullSerializer nullSerializer = new NullSerializer(recursionChecker, propertyCustomization, jsonbContext); + explicitChain.put(type, nullSerializer); + return nullSerializer; + } + } + + ModelSerializer typeSerializer = null; + if (!Object.class.equals(rawType)) { + typeSerializer = TypeSerializers.getTypeSerializer(chain, rawType, propertyCustomization, jsonbContext, isKey); + } + if (typeSerializer != null) { + if (jsonbContext.getConfigProperties().isStrictIJson() && rootValue) { + throw new JsonbException(Messages.getMessage(MessageKeys.IJSON_ENABLED_SINGLE_VALUE)); + } + return typeSerializer; + } + ClassModel classModel = jsonbContext.getMappingContext().getOrCreateClassModel(rawType); + if (Collection.class.isAssignableFrom(rawType)) { + return createCollectionSerializer(chain, type, propertyCustomization); + } else if (Map.class.isAssignableFrom(rawType)) { + return createMapSerializer(chain, type, propertyCustomization); + } else if (rawType.isArray()) { + return createArraySerializer(chain, rawType, propertyCustomization); + } else if (type instanceof GenericArrayType) { + return createGenericArraySerializer(chain, type, propertyCustomization); + } else if (Optional.class.equals(rawType)) { + return createOptionalSerializer(chain, type, propertyCustomization, isKey); + } + return createObjectSerializer(chain, type, classModel); + } + + private ModelSerializer createObjectSerializer(LinkedList chain, + Type type, + ClassModel classModel) { + LinkedHashMap propertySerializers = new LinkedHashMap<>(); + TypeInheritanceConfiguration typeInheritanceConfiguration = classModel.getClassCustomization().getPolymorphismConfig(); + if (typeInheritanceConfiguration != null) { + addPolymorphismProperty(typeInheritanceConfiguration, propertySerializers, classModel); + } + for (PropertyModel model : classModel.getSortedProperties()) { + if (model.isReadable()) { + String name = model.getWriteName(); + ModelSerializer memberModel = memberSerializer(chain, + model.getPropertySerializationType(), + model.getCustomization(), + false); + propertySerializers.put(name, new ValueGetterSerializer(model.getGetValueHandle(), memberModel)); + } + } + ModelSerializer objectSerializer = new ObjectSerializer(propertySerializers); + RecursionChecker recursionChecker = new RecursionChecker(objectSerializer); + KeyWriter keyWriter = new KeyWriter(recursionChecker); + NullVisibilitySwitcher nullVisibilitySwitcher = new NullVisibilitySwitcher(false, keyWriter); + NullSerializer nullSerializer = new NullSerializer(nullVisibilitySwitcher, classModel.getClassCustomization(), + jsonbContext); + explicitChain.put(type, nullSerializer); + return nullSerializer; + } + + private void addPolymorphismProperty(TypeInheritanceConfiguration typeInheritanceConfiguration, + LinkedHashMap propertySerializers, + ClassModel classModel) { + Class rawType = classModel.getType(); + String alias = typeInheritanceConfiguration.getAliases().get(rawType); + ModelSerializer serializer = createPolymorphismPropertySerializer(typeInheritanceConfiguration, alias); + if (serializer != null) { + if (typeInheritanceConfiguration.getParentConfig() != null) { + addParentPolymorphismProperty(typeInheritanceConfiguration.getParentConfig(), propertySerializers, classModel); + } + propertySerializers.put(typeInheritanceConfiguration.getFieldName(), serializer); + } + for (PropertyModel propertyModel : classModel.getSortedProperties()) { + if (propertySerializers.containsKey(propertyModel.getWriteName())) { + throw new JsonbException("CHANGE naming conflict!"); + } + } + } + + private void addParentPolymorphismProperty(TypeInheritanceConfiguration typeInheritanceConfiguration, + LinkedHashMap propertySerializers, + ClassModel classModel) { + Class rawType = classModel.getType(); + TypeInheritanceConfiguration current = typeInheritanceConfiguration; + LinkedHashMap toBeAdded = new LinkedHashMap<>(); + while (current != null) { + TypeInheritanceConfiguration local = current; + String alias = local.getAliases().entrySet().stream() + .filter(entry -> entry.getKey().isAssignableFrom(rawType)) + .map(Map.Entry::getValue) + .findFirst() + .orElse(null); + if (alias != null) { + ModelSerializer serializer = createPolymorphismPropertySerializer(local, alias); + toBeAdded.put(current.getFieldName(), serializer); + current = current.getParentConfig(); + } + } + ListIterator> iterator = new ArrayList<>(toBeAdded.entrySet()) + .listIterator(toBeAdded.size()); + while (iterator.hasPrevious()) { + Map.Entry entry = iterator.previous(); + propertySerializers.put(entry.getKey(), entry.getValue()); + } + } + + private ModelSerializer createPolymorphismPropertySerializer(TypeInheritanceConfiguration typeConfiguration, + String alias) { + if (alias != null) { + return (value, generator, context) -> generator.write(typeConfiguration.getFieldName(), alias); + } + return null; + } + + private ModelSerializer createCollectionSerializer(LinkedList chain, + Type type, + Customization customization) { + Type colType = type instanceof ParameterizedType + ? ((ParameterizedType) type).getActualTypeArguments()[0] + : Object.class; + ModelSerializer typeSerializer = memberSerializer(chain, colType, customization, false); + CollectionSerializer collectionSerializer = new CollectionSerializer(typeSerializer); + KeyWriter keyWriter = new KeyWriter(collectionSerializer); + NullVisibilitySwitcher nullVisibilitySwitcher = new NullVisibilitySwitcher(true, keyWriter); + return new NullSerializer(nullVisibilitySwitcher, customization, jsonbContext); + } + + private ModelSerializer createMapSerializer(LinkedList chain, Type type, Customization propertyCustomization) { + Type keyType = type instanceof ParameterizedType + ? ((ParameterizedType) type).getActualTypeArguments()[0] + : Object.class; + Type valueType = type instanceof ParameterizedType + ? ((ParameterizedType) type).getActualTypeArguments()[1] + : Object.class; + Type resolvedKey = ReflectionUtils.resolveType(chain, keyType); + Class rawClass = ReflectionUtils.getRawType(resolvedKey); + ModelSerializer keySerializer = memberSerializer(chain, keyType, ClassCustomization.empty(), true); + ModelSerializer valueSerializer = memberSerializer(chain, valueType, propertyCustomization, false); + MapSerializer mapSerializer = MapSerializer.create(rawClass, keySerializer, valueSerializer); + KeyWriter keyWriter = new KeyWriter(mapSerializer); + NullVisibilitySwitcher nullVisibilitySwitcher = new NullVisibilitySwitcher(true, keyWriter); + return new NullSerializer(nullVisibilitySwitcher, propertyCustomization, jsonbContext); + } + + private ModelSerializer createArraySerializer(LinkedList chain, + Class raw, + Customization propertyCustomization) { + Class arrayComponent = raw.getComponentType(); + ModelSerializer modelSerializer = memberSerializer(chain, arrayComponent, propertyCustomization, false); + ModelSerializer arraySerializer = ArraySerializer.create(raw, jsonbContext, modelSerializer); + KeyWriter keyWriter = new KeyWriter(arraySerializer); + NullVisibilitySwitcher nullVisibilitySwitcher = new NullVisibilitySwitcher(true, keyWriter); + return new NullSerializer(nullVisibilitySwitcher, propertyCustomization, jsonbContext); + } + + private ModelSerializer createGenericArraySerializer(LinkedList chain, + Type type, + Customization propertyCustomization) { + Class raw = ReflectionUtils.getRawType(type); + Class component = ReflectionUtils.getRawType(((GenericArrayType) type).getGenericComponentType()); + ModelSerializer modelSerializer = memberSerializer(chain, component, propertyCustomization, false); + ModelSerializer arraySerializer = ArraySerializer.create(raw, jsonbContext, modelSerializer); + KeyWriter keyWriter = new KeyWriter(arraySerializer); + NullVisibilitySwitcher nullVisibilitySwitcher = new NullVisibilitySwitcher(true, keyWriter); + return new NullSerializer(nullVisibilitySwitcher, propertyCustomization, jsonbContext); + } + + private ModelSerializer createOptionalSerializer(LinkedList chain, + Type type, + Customization propertyCustomization, + boolean isKey) { + Type optType = type instanceof ParameterizedType + ? ((ParameterizedType) type).getActualTypeArguments()[0] + : Object.class; + ModelSerializer modelSerializer = memberSerializer(chain, optType, propertyCustomization, isKey); + return new OptionalSerializer(modelSerializer); + } + + private ModelSerializer memberSerializer(LinkedList chain, + Type type, + Customization customization, + boolean key) { + Type resolved = ReflectionUtils.resolveType(chain, type); + Class rawType = ReflectionUtils.getRawType(resolved); + + Optional serializerBinding = userSerializer(resolved, + (ComponentBoundCustomization) customization); + if (serializerBinding.isPresent()) { + return serializerBinding.get(); + } + Optional maybeAdapter = adapterBinding(resolved, (ComponentBoundCustomization) customization); + if (maybeAdapter.isPresent()) { + AdapterBinding adapterBinding = maybeAdapter.get(); + Type toType = adapterBinding.getToType(); + Class rawToType = ReflectionUtils.getRawType(toType); + ModelSerializer typeSerializer = TypeSerializers.getTypeSerializer(rawToType, customization, jsonbContext); + if (typeSerializer == null) { + typeSerializer = serializerChain(toType, false, true); + } + AdapterSerializer adapterSerializer = new AdapterSerializer(adapterBinding, typeSerializer); + return new NullSerializer(adapterSerializer, customization, jsonbContext); + } + ModelSerializer typeSerializer = TypeSerializers.getTypeSerializer(chain, rawType, customization, jsonbContext, key); + if (typeSerializer == null) { + //Final classes dont have any child classes. It is safe to assume that there will be instance of that specific class. + boolean isFinal = Modifier.isFinal(rawType.getModifiers()); + if (isFinal + || Collection.class.isAssignableFrom(rawType) + || Map.class.isAssignableFrom(rawType)) { + return serializerChain(chain, resolved, customization, false, key, true); + } else { + if (dynamicChain.containsKey(resolved)) { + return dynamicChain.get(resolved); + } + boolean isAbstract = Modifier.isAbstract(rawType.getModifiers()); + ModelSerializer specificTypeSerializer = null; + if (!isAbstract && !rawType.equals(Object.class)) { + if (explicitChain.containsKey(resolved)) { + specificTypeSerializer = explicitChain.get(resolved); + } else { + specificTypeSerializer = serializerChain(chain, resolved, customization, false, key, true); + } + } + //Needs to be dynamically resolved with special cache since possible inheritance problem. + if (resolved instanceof Class) { + typeSerializer = TypeSerializers.getTypeSerializer(chain, Object.class, customization, jsonbContext, key); + } else { + chain.add(resolved); + typeSerializer = TypeSerializers.getTypeSerializer(chain, Object.class, customization, jsonbContext, key); + chain.removeLast(); + } + if (specificTypeSerializer != null && typeSerializer instanceof ObjectTypeSerializer) { + ((ObjectTypeSerializer) typeSerializer).addSpecificSerializer(rawType, specificTypeSerializer); + } + //Since typeSerializer is handled as Object currently, we need to wrap it with null checker (if it is not a key) + if (!key) { + typeSerializer = new NullSerializer(typeSerializer, customization, jsonbContext); + } + + dynamicChain.put(type, typeSerializer); + } + } + if (!key && typeSerializer instanceof ObjectTypeSerializer) { + typeSerializer = new NullSerializer(typeSerializer, customization, jsonbContext); + } + return typeSerializer; + } + + private Optional userSerializer(Type type, ComponentBoundCustomization classCustomization) { + final ComponentMatcher componentMatcher = jsonbContext.getComponentMatcher(); + return componentMatcher.getSerializerBinding(type, classCustomization) + .map(SerializerBinding::getJsonbSerializer) + .map(UserDefinedSerializer::new) + .map(RecursionChecker::new) + .map(serializer -> SerializationModelCreator.wrapInCommonSet(serializer, + (Customization) classCustomization, + jsonbContext)); + } + + private Optional adapterBinding(Type type, ComponentBoundCustomization classCustomization) { + return jsonbContext.getComponentMatcher().getSerializeAdapterBinding(type, classCustomization); + } + +} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/SerializerBuilder.java b/src/main/java/org/eclipse/yasson/internal/serializer/SerializerBuilder.java deleted file mode 100644 index ba9254326..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/SerializerBuilder.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import java.lang.reflect.GenericArrayType; -import java.lang.reflect.Type; -import java.util.Collection; -import java.util.Map; -import java.util.Optional; - -import jakarta.json.JsonObject; -import jakarta.json.JsonValue; -import jakarta.json.bind.config.BinaryDataStrategy; -import jakarta.json.bind.serializer.JsonbSerializer; - -import org.eclipse.yasson.internal.ComponentMatcher; -import org.eclipse.yasson.internal.JsonbContext; -import org.eclipse.yasson.internal.components.AdapterBinding; -import org.eclipse.yasson.internal.components.SerializerBinding; -import org.eclipse.yasson.internal.model.customization.ComponentBoundCustomization; - -/** - * Builder for serializers. - */ -public class SerializerBuilder extends AbstractSerializerBuilder { - - private Class objectClass; - - /** - * Creates a new builder. - * - * @param jsonbContext JSON-B context. - */ - public SerializerBuilder(JsonbContext jsonbContext) { - super(jsonbContext); - } - - /** - * Adds object class. - * - * @param objectClass object class - * @return Builder. - */ - public SerializerBuilder withObjectClass(Class objectClass) { - this.objectClass = objectClass; - return this; - } - - /** - * Builds a {@link JsonbSerializer}. - * - * @return JsonbSerializer. - */ - public JsonbSerializer build() { - withRuntimeType(resolveRuntimeType()); - - if (getCustomization() instanceof ComponentBoundCustomization) { - ComponentBoundCustomization customization = (ComponentBoundCustomization) this.getCustomization(); - //First check if user deserializer is registered for such type - final ComponentMatcher componentMatcher = getJsonbContext().getComponentMatcher(); - Optional> userSerializer = componentMatcher - .getSerializerBinding(getRuntimeType(), customization); - if (userSerializer.isPresent()) { - return new UserSerializerSerializer<>(getClassModel(), userSerializer.get().getJsonbSerializer()); - } - - //Second user components is registered. - Optional adapterInfoOptional = componentMatcher - .getSerializeAdapterBinding(getRuntimeType(), customization); - if (adapterInfoOptional.isPresent()) { - return new AdaptedObjectSerializer<>(getClassModel(), adapterInfoOptional.get()); - } - } - - final Optional> supportedTypeSerializer = getSupportedTypeSerializer(objectClass); - if (supportedTypeSerializer.isPresent()) { - return supportedTypeSerializer.get(); - } - - if (Collection.class.isAssignableFrom(objectClass)) { - return new CollectionSerializer<>(this); - } else if (Map.class.isAssignableFrom(objectClass)) { - return new MapSerializer<>(this); - } else if (isByteArray(objectClass)) { - String strategy = getJsonbContext().getConfigProperties().getBinaryDataStrategy(); - switch (strategy) { - case BinaryDataStrategy.BYTE: - return new ByteArraySerializer(this); - default: - return new ByteArrayBase64Serializer(getCustomization()); - } - } else if (objectClass.isArray() || getRuntimeType() instanceof GenericArrayType) { - return createArrayItem(objectClass.getComponentType()); - - } else if (JsonValue.class.isAssignableFrom(objectClass)) { - if (JsonObject.class.isAssignableFrom(objectClass)) { - return new JsonObjectSerializer(this); - } else { - return new JsonArraySerializer(this); - } - } else if (Optional.class.isAssignableFrom(objectClass)) { - return new OptionalObjectSerializer<>(this); - } else { - getJsonbContext().getMappingContext().addSerializerProvider(objectClass, new ObjectSerializerProvider()); - return new ObjectSerializer<>(this); - } - - } - - private boolean isByteArray(Class rawType) { - return rawType.isArray() && rawType.getComponentType() == Byte.TYPE; - } - - /** - * Instance is not created in case of array items, because, we don't know how long it should be - * till parser ends parsing. - */ - private JsonbSerializer createArrayItem(Class componentType) { - if (componentType == byte.class) { - return new ByteArraySerializer(this); - } else if (componentType == short.class) { - return new ShortArraySerializer(this); - } else if (componentType == char.class) { - return new CharArraySerializer(this); - } else if (componentType == int.class) { - return new IntArraySerializer(this); - } else if (componentType == long.class) { - return new LongArraySerializer(this); - } else if (componentType == float.class) { - return new FloatArraySerializer(this); - } else if (componentType == double.class) { - return new DoubleArraySerializer(this); - } else if (componentType == boolean.class) { - return new BooleanArraySerializer(this); - } else { - return new ObjectArraySerializer<>(this); - } - } - - private Optional> getSupportedTypeSerializer(Class rawType) { - final Optional supportedTypeSerializerOptional = DefaultSerializers - .findValueSerializerProvider(rawType); - if (supportedTypeSerializerOptional.isPresent()) { - return Optional - .of(supportedTypeSerializerOptional.get().getSerializerProvider().provideSerializer(getCustomization())); - } - return Optional.empty(); - } - - private Type resolveRuntimeType() { - Type genericType = getGenericType(); - if (genericType != null && genericType != Object.class) { - return genericType; - } - return objectClass; - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/SerializerBuilderParams.java b/src/main/java/org/eclipse/yasson/internal/serializer/SerializerBuilderParams.java new file mode 100644 index 000000000..525d4d2e9 --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/serializer/SerializerBuilderParams.java @@ -0,0 +1,124 @@ +/* + * 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.serializer; + +import java.lang.reflect.Type; +import java.util.Objects; + +import org.eclipse.yasson.internal.model.customization.ClassCustomization; +import org.eclipse.yasson.internal.model.customization.Customization; + +/** + * Not currently supported. Possibly implemented in the future. + * + * Holder of serialization parameters during creation process. Reduces the number of needed parameters. + */ +class SerializerBuilderParams { + + private final Type type; + private final Customization customization; + private final boolean root; + private final boolean key; + private final boolean resolveRootAdapter; + private final ModelSerializer objectBaseSerializer; + + private SerializerBuilderParams(Builder builder) { + this.type = builder.type; + this.customization = builder.customization; + this.root = builder.root; + this.key = builder.key; + this.resolveRootAdapter = builder.resolveRootAdapter; + this.objectBaseSerializer = builder.objectBaseSerializer; + } + + public static Builder builder(Type type) { + return new Builder(type); + } + + public Type getType() { + return type; + } + + public Customization getCustomization() { + return customization; + } + + public boolean isRoot() { + return root; + } + + public boolean isKey() { + return key; + } + + public boolean isResolveRootAdapter() { + return resolveRootAdapter; + } + + public ModelSerializer getObjectBaseSerializer() { + return objectBaseSerializer; + } + + static final class Builder { + + private Type type; + private Customization customization; + private boolean root; + private boolean key; + private boolean resolveRootAdapter; + private ModelSerializer objectBaseSerializer; + + private Builder(Type type) { + this.type = Objects.requireNonNull(type); + this.customization = ClassCustomization.empty(); + this.root = true; + this.key = false; + } + + public Builder type(Type type) { + this.type = Objects.requireNonNull(type); + return this; + } + + public Builder customization(Customization customization) { + this.customization = Objects.requireNonNull(customization); + return this; + } + + public Builder root(boolean root) { + this.root = root; + return this; + } + + public Builder key(boolean key) { + this.key = key; + return this; + } + + public Builder resolveRootAdapter(boolean resolveRootAdapter) { + this.resolveRootAdapter = resolveRootAdapter; + return this; + } + + public Builder objectBaseSerializer(ModelSerializer objectBaseSerializer) { + this.objectBaseSerializer = objectBaseSerializer; + return this; + } + + public SerializerBuilderParams build() { + return new SerializerBuilderParams(this); + } + + } + +} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/SerializerProviderWrapper.java b/src/main/java/org/eclipse/yasson/internal/serializer/SerializerProviderWrapper.java deleted file mode 100644 index e135153ae..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/SerializerProviderWrapper.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2015, 2020 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.serializer; - -/** - * Wraps serializer and deserializer providers. - */ -public class SerializerProviderWrapper { - - private ISerializerProvider serializerProvider; - private IDeserializerProvider deserializerProvider; - - /** - * Creates a new instance. - * - * @param serializerProvider Serializer provider. - * @param deserializerProvider Deserializer provider. - */ - public SerializerProviderWrapper(ISerializerProvider serializerProvider, IDeserializerProvider deserializerProvider) { - this.serializerProvider = serializerProvider; - this.deserializerProvider = deserializerProvider; - } - - /** - * Gets serializer provider. - * - * @return Serializer provider. - */ - public ISerializerProvider getSerializerProvider() { - return serializerProvider; - } - - /** - * Gets deserializer provider. - * - * @return Deserializer provider. - */ - public IDeserializerProvider getDeserializerProvider() { - return deserializerProvider; - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/ShortArrayDeserializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/ShortArrayDeserializer.java deleted file mode 100644 index 23c5db781..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/ShortArrayDeserializer.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import java.util.ArrayList; -import java.util.List; - -import org.eclipse.yasson.internal.Unmarshaller; - -/** - * Array unmarshaller item implementation for small short. - */ -public class ShortArrayDeserializer extends AbstractArrayDeserializer { - - private final List items = new ArrayList<>(); - - /** - * Creates new short array deserializer. - * - * @param builder deserializer builder - */ - protected ShortArrayDeserializer(DeserializerBuilder builder) { - super(builder); - } - - @Override - protected List getItems() { - return items; - } - - @Override - public short[] getInstance(Unmarshaller unmarshaller) { - final int size = items.size(); - final short[] shortArray = new short[size]; - for (int i = 0; i < size; i++) { - shortArray[i] = items.get(i); - } - return shortArray; - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/ShortArraySerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/ShortArraySerializer.java deleted file mode 100644 index dd7290b25..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/ShortArraySerializer.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import jakarta.json.bind.serializer.SerializationContext; -import jakarta.json.stream.JsonGenerator; - -/** - * Serializer for arrays of shorts. - */ -public class ShortArraySerializer extends AbstractArraySerializer { - - /** - * Creates new short array serializer. - * - * @param builder serializer builder - */ - protected ShortArraySerializer(SerializerBuilder builder) { - super(builder); - } - - @Override - protected void serializeInternal(short[] arr, JsonGenerator generator, SerializationContext ctx) { - for (short obj : arr) { - generator.write(obj); - } - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/ShortTypeDeserializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/ShortTypeDeserializer.java deleted file mode 100644 index 316f58ac5..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/ShortTypeDeserializer.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import java.lang.reflect.Type; - -import jakarta.json.bind.JsonbException; - -import org.eclipse.yasson.internal.Unmarshaller; -import org.eclipse.yasson.internal.model.customization.Customization; -import org.eclipse.yasson.internal.properties.MessageKeys; -import org.eclipse.yasson.internal.properties.Messages; - -/** - * Deserializer for {@link Short} type. - */ -public class ShortTypeDeserializer extends AbstractNumberDeserializer { - - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public ShortTypeDeserializer(Customization customization) { - super(Short.class, customization); - } - - @Override - protected Short deserialize(String jsonValue, Unmarshaller unmarshaller, Type rtType) { - return deserializeFormatted(jsonValue, true, unmarshaller.getJsonbContext()) - .map(num -> Short.parseShort(num.toString())) - .orElseGet(() -> { - try { - return Short.parseShort(jsonValue); - } catch (NumberFormatException e) { - throw new JsonbException(Messages.getMessage(MessageKeys.DESERIALIZE_VALUE_ERROR, Short.class)); - } - }); - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/ShortTypeSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/ShortTypeSerializer.java deleted file mode 100644 index c164ad00a..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/ShortTypeSerializer.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import jakarta.json.stream.JsonGenerator; - -import org.eclipse.yasson.internal.model.customization.Customization; - -/** - * Serializer for {@link Short} type. - */ -public class ShortTypeSerializer extends AbstractNumberSerializer { - - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public ShortTypeSerializer(Customization customization) { - super(customization); - } - - @Override - protected void serializeNonFormatted(Short obj, JsonGenerator generator, String key) { - generator.write(key, obj); - } - - @Override - protected void serializeNonFormatted(Short obj, JsonGenerator generator) { - generator.write(obj); - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/StringTypeDeserializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/StringTypeDeserializer.java deleted file mode 100644 index dbc118d54..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/StringTypeDeserializer.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import java.io.UnsupportedEncodingException; -import java.lang.reflect.Type; - -import jakarta.json.bind.JsonbConfig; -import jakarta.json.bind.JsonbException; - -import org.eclipse.yasson.internal.Unmarshaller; -import org.eclipse.yasson.internal.model.customization.Customization; -import org.eclipse.yasson.internal.properties.MessageKeys; -import org.eclipse.yasson.internal.properties.Messages; - -/** - * Deserializer for {@link String} type. - */ -public class StringTypeDeserializer extends AbstractValueTypeDeserializer { - - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public StringTypeDeserializer(Customization customization) { - super(String.class, customization); - } - - @Override - protected String deserialize(String jsonValue, Unmarshaller unmarshaller, Type rtType) { - if ((boolean) unmarshaller.getJsonbContext().getConfig().getProperty(JsonbConfig.STRICT_IJSON).orElse(false)) { - try { - String newString = new String(jsonValue.getBytes("UTF-8"), "UTF-8"); - if (!newString.equals(jsonValue)) { - throw new JsonbException(Messages.getMessage(MessageKeys.UNPAIRED_SURROGATE)); - } - } catch (UnsupportedEncodingException e) { - e.printStackTrace(); - } - } - return jsonValue; - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/StringTypeSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/StringTypeSerializer.java deleted file mode 100644 index 58f232535..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/StringTypeSerializer.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import java.io.UnsupportedEncodingException; - -import jakarta.json.bind.JsonbConfig; -import jakarta.json.bind.JsonbException; -import jakarta.json.stream.JsonGenerator; - -import org.eclipse.yasson.internal.JsonbContext; -import org.eclipse.yasson.internal.Marshaller; -import org.eclipse.yasson.internal.model.customization.Customization; -import org.eclipse.yasson.internal.properties.MessageKeys; -import org.eclipse.yasson.internal.properties.Messages; - -/** - * Serializer for {@link String} type. - */ -public class StringTypeSerializer extends AbstractValueTypeSerializer { - - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public StringTypeSerializer(Customization customization) { - super(customization); - } - - private String toJson(String object, JsonbContext jsonbContext) { - if ((boolean) jsonbContext.getConfig().getProperty(JsonbConfig.STRICT_IJSON).orElse(false)) { - try { - String newString = new String(object.getBytes("UTF-8"), "UTF-8"); - if (!newString.equals(object)) { - throw new JsonbException(Messages.getMessage(MessageKeys.UNPAIRED_SURROGATE)); - } - } catch (UnsupportedEncodingException e) { - e.printStackTrace(); - } - } - return object; - } - - @Override - protected void serialize(String obj, JsonGenerator generator, Marshaller marshaller) { - generator.write(toJson(obj, marshaller.getJsonbContext())); - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/TimeZoneTypeSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/TimeZoneTypeSerializer.java deleted file mode 100644 index 03549bfbf..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/TimeZoneTypeSerializer.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import java.util.TimeZone; - -import jakarta.json.stream.JsonGenerator; - -import org.eclipse.yasson.internal.Marshaller; -import org.eclipse.yasson.internal.model.customization.Customization; - -/** - * Serializer for {@link TimeZone} type. - */ -public class TimeZoneTypeSerializer extends AbstractValueTypeSerializer { - - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public TimeZoneTypeSerializer(Customization customization) { - super(customization); - } - - @Override - protected void serialize(TimeZone obj, JsonGenerator generator, Marshaller marshaller) { - generator.write(obj.getID()); - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/URITypeDeserializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/URITypeDeserializer.java deleted file mode 100644 index e48790412..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/URITypeDeserializer.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import java.lang.reflect.Type; -import java.net.URI; - -import org.eclipse.yasson.internal.Unmarshaller; -import org.eclipse.yasson.internal.model.customization.Customization; - -/** - * Deserializer for {@link URI} type. - */ -public class URITypeDeserializer extends AbstractValueTypeDeserializer { - - /** - * Creates a new instance. - * - * @param customization Binding model. - */ - public URITypeDeserializer(Customization customization) { - super(URI.class, customization); - } - - @Override - protected URI deserialize(String jsonValue, Unmarshaller unmarshaller, Type rtType) { - return URI.create(jsonValue); - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/URITypeSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/URITypeSerializer.java deleted file mode 100644 index 4027d4e0b..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/URITypeSerializer.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import java.net.URI; - -import jakarta.json.stream.JsonGenerator; - -import org.eclipse.yasson.internal.Marshaller; -import org.eclipse.yasson.internal.model.customization.Customization; - -/** - * Serializer for {@link URI} type. - */ -public class URITypeSerializer extends AbstractValueTypeSerializer { - - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public URITypeSerializer(Customization customization) { - super(customization); - } - - @Override - protected void serialize(URI obj, JsonGenerator generator, Marshaller marshaller) { - generator.write(obj.toString()); - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/URLTypeDeserializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/URLTypeDeserializer.java deleted file mode 100644 index 8f3eac6c4..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/URLTypeDeserializer.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import java.lang.reflect.Type; -import java.net.MalformedURLException; -import java.net.URL; - -import org.eclipse.yasson.internal.Unmarshaller; -import org.eclipse.yasson.internal.model.customization.Customization; - -/** - * Deserializer for {@link URL} type. - */ -public class URLTypeDeserializer extends AbstractValueTypeDeserializer { - - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public URLTypeDeserializer(Customization customization) { - super(URL.class, customization); - } - - @Override - protected URL deserialize(String jsonValue, Unmarshaller unmarshaller, Type rtType) { - URL url = null; - try { - url = new URL(jsonValue); - } catch (MalformedURLException e) { - e.printStackTrace(); - } - return url; - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/URLTypeSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/URLTypeSerializer.java deleted file mode 100644 index d7403724c..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/URLTypeSerializer.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import java.net.URL; - -import jakarta.json.stream.JsonGenerator; - -import org.eclipse.yasson.internal.Marshaller; -import org.eclipse.yasson.internal.model.customization.Customization; - -/** - * Serializer for {@link URL} type. - */ -public class URLTypeSerializer extends AbstractValueTypeSerializer { - - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public URLTypeSerializer(Customization customization) { - super(customization); - } - - @Override - protected void serialize(URL obj, JsonGenerator generator, Marshaller marshaller) { - generator.write(obj.toString()); - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/UUIDTypeDeserializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/UUIDTypeDeserializer.java deleted file mode 100644 index b85fe33b0..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/UUIDTypeDeserializer.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2018, 2020 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.serializer; - -import java.lang.reflect.Type; -import java.util.UUID; - -import org.eclipse.yasson.internal.Unmarshaller; -import org.eclipse.yasson.internal.model.customization.Customization; - -/** - * Deserializer for {@link UUID} type. - */ -public class UUIDTypeDeserializer extends AbstractValueTypeDeserializer { - - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public UUIDTypeDeserializer(Customization customization) { - super(UUID.class, customization); - } - - @Override - protected UUID deserialize(String jsonValue, Unmarshaller unmarshaller, Type rtType) { - return UUID.fromString(jsonValue); - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/UUIDTypeSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/UUIDTypeSerializer.java deleted file mode 100644 index 5c72a072f..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/UUIDTypeSerializer.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2018, 2020 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.serializer; - -import java.util.UUID; - -import jakarta.json.stream.JsonGenerator; - -import org.eclipse.yasson.internal.Marshaller; -import org.eclipse.yasson.internal.model.customization.Customization; - -/** - * Serializer for {@link UUID} type. - */ -public class UUIDTypeSerializer extends AbstractValueTypeSerializer { - - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public UUIDTypeSerializer(Customization customization) { - super(customization); - } - - @Override - protected void serialize(UUID obj, JsonGenerator generator, Marshaller marshaller) { - generator.write(obj.toString()); - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/UserDefinedSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/UserDefinedSerializer.java new file mode 100644 index 000000000..88edd1108 --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/serializer/UserDefinedSerializer.java @@ -0,0 +1,38 @@ +/* + * 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.serializer; + +import jakarta.json.bind.serializer.JsonbSerializer; +import jakarta.json.stream.JsonGenerator; + +import org.eclipse.yasson.internal.SerializationContextImpl; + +/** + * User defined serializer executor. + */ +class UserDefinedSerializer implements ModelSerializer { + + private final JsonbSerializer userDefinedSerializer; + + UserDefinedSerializer(JsonbSerializer userDefinedSerializer) { + this.userDefinedSerializer = userDefinedSerializer; + } + + @SuppressWarnings("unchecked") + @Override + public void serialize(Object value, JsonGenerator generator, SerializationContextImpl context) { + YassonGenerator yassonGenerator = new YassonGenerator(generator); + userDefinedSerializer.serialize((T) value, yassonGenerator, context); + } + +} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/UserDeserializerDeserializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/UserDeserializerDeserializer.java deleted file mode 100644 index 4feb23f3a..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/UserDeserializerDeserializer.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2016, 2021 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.serializer; - -import jakarta.json.stream.JsonParser; - -import org.eclipse.yasson.internal.JsonbParser; -import org.eclipse.yasson.internal.JsonbRiParser; -import org.eclipse.yasson.internal.Unmarshaller; -import org.eclipse.yasson.internal.UserDeserializerParser; -import org.eclipse.yasson.internal.components.DeserializerBinding; - -/** - * Item for processing types, to which deserializer is bound. - * - * @param object type - */ -public class UserDeserializerDeserializer extends AbstractContainerDeserializer { - - private DeserializerBinding deserializerBinding; - - private T deserializerResult; - - /** - * Create instance of current item with its builder. - * Contains user provided component for custom deserialization. - * Decorates calls to JsonParser, with validation logic so user can't left parser cursor - * in wrong position after returning from deserializerBinding. - * - * @param builder {@link DeserializerBuilder} used to build this instance - * @param deserializerBinding Deserializer. - */ - protected UserDeserializerDeserializer(DeserializerBuilder builder, DeserializerBinding deserializerBinding) { - super(builder); - this.deserializerBinding = deserializerBinding; - } - - @Override - public void appendResult(Object result, Unmarshaller context) { - //ignore internal deserialize() call in custom deserializer - } - - @Override - @SuppressWarnings("unchecked") - public T getInstance(Unmarshaller unmarshaller) { - return deserializerResult; - } - - @SuppressWarnings("unchecked") - @Override - public void deserializeInternal(JsonbParser parser, Unmarshaller context) { - setParserContext(moveToFirst(parser)); - JsonParser.Event lastEvent = getParserContext().getLastEvent(); - final UserDeserializerParser userDeserializerParser = new UserDeserializerParser(parser); - deserializerResult = (T) deserializerBinding.getJsonbDeserializer() - .deserialize(userDeserializerParser, context, getRuntimeType()); - //In case deserialized structure is json object or array and the parser is not advanced - //after enclosing bracket of deserialized object. - if (parser.getCurrentLevel() == getParserContext() && !DeserializerBuilder.isJsonValueEvent(lastEvent)) { - userDeserializerParser.advanceParserToEnd(); - } - } - - @Override - protected void deserializeNext(JsonParser parser, Unmarshaller context) { - throw new UnsupportedOperationException("Not supported for user deserializer"); - } - - /** - * Don't move anywhere in case of user deserializer. - */ - @Override - protected JsonbRiParser.LevelContext moveToFirst(JsonbParser parser) { - return parser.getCurrentLevel(); - } - -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/UserSerializerSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/UserSerializerSerializer.java deleted file mode 100644 index b4672414d..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/UserSerializerSerializer.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import jakarta.json.bind.JsonbException; -import jakarta.json.bind.serializer.JsonbSerializer; -import jakarta.json.bind.serializer.SerializationContext; -import jakarta.json.stream.JsonGenerator; - -import org.eclipse.yasson.internal.Marshaller; -import org.eclipse.yasson.internal.ProcessingContext; -import org.eclipse.yasson.internal.model.ClassModel; -import org.eclipse.yasson.internal.properties.MessageKeys; -import org.eclipse.yasson.internal.properties.Messages; - -/** - * Serializes an object with user defined serializer. - * - * @param type of serializer - */ -public class UserSerializerSerializer implements JsonbSerializer { - - private final JsonbSerializer userSerializer; - - private final ClassModel classModel; - - /** - * Create instance of current item with its builder. - * - * @param classModel model - * @param userSerializer user serializer - */ - public UserSerializerSerializer(ClassModel classModel, JsonbSerializer userSerializer) { - this.classModel = classModel; - this.userSerializer = userSerializer; - } - - @Override - public void serialize(T obj, JsonGenerator generator, SerializationContext ctx) { - ProcessingContext context = (Marshaller) ctx; - try { - if (context.addProcessedObject(obj)) { - userSerializer.serialize(obj, generator, ctx); - } else { - throw new JsonbException(Messages.getMessage(MessageKeys.RECURSIVE_REFERENCE, obj.getClass())); - } - } finally { - context.removeProcessedObject(obj); - } - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/ValueGetterSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/ValueGetterSerializer.java new file mode 100644 index 000000000..4b2c0c8fb --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/serializer/ValueGetterSerializer.java @@ -0,0 +1,45 @@ +/* + * 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.serializer; + +import java.lang.invoke.MethodHandle; + +import jakarta.json.bind.JsonbException; +import jakarta.json.stream.JsonGenerator; + +import org.eclipse.yasson.internal.SerializationContextImpl; + +/** + * Extractor of the serialized value from the instance. + */ +class ValueGetterSerializer implements ModelSerializer { + + private final MethodHandle valueGetter; + private final ModelSerializer delegate; + + ValueGetterSerializer(MethodHandle valueGetter, ModelSerializer delegate) { + this.valueGetter = valueGetter; + this.delegate = delegate; + } + + @Override + public void serialize(Object value, JsonGenerator generator, SerializationContextImpl context) { + Object object; + try { + object = valueGetter.invoke(value); + } catch (Throwable e) { + throw new JsonbException("Error getting value on: " + value, e); + } + delegate.serialize(object, generator, context); + } +} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/YassonGenerator.java b/src/main/java/org/eclipse/yasson/internal/serializer/YassonGenerator.java new file mode 100644 index 000000000..ce552b5cb --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/serializer/YassonGenerator.java @@ -0,0 +1,215 @@ +/* + * 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.serializer; + +import java.math.BigDecimal; +import java.math.BigInteger; + +import jakarta.json.JsonValue; +import jakarta.json.bind.JsonbException; +import jakarta.json.stream.JsonGenerator; + +/** + * Yasson {@link JsonGenerator} generator wrapper. + *
+ * Used for user defined serializers. Does not allow serializer to write outside the scope it should be used on. + */ +class YassonGenerator implements JsonGenerator { + + private final JsonGenerator delegate; + private int level; + + YassonGenerator(JsonGenerator delegate) { + this.delegate = delegate; + } + + @Override + public JsonGenerator writeStartObject() { + writeValidate("writeStartObject()"); + level++; + return delegate.writeStartObject(); + } + + @Override + public JsonGenerator writeStartObject(String name) { + writeValidate("writeStartObject(String name)"); + level++; + return delegate.writeStartObject(name); + } + + @Override + public JsonGenerator writeKey(String name) { + writeValidate("writeKey(String name)"); + level++; + return delegate.writeKey(name); + } + + @Override + public JsonGenerator writeStartArray() { + writeValidate("writeStartArray()"); + level++; + return delegate.writeStartArray(); + } + + @Override + public JsonGenerator writeStartArray(String name) { + writeValidate("writeStartArray(String name)"); + level++; + return delegate.writeStartArray(name); + } + + @Override + public JsonGenerator write(String name, JsonValue value) { + writeValidate("write(String name, JsonValue value)"); + return delegate.write(name, value); + } + + @Override + public JsonGenerator write(String name, String value) { + writeValidate("write(String name, String value)"); + return delegate.write(name, value); + } + + @Override + public JsonGenerator write(String name, BigInteger value) { + writeValidate("write(String name, BigInteger value)"); + return delegate.write(name, value); + } + + @Override + public JsonGenerator write(String name, BigDecimal value) { + writeValidate("write(String name, BigDecimal value)"); + return delegate.write(name, value); + } + + @Override + public JsonGenerator write(String name, int value) { + writeValidate("write(String name, int value)"); + return delegate.write(name, value); + } + + @Override + public JsonGenerator write(String name, long value) { + writeValidate("write(String name, long value)"); + return delegate.write(name, value); + } + + @Override + public JsonGenerator write(String name, double value) { + writeValidate("write(String name, double value)"); + return delegate.write(name, value); + } + + @Override + public JsonGenerator write(String name, boolean value) { + writeValidate("write(String name, boolean value)"); + return delegate.write(name, value); + } + + @Override + public JsonGenerator writeNull(String name) { + writeValidate("writeNull(String name)"); + return delegate.writeNull(name); + } + + @Override + public JsonGenerator writeEnd() { + level--; + if (level < 0) { + throw new JsonbException("writeEnd() cannot be called outside of the scope of user generator."); + } + if (level == 0) { + level--; //if user has closed array or object and is on the same level he started. There is no more allowed writing. + } + return delegate.writeEnd(); + } + + @Override + public JsonGenerator write(JsonValue value) { + writeValidate("write(JsonValue value)"); + level--; + return delegate.write(value); + } + + @Override + public JsonGenerator write(String value) { + writeValidate("write(String value)"); + level--; + return delegate.write(value); + } + + @Override + public JsonGenerator write(BigDecimal value) { + writeValidate("write(BigDecimal value)"); + level--; + return delegate.write(value); + } + + @Override + public JsonGenerator write(BigInteger value) { + writeValidate("write(BigInteger value)"); + level--; + return delegate.write(value); + } + + @Override + public JsonGenerator write(int value) { + writeValidate("write(int value)"); + level--; + return delegate.write(value); + } + + @Override + public JsonGenerator write(long value) { + writeValidate("write(long value)"); + level--; + return delegate.write(value); + } + + @Override + public JsonGenerator write(double value) { + writeValidate("write(double value)"); + level--; + return delegate.write(value); + } + + @Override + public JsonGenerator write(boolean value) { + writeValidate("write(boolean value)"); + level--; + return delegate.write(value); + } + + @Override + public JsonGenerator writeNull() { + writeValidate("writeNull()"); + level--; + return delegate.writeNull(); + } + + @Override + public void close() { + throw new JsonbException("Unsupported operation in user defined deserializer."); + } + + @Override + public void flush() { + throw new JsonbException("Unsupported operation in user defined deserializer."); + } + + private void writeValidate(String method) { + if (level < 0) { + throw new JsonbException(method + " cannot be called outside of the scope of user generator."); + } + } +} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/ZoneIdTypeDeserializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/ZoneIdTypeDeserializer.java deleted file mode 100644 index 2756fbd1b..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/ZoneIdTypeDeserializer.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import java.lang.reflect.Type; -import java.time.ZoneId; - -import org.eclipse.yasson.internal.Unmarshaller; -import org.eclipse.yasson.internal.model.customization.Customization; - -/** - * Deserializer for {@link ZoneId} type. - */ -public class ZoneIdTypeDeserializer extends AbstractValueTypeDeserializer { - - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public ZoneIdTypeDeserializer(Customization customization) { - super(ZoneId.class, customization); - } - - @Override - protected ZoneId deserialize(String jsonValue, Unmarshaller unmarshaller, Type rtType) { - return ZoneId.of(jsonValue); - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/ZoneIdTypeSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/ZoneIdTypeSerializer.java deleted file mode 100644 index 29ec3a067..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/ZoneIdTypeSerializer.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import java.time.ZoneId; - -import jakarta.json.stream.JsonGenerator; - -import org.eclipse.yasson.internal.Marshaller; -import org.eclipse.yasson.internal.model.customization.Customization; - -/** - * Serializer for {@link ZoneId} type. - */ -public class ZoneIdTypeSerializer extends AbstractValueTypeSerializer { - - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public ZoneIdTypeSerializer(Customization customization) { - super(customization); - } - - @Override - protected void serialize(ZoneId obj, JsonGenerator generator, Marshaller marshaller) { - generator.write(obj.getId()); - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/ZoneOffsetTypeDeserializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/ZoneOffsetTypeDeserializer.java deleted file mode 100644 index 45e3ddff8..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/ZoneOffsetTypeDeserializer.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import java.lang.reflect.Type; -import java.time.ZoneOffset; - -import org.eclipse.yasson.internal.Unmarshaller; -import org.eclipse.yasson.internal.model.customization.Customization; - -/** - * Deserializer for {@link ZoneOffset} type. - */ -public class ZoneOffsetTypeDeserializer extends AbstractValueTypeDeserializer { - - /** - * Creates a new instance. - * - * @param customization customization - */ - public ZoneOffsetTypeDeserializer(Customization customization) { - super(ZoneOffset.class, customization); - } - - @Override - protected ZoneOffset deserialize(String jsonValue, Unmarshaller unmarshaller, Type rtType) { - return ZoneOffset.of(jsonValue); - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/ZoneOffsetTypeSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/ZoneOffsetTypeSerializer.java deleted file mode 100644 index 6df669b44..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/ZoneOffsetTypeSerializer.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2016, 2020 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.serializer; - -import java.time.ZoneOffset; - -import jakarta.json.stream.JsonGenerator; - -import org.eclipse.yasson.internal.Marshaller; -import org.eclipse.yasson.internal.model.customization.Customization; - -/** - * Serializer for {@link ZoneOffset} type. - */ -public class ZoneOffsetTypeSerializer extends AbstractValueTypeSerializer { - - /** - * Creates a new instance. - * - * @param customization customization - */ - public ZoneOffsetTypeSerializer(Customization customization) { - super(customization); - } - - @Override - protected void serialize(ZoneOffset obj, JsonGenerator generator, Marshaller marshaller) { - generator.write(obj.getId()); - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/AbstractDateTimeSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/types/AbstractDateSerializer.java similarity index 51% rename from src/main/java/org/eclipse/yasson/internal/serializer/AbstractDateTimeSerializer.java rename to src/main/java/org/eclipse/yasson/internal/serializer/types/AbstractDateSerializer.java index a45124c0b..3f5715c07 100644 --- a/src/main/java/org/eclipse/yasson/internal/serializer/AbstractDateTimeSerializer.java +++ b/src/main/java/org/eclipse/yasson/internal/serializer/types/AbstractDateSerializer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2020 Oracle and/or its affiliates. All rights reserved. + * 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 @@ -10,100 +10,63 @@ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ -package org.eclipse.yasson.internal.serializer; +package org.eclipse.yasson.internal.serializer.types; import java.time.Instant; import java.time.ZoneId; import java.time.format.DateTimeFormatter; import java.time.temporal.TemporalAccessor; import java.util.Locale; +import java.util.Optional; +import java.util.function.Function; import jakarta.json.bind.annotation.JsonbDateFormat; -import jakarta.json.bind.serializer.SerializationContext; import jakarta.json.stream.JsonGenerator; -import org.eclipse.yasson.internal.JsonbContext; -import org.eclipse.yasson.internal.Marshaller; +import org.eclipse.yasson.internal.JsonbConfigProperties; +import org.eclipse.yasson.internal.JsonbDateFormatter; +import org.eclipse.yasson.internal.SerializationContextImpl; import org.eclipse.yasson.internal.model.customization.Customization; /** - * Abstract class for converting date objects. - * - * @param Type to serialize. + * Base for all date related serializers. */ -public abstract class AbstractDateTimeSerializer extends AbstractValueTypeSerializer { +abstract class AbstractDateSerializer extends TypeSerializer { - /** - * Default zone id. - */ - public static final ZoneId UTC = ZoneId.of("UTC"); + static final ZoneId UTC = ZoneId.of("UTC"); - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public AbstractDateTimeSerializer(Customization customization) { - super(customization); - } + private final Function valueSerializer; - @Override - public void serialize(T obj, JsonGenerator generator, SerializationContext ctx) { - final JsonbContext jsonbContext = ((Marshaller) ctx).getJsonbContext(); - final JsonbDateFormatter formatter = getJsonbDateFormatter(jsonbContext); - generator.write(toJson(obj, formatter, jsonbContext)); + AbstractDateSerializer(TypeSerializerBuilder serializerBuilder) { + super(serializerBuilder); + valueSerializer = valueSerializer(serializerBuilder); } - /** - * Converts to JSON string. - * - * @param object Object to convert. - * @param formatter Formatter to use. - * @param jsonbContext JSON-B context. - * @return JSON representation of given object. - */ - public String toJson(T object, JsonbDateFormatter formatter, JsonbContext jsonbContext) { + private Function valueSerializer(TypeSerializerBuilder serializerBuilder) { + Customization customization = serializerBuilder.getCustomization(); + JsonbConfigProperties properties = serializerBuilder.getJsonbContext().getConfigProperties(); + final JsonbDateFormatter formatter = getJsonbDateFormatter(properties, customization); if (JsonbDateFormat.TIME_IN_MILLIS.equals(formatter.getFormat())) { - return String.valueOf(toInstant(object).toEpochMilli()); + return value -> String.valueOf(toInstant(value).toEpochMilli()); } else if (formatter.getDateTimeFormatter() != null) { - return formatWithFormatter(object, formatter.getDateTimeFormatter()); + DateTimeFormatter dateTimeFormatter = formatter.getDateTimeFormatter(); + return value -> formatWithFormatter(value, dateTimeFormatter); } else { - DateTimeFormatter configDateTimeFormatter = jsonbContext.getConfigProperties().getConfigDateFormatter() - .getDateTimeFormatter(); + DateTimeFormatter configDateTimeFormatter = properties.getConfigDateFormatter().getDateTimeFormatter(); if (configDateTimeFormatter != null) { - return formatWithFormatter(object, configDateTimeFormatter); + return value -> formatWithFormatter(value, configDateTimeFormatter); } } - if (jsonbContext.getConfigProperties().isStrictIJson()) { - return formatStrictIJson(object); + if (properties.isStrictIJson()) { + return this::formatStrictIJson; } - return formatDefault(object, jsonbContext.getConfigProperties().getLocale(formatter.getLocale())); + Locale locale = properties.getLocale(formatter.getLocale()); + return value -> formatDefault(value, locale); } - /** - * Returns registered serialization jsonb date formatter. - * - * @param context context - * @return jsonb formatter - */ - protected JsonbDateFormatter getJsonbDateFormatter(JsonbContext context) { - Customization customization = getCustomization(); - if (customization != null && customization.getSerializeDateFormatter() != null) { - return customization.getSerializeDateFormatter(); - } - return context.getConfigProperties().getConfigDateFormatter(); - } - - /** - * Append UTC zone in case zone is not set on formatter. - * - * @param formatter formatter - * @return zoned formatter - */ - protected DateTimeFormatter getZonedFormatter(DateTimeFormatter formatter) { - return formatter.getZone() != null - ? formatter - : formatter.withZone(UTC); + private JsonbDateFormatter getJsonbDateFormatter(JsonbConfigProperties properties, Customization customization) { + return Optional.ofNullable(customization.getSerializeDateFormatter()) + .orElse(properties.getConfigDateFormatter()); } /** @@ -111,11 +74,11 @@ protected DateTimeFormatter getZonedFormatter(DateTimeFormatter formatter) { * * Only for legacy dates. * - * @param object date object + * @param value date object * @return converted {@link TemporalAccessor} */ - protected TemporalAccessor toTemporalAccessor(T object) { - return (TemporalAccessor) object; + protected TemporalAccessor toTemporalAccessor(T value) { + return (TemporalAccessor) value; } /** @@ -157,8 +120,25 @@ protected String formatStrictIJson(T value) { return JsonbDateFormatter.IJSON_DATE_FORMATTER.format(toTemporalAccessor(value)); } + /** + * Append UTC zone in case zone is not set on formatter. + * + * @param formatter formatter + * @return zoned formatter + */ + protected DateTimeFormatter getZonedFormatter(DateTimeFormatter formatter) { + return formatter.getZone() != null + ? formatter + : formatter.withZone(UTC); + } + + @Override + void serializeValue(T value, JsonGenerator generator, SerializationContextImpl context) { + generator.write(valueSerializer.apply(value)); + } + @Override - protected void serialize(T obj, JsonGenerator generator, Marshaller marshaller) { - throw new UnsupportedOperationException("Not supported in DateTimeSerializer"); + void serializeKey(T key, JsonGenerator generator, SerializationContextImpl context) { + generator.writeKey(valueSerializer.apply(key)); } } diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/types/AbstractNumberSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/types/AbstractNumberSerializer.java new file mode 100644 index 000000000..e40d040a1 --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/serializer/types/AbstractNumberSerializer.java @@ -0,0 +1,57 @@ +/* + * 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.serializer.types; + +import java.text.DecimalFormat; +import java.text.NumberFormat; + +import jakarta.json.stream.JsonGenerator; + +import org.eclipse.yasson.internal.JsonbContext; +import org.eclipse.yasson.internal.JsonbNumberFormatter; +import org.eclipse.yasson.internal.SerializationContextImpl; +import org.eclipse.yasson.internal.model.customization.Customization; +import org.eclipse.yasson.internal.serializer.ModelSerializer; + +/** + * Base for all number related serializers. + */ +abstract class AbstractNumberSerializer extends TypeSerializer { + + private final ModelSerializer actualSerializer; + + AbstractNumberSerializer(TypeSerializerBuilder builder) { + super(builder); + actualSerializer = actualSerializer(builder.getCustomization(), builder.getJsonbContext()); + } + + @SuppressWarnings("unchecked") + private ModelSerializer actualSerializer(Customization customization, JsonbContext jsonbContext) { + JsonbNumberFormatter formatter = customization.getSerializeNumberFormatter(); + if (formatter == null) { + return (value, generator, context) -> writeValue((T) value, generator); + } + final NumberFormat format = NumberFormat + .getInstance(jsonbContext.getConfigProperties().getLocale(formatter.getLocale())); + ((DecimalFormat) format).applyPattern(formatter.getFormat()); + return (value, generator, context) -> generator.write(format.format(value)); + } + + @Override + void serializeValue(T value, JsonGenerator generator, SerializationContextImpl context) { + actualSerializer.serialize(value, generator, context); + } + + abstract void writeValue(T value, JsonGenerator generator); + +} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/types/BigDecimalSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/types/BigDecimalSerializer.java new file mode 100644 index 000000000..740d9dd25 --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/serializer/types/BigDecimalSerializer.java @@ -0,0 +1,32 @@ +/* + * 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.serializer.types; + +import java.math.BigDecimal; + +import jakarta.json.stream.JsonGenerator; + +/** + * Serializer of the {@link BigDecimal} type. + */ +class BigDecimalSerializer extends AbstractNumberSerializer { + + BigDecimalSerializer(TypeSerializerBuilder builder) { + super(builder); + } + + @Override + void writeValue(BigDecimal value, JsonGenerator generator) { + generator.write(value); + } +} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/types/BigIntegerSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/types/BigIntegerSerializer.java new file mode 100644 index 000000000..f93c3f1aa --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/serializer/types/BigIntegerSerializer.java @@ -0,0 +1,32 @@ +/* + * 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.serializer.types; + +import java.math.BigInteger; + +import jakarta.json.stream.JsonGenerator; + +/** + * Serializer of the {@link BigInteger} type. + */ +class BigIntegerSerializer extends AbstractNumberSerializer { + + BigIntegerSerializer(TypeSerializerBuilder builder) { + super(builder); + } + + @Override + void writeValue(BigInteger value, JsonGenerator generator) { + generator.write(value); + } +} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/types/BooleanSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/types/BooleanSerializer.java new file mode 100644 index 000000000..ff60782c6 --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/serializer/types/BooleanSerializer.java @@ -0,0 +1,32 @@ +/* + * 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.serializer.types; + +import jakarta.json.stream.JsonGenerator; + +import org.eclipse.yasson.internal.SerializationContextImpl; + +/** + * Serializer of the {@link Boolean} type. + */ +class BooleanSerializer extends TypeSerializer { + + BooleanSerializer(TypeSerializerBuilder serializerBuilder) { + super(serializerBuilder); + } + + @Override + void serializeValue(Boolean value, JsonGenerator generator, SerializationContextImpl context) { + generator.write(value); + } +} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/types/ByteSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/types/ByteSerializer.java new file mode 100644 index 000000000..ce26f9955 --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/serializer/types/ByteSerializer.java @@ -0,0 +1,31 @@ +/* + * 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.serializer.types; + +import jakarta.json.stream.JsonGenerator; + +/** + * Serializer of the {@link Byte} type. + */ +class ByteSerializer extends AbstractNumberSerializer { + + ByteSerializer(TypeSerializerBuilder builder) { + super(builder); + } + + @Override + void writeValue(Byte value, JsonGenerator generator) { + generator.write(value); + } + +} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/CalendarTypeSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/types/CalendarSerializer.java similarity index 69% rename from src/main/java/org/eclipse/yasson/internal/serializer/CalendarTypeSerializer.java rename to src/main/java/org/eclipse/yasson/internal/serializer/types/CalendarSerializer.java index 993524304..b6cc7b30a 100644 --- a/src/main/java/org/eclipse/yasson/internal/serializer/CalendarTypeSerializer.java +++ b/src/main/java/org/eclipse/yasson/internal/serializer/types/CalendarSerializer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2020 Oracle and/or its affiliates. All rights reserved. + * 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 @@ -10,7 +10,7 @@ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ -package org.eclipse.yasson.internal.serializer; +package org.eclipse.yasson.internal.serializer.types; import java.time.Instant; import java.time.ZonedDateTime; @@ -19,20 +19,13 @@ import java.util.Calendar; import java.util.Locale; -import org.eclipse.yasson.internal.model.customization.Customization; - /** - * Serializer for {@link Calendar} type. + * Serializer of the {@link Calendar} type. */ -public class CalendarTypeSerializer extends AbstractDateTimeSerializer { - - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public CalendarTypeSerializer(Customization customization) { - super(customization); +class CalendarSerializer extends AbstractDateSerializer { + + CalendarSerializer(TypeSerializerBuilder serializerBuilder) { + super(serializerBuilder); } @Override @@ -51,11 +44,8 @@ protected String formatDefault(Calendar value, Locale locale) { @Override protected TemporalAccessor toTemporalAccessor(Calendar object) { - return toZonedDateTime(object); - } - - private ZonedDateTime toZonedDateTime(Calendar object) { return ZonedDateTime.ofInstant(Instant.ofEpochMilli(object.getTimeInMillis()), object.getTimeZone().toZoneId()); } + } diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/types/CharSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/types/CharSerializer.java new file mode 100644 index 000000000..0a5630ee7 --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/serializer/types/CharSerializer.java @@ -0,0 +1,33 @@ +/* + * 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.serializer.types; + +import jakarta.json.stream.JsonGenerator; + +import org.eclipse.yasson.internal.SerializationContextImpl; + +/** + * Serializer of the {@link Character} type. + */ +class CharSerializer extends TypeSerializer { + + CharSerializer(TypeSerializerBuilder serializerBuilder) { + super(serializerBuilder); + } + + @Override + void serializeValue(Character value, JsonGenerator generator, SerializationContextImpl context) { + generator.write(String.valueOf(value)); + } + +} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/DateTypeSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/types/DateSerializer.java similarity index 73% rename from src/main/java/org/eclipse/yasson/internal/serializer/DateTypeSerializer.java rename to src/main/java/org/eclipse/yasson/internal/serializer/types/DateSerializer.java index 37f37d556..634da30ae 100644 --- a/src/main/java/org/eclipse/yasson/internal/serializer/DateTypeSerializer.java +++ b/src/main/java/org/eclipse/yasson/internal/serializer/types/DateSerializer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020 Oracle and/or its affiliates. All rights reserved. + * 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 @@ -10,7 +10,7 @@ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ -package org.eclipse.yasson.internal.serializer; +package org.eclipse.yasson.internal.serializer.types; import java.time.Instant; import java.time.format.DateTimeFormatter; @@ -18,23 +18,17 @@ import java.util.Date; import java.util.Locale; -import org.eclipse.yasson.internal.model.customization.Customization; +import org.eclipse.yasson.internal.JsonbDateFormatter; /** - * Serializer for {@link Date} type. - * @param date type + * Serializer of the {@link Date} type. */ -public class DateTypeSerializer extends AbstractDateTimeSerializer { - +class DateSerializer extends AbstractDateSerializer { + private static final DateTimeFormatter DEFAULT_DATE_FORMATTER = DateTimeFormatter.ISO_DATE_TIME.withZone(UTC); - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public DateTypeSerializer(Customization customization) { - super(customization); + DateSerializer(TypeSerializerBuilder serializerBuilder) { + super(serializerBuilder); } @Override @@ -61,4 +55,5 @@ protected String formatStrictIJson(Date value) { protected TemporalAccessor toTemporalAccessor(Date object) { return toInstant(object); } + } diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/types/DoubleSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/types/DoubleSerializer.java new file mode 100644 index 000000000..99ab3fa1a --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/serializer/types/DoubleSerializer.java @@ -0,0 +1,30 @@ +/* + * 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.serializer.types; + +import jakarta.json.stream.JsonGenerator; + +/** + * Serializer of the {@link Double} type. + */ +class DoubleSerializer extends AbstractNumberSerializer { + + DoubleSerializer(TypeSerializerBuilder builder) { + super(builder); + } + + @Override + void writeValue(Double value, JsonGenerator generator) { + generator.write(value); + } +} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/types/DurationSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/types/DurationSerializer.java new file mode 100644 index 000000000..46118d719 --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/serializer/types/DurationSerializer.java @@ -0,0 +1,35 @@ +/* + * 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.serializer.types; + +import java.time.Duration; + +import jakarta.json.stream.JsonGenerator; + +import org.eclipse.yasson.internal.SerializationContextImpl; + +/** + * Serializer of the {@link Duration} type. + */ +class DurationSerializer extends TypeSerializer { + + DurationSerializer(TypeSerializerBuilder serializerBuilder) { + super(serializerBuilder); + } + + @Override + void serializeValue(Duration value, JsonGenerator generator, SerializationContextImpl context) { + generator.write(value.toString()); + } + +} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/types/EnumSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/types/EnumSerializer.java new file mode 100644 index 000000000..39b14ae1f --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/serializer/types/EnumSerializer.java @@ -0,0 +1,37 @@ +/* + * 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.serializer.types; + +import jakarta.json.stream.JsonGenerator; + +import org.eclipse.yasson.internal.SerializationContextImpl; + +/** + * Serializer of the {@link Enum} types. + */ +class EnumSerializer extends TypeSerializer> { + + EnumSerializer(TypeSerializerBuilder serializerBuilder) { + super(serializerBuilder); + } + + @Override + void serializeValue(Enum value, JsonGenerator generator, SerializationContextImpl context) { + generator.write(value.name()); + } + + @Override + void serializeKey(Enum key, JsonGenerator generator, SerializationContextImpl context) { + generator.writeKey(key.name()); + } +} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/types/FloatSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/types/FloatSerializer.java new file mode 100644 index 000000000..2a87f6983 --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/serializer/types/FloatSerializer.java @@ -0,0 +1,34 @@ +/* + * 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.serializer.types; + +import java.math.BigDecimal; + +import jakarta.json.stream.JsonGenerator; + +/** + * Serializer of the {@link Float} type. + */ +class FloatSerializer extends AbstractNumberSerializer { + + FloatSerializer(TypeSerializerBuilder builder) { + super(builder); + } + + @Override + void writeValue(Float value, JsonGenerator generator) { + //floats lose precision, after upcasting to doubles in jsonp + generator.write(new BigDecimal(String.valueOf(value))); + } + +} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/InstantTypeSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/types/InstantSerializer.java similarity index 68% rename from src/main/java/org/eclipse/yasson/internal/serializer/InstantTypeSerializer.java rename to src/main/java/org/eclipse/yasson/internal/serializer/types/InstantSerializer.java index 78a4f804b..0ea3a5703 100644 --- a/src/main/java/org/eclipse/yasson/internal/serializer/InstantTypeSerializer.java +++ b/src/main/java/org/eclipse/yasson/internal/serializer/types/InstantSerializer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2020 Oracle and/or its affiliates. All rights reserved. + * 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 @@ -10,26 +10,21 @@ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ -package org.eclipse.yasson.internal.serializer; +package org.eclipse.yasson.internal.serializer.types; import java.time.Instant; import java.time.format.DateTimeFormatter; import java.util.Locale; -import org.eclipse.yasson.internal.model.customization.Customization; +import org.eclipse.yasson.internal.JsonbDateFormatter; /** - * Serializer for {@link Instant} type. + * Serializer of the {@link Instant} type. */ -public class InstantTypeSerializer extends AbstractDateTimeSerializer { - - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public InstantTypeSerializer(Customization customization) { - super(customization); +class InstantSerializer extends AbstractDateSerializer { + + InstantSerializer(TypeSerializerBuilder serializerBuilder) { + super(serializerBuilder); } @Override @@ -51,5 +46,4 @@ protected String formatWithFormatter(Instant value, DateTimeFormatter formatter) protected String formatStrictIJson(Instant value) { return JsonbDateFormatter.IJSON_DATE_FORMATTER.withZone(UTC).format(value); } - } diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/types/IntegerSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/types/IntegerSerializer.java new file mode 100644 index 000000000..fe0bf8292 --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/serializer/types/IntegerSerializer.java @@ -0,0 +1,31 @@ +/* + * 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.serializer.types; + +import jakarta.json.stream.JsonGenerator; + +/** + * Serializer of the {@link Integer} type. + */ +class IntegerSerializer extends AbstractNumberSerializer { + + IntegerSerializer(TypeSerializerBuilder builder) { + super(builder); + } + + @Override + void writeValue(Integer value, JsonGenerator generator) { + generator.write(value); + } + +} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/types/JsonValueSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/types/JsonValueSerializer.java new file mode 100644 index 000000000..9ef0c1e95 --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/serializer/types/JsonValueSerializer.java @@ -0,0 +1,34 @@ +/* + * 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.serializer.types; + +import jakarta.json.JsonValue; +import jakarta.json.stream.JsonGenerator; + +import org.eclipse.yasson.internal.SerializationContextImpl; + +/** + * Serializer of the {@link JsonValue} type. + */ +class JsonValueSerializer extends TypeSerializer { + + JsonValueSerializer(TypeSerializerBuilder serializerBuilder) { + super(serializerBuilder); + } + + @Override + void serializeValue(JsonValue value, JsonGenerator generator, SerializationContextImpl context) { + generator.write(value); + } + +} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/LocalDateTypeSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/types/LocalDateSerializer.java similarity index 70% rename from src/main/java/org/eclipse/yasson/internal/serializer/LocalDateTypeSerializer.java rename to src/main/java/org/eclipse/yasson/internal/serializer/types/LocalDateSerializer.java index 65206ff2b..f156c53fd 100644 --- a/src/main/java/org/eclipse/yasson/internal/serializer/LocalDateTypeSerializer.java +++ b/src/main/java/org/eclipse/yasson/internal/serializer/types/LocalDateSerializer.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 @@ -10,7 +10,7 @@ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ -package org.eclipse.yasson.internal.serializer; +package org.eclipse.yasson.internal.serializer.types; import java.time.Instant; import java.time.LocalDate; @@ -18,22 +18,17 @@ import java.time.format.DateTimeFormatter; import java.util.Locale; -import org.eclipse.yasson.internal.model.customization.Customization; +import org.eclipse.yasson.internal.JsonbDateFormatter; /** - * Serializer for {@link LocalDate} type. + * Serializer of the {@link LocalDate} type. */ -public class LocalDateTypeSerializer extends AbstractDateTimeSerializer { +class LocalDateSerializer extends AbstractDateSerializer { private static final DateTimeFormatter DEFAULT_FORMAT = DateTimeFormatter.ISO_LOCAL_DATE.withZone(UTC); - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public LocalDateTypeSerializer(Customization customization) { - super(customization); + LocalDateSerializer(TypeSerializerBuilder serializerBuilder) { + super(serializerBuilder); } @Override @@ -51,4 +46,5 @@ protected String formatStrictIJson(LocalDate value) { final ZonedDateTime zonedDateTime = value.atTime(0, 0, 0).atZone(UTC); return JsonbDateFormatter.IJSON_DATE_FORMATTER.withZone(UTC).format(zonedDateTime); } + } diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/LocalDateTimeTypeSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/types/LocalDateTimeSerializer.java similarity index 70% rename from src/main/java/org/eclipse/yasson/internal/serializer/LocalDateTimeTypeSerializer.java rename to src/main/java/org/eclipse/yasson/internal/serializer/types/LocalDateTimeSerializer.java index 39fffb0aa..04ffa1d9a 100644 --- a/src/main/java/org/eclipse/yasson/internal/serializer/LocalDateTimeTypeSerializer.java +++ b/src/main/java/org/eclipse/yasson/internal/serializer/types/LocalDateTimeSerializer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2020 Oracle and/or its affiliates. All rights reserved. + * 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 @@ -10,7 +10,7 @@ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ -package org.eclipse.yasson.internal.serializer; +package org.eclipse.yasson.internal.serializer.types; import java.time.Instant; import java.time.LocalDateTime; @@ -18,20 +18,15 @@ import java.time.format.DateTimeFormatter; import java.util.Locale; -import org.eclipse.yasson.internal.model.customization.Customization; +import org.eclipse.yasson.internal.JsonbDateFormatter; /** - * Serializer for {@link LocalDateTime} type. + * Serializer of the {@link LocalDateTime} type. */ -public class LocalDateTimeTypeSerializer extends AbstractDateTimeSerializer { - - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public LocalDateTimeTypeSerializer(Customization customization) { - super(customization); +class LocalDateTimeSerializer extends AbstractDateSerializer { + + LocalDateTimeSerializer(TypeSerializerBuilder builder) { + super(builder); } @Override @@ -54,4 +49,5 @@ protected String formatStrictIJson(LocalDateTime value) { final ZonedDateTime zonedDateTime = value.atZone(UTC); return JsonbDateFormatter.IJSON_DATE_FORMATTER.format(zonedDateTime); } + } diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/LocalTimeTypeSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/types/LocalTimeSerializer.java similarity index 67% rename from src/main/java/org/eclipse/yasson/internal/serializer/LocalTimeTypeSerializer.java rename to src/main/java/org/eclipse/yasson/internal/serializer/types/LocalTimeSerializer.java index f975bfa30..4be94fe36 100644 --- a/src/main/java/org/eclipse/yasson/internal/serializer/LocalTimeTypeSerializer.java +++ b/src/main/java/org/eclipse/yasson/internal/serializer/types/LocalTimeSerializer.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 @@ -10,7 +10,7 @@ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ -package org.eclipse.yasson.internal.serializer; +package org.eclipse.yasson.internal.serializer.types; import java.time.Instant; import java.time.LocalTime; @@ -19,22 +19,16 @@ import jakarta.json.bind.JsonbException; -import org.eclipse.yasson.internal.model.customization.Customization; import org.eclipse.yasson.internal.properties.MessageKeys; import org.eclipse.yasson.internal.properties.Messages; /** - * Serializer for {@link LocalTime} type. + * Serializer of the {@link LocalTime} type. */ -public class LocalTimeTypeSerializer extends AbstractDateTimeSerializer { - - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public LocalTimeTypeSerializer(Customization customization) { - super(customization); +class LocalTimeSerializer extends AbstractDateSerializer { + + LocalTimeSerializer(TypeSerializerBuilder serializerBuilder) { + super(serializerBuilder); } @Override diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/types/LongSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/types/LongSerializer.java new file mode 100644 index 000000000..e522e7a54 --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/serializer/types/LongSerializer.java @@ -0,0 +1,30 @@ +/* + * 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.serializer.types; + +import jakarta.json.stream.JsonGenerator; + +/** + * Serializer of the {@link Long} type. + */ +class LongSerializer extends AbstractNumberSerializer { + + LongSerializer(TypeSerializerBuilder builder) { + super(builder); + } + + @Override + void writeValue(Long value, JsonGenerator generator) { + generator.write(value); + } +} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/MonthDayTypeSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/types/MonthDayTypeSerializer.java similarity index 66% rename from src/main/java/org/eclipse/yasson/internal/serializer/MonthDayTypeSerializer.java rename to src/main/java/org/eclipse/yasson/internal/serializer/types/MonthDayTypeSerializer.java index 8eb446450..0108e464d 100644 --- a/src/main/java/org/eclipse/yasson/internal/serializer/MonthDayTypeSerializer.java +++ b/src/main/java/org/eclipse/yasson/internal/serializer/types/MonthDayTypeSerializer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. + * 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 @@ -10,7 +10,7 @@ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ -package org.eclipse.yasson.internal.serializer; +package org.eclipse.yasson.internal.serializer.types; import java.time.Instant; import java.time.MonthDay; @@ -18,24 +18,17 @@ import java.time.format.DateTimeFormatter; import java.util.Locale; -import org.eclipse.yasson.internal.model.customization.Customization; - /** - * Serializer for {@link MonthDay} type. + * Serializer of the {@link MonthDay} type. */ -public class MonthDayTypeSerializer extends AbstractDateTimeSerializer { +class MonthDayTypeSerializer extends AbstractDateSerializer { private static final int YEAR_NUMBER = Year.now().getValue(); private static final DateTimeFormatter DEFAULT_FORMAT = DateTimeFormatter.ofPattern("--MM-dd").withZone(UTC); - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public MonthDayTypeSerializer(Customization customization) { - super(customization); + MonthDayTypeSerializer(TypeSerializerBuilder serializerBuilder) { + super(serializerBuilder); } @Override diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/types/NumberSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/types/NumberSerializer.java new file mode 100644 index 000000000..0dff22bac --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/serializer/types/NumberSerializer.java @@ -0,0 +1,32 @@ +/* + * 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.serializer.types; + +import java.math.BigDecimal; + +import jakarta.json.stream.JsonGenerator; + +/** + * Serializer of the {@link Number} type. + */ +class NumberSerializer extends AbstractNumberSerializer { + + NumberSerializer(TypeSerializerBuilder builder) { + super(builder); + } + + @Override + void writeValue(Number value, JsonGenerator generator) { + generator.write(new BigDecimal(String.valueOf(value))); + } +} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/types/ObjectTypeSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/types/ObjectTypeSerializer.java new file mode 100644 index 000000000..db9ef9539 --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/serializer/types/ObjectTypeSerializer.java @@ -0,0 +1,80 @@ +/* + * 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.serializer.types; + +import java.lang.reflect.Type; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import jakarta.json.stream.JsonGenerator; + +import org.eclipse.yasson.internal.SerializationContextImpl; +import org.eclipse.yasson.internal.model.customization.Customization; +import org.eclipse.yasson.internal.serializer.ModelSerializer; +import org.eclipse.yasson.internal.serializer.SerializationModelCreator; + +/** + * Object type serializer. Dynamically resolves the serialized type based on the serialized instance class. + */ +public class ObjectTypeSerializer extends TypeSerializer { + + private final Customization customization; + + private final Map, ModelSerializer> cache; + private final List chain; + private final boolean isKey; + + ObjectTypeSerializer(TypeSerializerBuilder serializerBuilder) { + super(serializerBuilder); + this.customization = serializerBuilder.getCustomization(); + this.cache = new ConcurrentHashMap<>(); + this.chain = new LinkedList<>(serializerBuilder.getChain()); + this.isKey = serializerBuilder.isKey(); + } + + @Override + void serializeValue(Object value, JsonGenerator generator, SerializationContextImpl context) { + //Dynamically resolved type during runtime. Cached in SerializationModelCreator. + findSerializer(value, generator, context); + } + + @Override + void serializeKey(Object key, JsonGenerator generator, SerializationContextImpl context) { + if (key == null) { + super.serializeKey(null, generator, context); + return; + } + //Dynamically resolved type during runtime. Cached in SerializationModelCreator. + findSerializer(key, generator, context); + } + + private void findSerializer(Object key, JsonGenerator generator, SerializationContextImpl context) { + Class clazz = key.getClass(); + cache.computeIfAbsent(clazz, aClass -> { + SerializationModelCreator serializationModelCreator = context.getJsonbContext().getSerializationModelCreator(); + return serializationModelCreator.serializerChainRuntime(new LinkedList<>(chain), clazz, customization, false, isKey); + }).serialize(key, generator, context); + } + + /** + * Add serializer to the cache. + * + * @param clazz class of the serializer + * @param modelSerializer model serializer bound to the class + */ + public void addSpecificSerializer(Class clazz, ModelSerializer modelSerializer) { + cache.put(clazz, modelSerializer); + } +} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/OffsetDateTimeTypeSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/types/OffsetDateTimeSerializer.java similarity index 60% rename from src/main/java/org/eclipse/yasson/internal/serializer/OffsetDateTimeTypeSerializer.java rename to src/main/java/org/eclipse/yasson/internal/serializer/types/OffsetDateTimeSerializer.java index 0cdf0eddf..eb463ea1c 100644 --- a/src/main/java/org/eclipse/yasson/internal/serializer/OffsetDateTimeTypeSerializer.java +++ b/src/main/java/org/eclipse/yasson/internal/serializer/types/OffsetDateTimeSerializer.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 @@ -10,27 +10,20 @@ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ -package org.eclipse.yasson.internal.serializer; +package org.eclipse.yasson.internal.serializer.types; import java.time.Instant; import java.time.OffsetDateTime; import java.time.format.DateTimeFormatter; import java.util.Locale; -import org.eclipse.yasson.internal.model.customization.Customization; - /** - * Serializer for {@link OffsetDateTime} type. + * Serializer of the {@link OffsetDateTime} type. */ -public class OffsetDateTimeTypeSerializer extends AbstractDateTimeSerializer { +class OffsetDateTimeSerializer extends AbstractDateSerializer { - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public OffsetDateTimeTypeSerializer(Customization customization) { - super(customization); + OffsetDateTimeSerializer(TypeSerializerBuilder serializerBuilder) { + super(serializerBuilder); } @Override diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/OffsetTimeTypeSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/types/OffsetTimeSerializer.java similarity index 67% rename from src/main/java/org/eclipse/yasson/internal/serializer/OffsetTimeTypeSerializer.java rename to src/main/java/org/eclipse/yasson/internal/serializer/types/OffsetTimeSerializer.java index fcd383259..8610c196a 100644 --- a/src/main/java/org/eclipse/yasson/internal/serializer/OffsetTimeTypeSerializer.java +++ b/src/main/java/org/eclipse/yasson/internal/serializer/types/OffsetTimeSerializer.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 @@ -10,7 +10,7 @@ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ -package org.eclipse.yasson.internal.serializer; +package org.eclipse.yasson.internal.serializer.types; import java.time.Instant; import java.time.OffsetTime; @@ -19,22 +19,16 @@ import jakarta.json.bind.JsonbException; -import org.eclipse.yasson.internal.model.customization.Customization; import org.eclipse.yasson.internal.properties.MessageKeys; import org.eclipse.yasson.internal.properties.Messages; /** - * Serializer for {@link OffsetTime} type. + * Serializer of the {@link OffsetTime} type. */ -public class OffsetTimeTypeSerializer extends AbstractDateTimeSerializer { - - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public OffsetTimeTypeSerializer(Customization customization) { - super(customization); +class OffsetTimeSerializer extends AbstractDateSerializer { + + OffsetTimeSerializer(TypeSerializerBuilder serializerBuilder) { + super(serializerBuilder); } @Override diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/types/OptionalDoubleSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/types/OptionalDoubleSerializer.java new file mode 100644 index 000000000..a0e0a0fc2 --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/serializer/types/OptionalDoubleSerializer.java @@ -0,0 +1,42 @@ +/* + * 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.serializer.types; + +import java.util.OptionalDouble; + +import jakarta.json.stream.JsonGenerator; + +import org.eclipse.yasson.internal.SerializationContextImpl; +import org.eclipse.yasson.internal.serializer.ModelSerializer; + +/** + * Serializer of the {@link OptionalDouble} type. + */ +class OptionalDoubleSerializer implements ModelSerializer { + + private final ModelSerializer typeSerializer; + + OptionalDoubleSerializer(ModelSerializer typeSerializer) { + this.typeSerializer = typeSerializer; + } + + @Override + public void serialize(Object value, JsonGenerator generator, SerializationContextImpl context) { + OptionalDouble optionalDouble = (OptionalDouble) value; + if (optionalDouble.isPresent()) { + typeSerializer.serialize(optionalDouble.getAsDouble(), generator, context); + } else { + typeSerializer.serialize(null, generator, context); + } + } +} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/types/OptionalIntSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/types/OptionalIntSerializer.java new file mode 100644 index 000000000..d80448055 --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/serializer/types/OptionalIntSerializer.java @@ -0,0 +1,42 @@ +/* + * 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.serializer.types; + +import java.util.OptionalInt; + +import jakarta.json.stream.JsonGenerator; + +import org.eclipse.yasson.internal.SerializationContextImpl; +import org.eclipse.yasson.internal.serializer.ModelSerializer; + +/** + * Serializer of the {@link OptionalInt} type. + */ +class OptionalIntSerializer implements ModelSerializer { + + private final ModelSerializer typeSerializer; + + OptionalIntSerializer(ModelSerializer typeSerializer) { + this.typeSerializer = typeSerializer; + } + + @Override + public void serialize(Object value, JsonGenerator generator, SerializationContextImpl context) { + OptionalInt optionalInt = (OptionalInt) value; + if (optionalInt.isPresent()) { + typeSerializer.serialize(optionalInt.getAsInt(), generator, context); + } else { + typeSerializer.serialize(null, generator, context); + } + } +} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/types/OptionalLongSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/types/OptionalLongSerializer.java new file mode 100644 index 000000000..7b7b6697b --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/serializer/types/OptionalLongSerializer.java @@ -0,0 +1,42 @@ +/* + * 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.serializer.types; + +import java.util.OptionalLong; + +import jakarta.json.stream.JsonGenerator; + +import org.eclipse.yasson.internal.SerializationContextImpl; +import org.eclipse.yasson.internal.serializer.ModelSerializer; + +/** + * Serializer of the {@link OptionalLong} type. + */ +class OptionalLongSerializer implements ModelSerializer { + + private final ModelSerializer typeSerializer; + + OptionalLongSerializer(ModelSerializer typeSerializer) { + this.typeSerializer = typeSerializer; + } + + @Override + public void serialize(Object value, JsonGenerator generator, SerializationContextImpl context) { + OptionalLong optionalLong = (OptionalLong) value; + if (optionalLong.isPresent()) { + typeSerializer.serialize(optionalLong.getAsLong(), generator, context); + } else { + typeSerializer.serialize(null, generator, context); + } + } +} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/types/PathSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/types/PathSerializer.java new file mode 100644 index 000000000..57388cc20 --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/serializer/types/PathSerializer.java @@ -0,0 +1,35 @@ +/* + * 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.serializer.types; + +import java.nio.file.Path; + +import jakarta.json.stream.JsonGenerator; + +import org.eclipse.yasson.internal.SerializationContextImpl; + +/** + * Serializer of the {@link Path} type. + */ +class PathSerializer extends TypeSerializer { + + PathSerializer(TypeSerializerBuilder serializerBuilder) { + super(serializerBuilder); + } + + @Override + void serializeValue(Path value, JsonGenerator generator, SerializationContextImpl context) { + generator.write(value.toString()); + } + +} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/types/PeriodSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/types/PeriodSerializer.java new file mode 100644 index 000000000..d2f3e63ce --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/serializer/types/PeriodSerializer.java @@ -0,0 +1,35 @@ +/* + * 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.serializer.types; + +import java.time.Period; + +import jakarta.json.stream.JsonGenerator; + +import org.eclipse.yasson.internal.SerializationContextImpl; + +/** + * Serializer of the {@link Period} type. + */ +class PeriodSerializer extends TypeSerializer { + + PeriodSerializer(TypeSerializerBuilder serializerBuilder) { + super(serializerBuilder); + } + + @Override + void serializeValue(Period value, JsonGenerator generator, SerializationContextImpl context) { + generator.write(value.toString()); + } + +} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/types/ShortSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/types/ShortSerializer.java new file mode 100644 index 000000000..17bc7eba4 --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/serializer/types/ShortSerializer.java @@ -0,0 +1,31 @@ +/* + * 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.serializer.types; + +import jakarta.json.stream.JsonGenerator; + +/** + * Serializer of the {@link Short} type. + */ +class ShortSerializer extends AbstractNumberSerializer { + + ShortSerializer(TypeSerializerBuilder builder) { + super(builder); + } + + @Override + void writeValue(Short value, JsonGenerator generator) { + generator.write(value); + } + +} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/SqlDateTypeSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/types/SqlDateSerializer.java similarity index 77% rename from src/main/java/org/eclipse/yasson/internal/serializer/SqlDateTypeSerializer.java rename to src/main/java/org/eclipse/yasson/internal/serializer/types/SqlDateSerializer.java index e64b714cb..aad680fb4 100644 --- a/src/main/java/org/eclipse/yasson/internal/serializer/SqlDateTypeSerializer.java +++ b/src/main/java/org/eclipse/yasson/internal/serializer/types/SqlDateSerializer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 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,28 +10,20 @@ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ -package org.eclipse.yasson.internal.serializer; +package org.eclipse.yasson.internal.serializer.types; import java.time.Instant; import java.time.format.DateTimeFormatter; import java.util.Date; import java.util.Locale; -import org.eclipse.yasson.internal.model.customization.Customization; - /** * Common serializer for {@link Date} and {@link java.sql.Date} types. - * @param date type */ -public class SqlDateTypeSerializer extends DateTypeSerializer { - - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public SqlDateTypeSerializer(Customization customization) { - super(customization); +class SqlDateSerializer extends DateSerializer { + + SqlDateSerializer(TypeSerializerBuilder serializerBuilder) { + super(serializerBuilder); } @Override @@ -62,4 +54,4 @@ protected String formatWithFormatter(Date value, DateTimeFormatter formatter) { return super.formatWithFormatter(value, formatter); } } -} \ No newline at end of file +} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/SqlTimestampTypeSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/types/SqlTimestampSerializer.java similarity index 53% rename from src/main/java/org/eclipse/yasson/internal/serializer/SqlTimestampTypeSerializer.java rename to src/main/java/org/eclipse/yasson/internal/serializer/types/SqlTimestampSerializer.java index e9ea658b6..166047342 100644 --- a/src/main/java/org/eclipse/yasson/internal/serializer/SqlTimestampTypeSerializer.java +++ b/src/main/java/org/eclipse/yasson/internal/serializer/types/SqlTimestampSerializer.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 @@ -10,32 +10,25 @@ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ -package org.eclipse.yasson.internal.serializer; +package org.eclipse.yasson.internal.serializer.types; import java.sql.Timestamp; import java.time.Instant; import java.time.format.DateTimeFormatter; import java.util.Locale; -import org.eclipse.yasson.internal.model.customization.Customization; - /** - * Serializer for {@link java.sql.Timestamp} type. + * Serializer of the {@link Timestamp} type. */ -public class SqlTimestampTypeSerializer extends AbstractDateTimeSerializer { +class SqlTimestampSerializer extends AbstractDateSerializer { /** - * Default Yasson {@link java.time.format.DateTimeFormatter}. + * Default Yasson {@link DateTimeFormatter}. */ - public static final DateTimeFormatter DEFAULT_FORMATTER = DateTimeFormatter.ISO_DATE_TIME.withZone(UTC); + private static final DateTimeFormatter DEFAULT_FORMATTER = DateTimeFormatter.ISO_DATE_TIME.withZone(UTC); - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public SqlTimestampTypeSerializer(Customization customization) { - super(customization); + SqlTimestampSerializer(TypeSerializerBuilder serializerBuilder) { + super(serializerBuilder); } @Override diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/types/StringSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/types/StringSerializer.java new file mode 100644 index 000000000..63b5309b9 --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/serializer/types/StringSerializer.java @@ -0,0 +1,46 @@ +/* + * 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.serializer.types; + +import java.nio.charset.StandardCharsets; + +import jakarta.json.bind.JsonbException; +import jakarta.json.stream.JsonGenerator; + +import org.eclipse.yasson.internal.JsonbConfigProperties; +import org.eclipse.yasson.internal.SerializationContextImpl; +import org.eclipse.yasson.internal.properties.MessageKeys; +import org.eclipse.yasson.internal.properties.Messages; + +/** + * Serializer of the {@link String} type. + */ +class StringSerializer extends TypeSerializer { + + StringSerializer(TypeSerializerBuilder serializerBuilder) { + super(serializerBuilder); + } + + @Override + void serializeValue(String value, JsonGenerator generator, SerializationContextImpl context) { + JsonbConfigProperties configProperties = context.getJsonbContext().getConfigProperties(); + if (configProperties.isStrictIJson()) { + String newString = new String(value.getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8); + if (!newString.equals(value)) { + throw new JsonbException(Messages.getMessage(MessageKeys.UNPAIRED_SURROGATE)); + } + } + generator.write(value); + } + +} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/types/TimeZoneSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/types/TimeZoneSerializer.java new file mode 100644 index 000000000..e35e5f447 --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/serializer/types/TimeZoneSerializer.java @@ -0,0 +1,34 @@ +/* + * 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 + * 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.serializer.types; + +import java.util.TimeZone; + +import jakarta.json.stream.JsonGenerator; + +import org.eclipse.yasson.internal.SerializationContextImpl; + +/** + * Serializer of the {@link TimeZone} type. + */ +class TimeZoneSerializer extends TypeSerializer { + + TimeZoneSerializer(TypeSerializerBuilder serializerBuilder) { + super(serializerBuilder); + } + + @Override + void serializeValue(TimeZone value, JsonGenerator generator, SerializationContextImpl context) { + generator.write(value.getID()); + } +} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/types/TypeSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/types/TypeSerializer.java new file mode 100644 index 000000000..badbdb9eb --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/serializer/types/TypeSerializer.java @@ -0,0 +1,65 @@ +/* + * 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.serializer.types; + +import jakarta.json.stream.JsonGenerator; + +import org.eclipse.yasson.internal.SerializationContextImpl; +import org.eclipse.yasson.internal.serializer.ModelSerializer; + +/** + * Base for all the type serializers. + */ +abstract class TypeSerializer implements ModelSerializer { + + private final ModelSerializer serializer; + + TypeSerializer(TypeSerializerBuilder serializerBuilder) { + if (serializerBuilder.isKey()) { + serializer = new KeySerializer(); + } else { + serializer = new ValueSerializer(); + } + } + + @Override + public void serialize(Object value, JsonGenerator generator, SerializationContextImpl context) { + serializer.serialize(value, generator, context); + } + + abstract void serializeValue(T value, JsonGenerator generator, SerializationContextImpl context); + + void serializeKey(T key, JsonGenerator generator, SerializationContextImpl context) { + generator.writeKey(String.valueOf(key)); + } + + private final class ValueSerializer implements ModelSerializer { + + @SuppressWarnings("unchecked") + @Override + public void serialize(Object value, JsonGenerator generator, SerializationContextImpl context) { + serializeValue((T) value, generator, context); + } + + } + + private final class KeySerializer implements ModelSerializer { + + @SuppressWarnings("unchecked") + @Override + public void serialize(Object value, JsonGenerator generator, SerializationContextImpl context) { + serializeKey((T) value, generator, context); + } + + } +} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/types/TypeSerializerBuilder.java b/src/main/java/org/eclipse/yasson/internal/serializer/types/TypeSerializerBuilder.java new file mode 100644 index 000000000..84257157a --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/serializer/types/TypeSerializerBuilder.java @@ -0,0 +1,63 @@ +/* + * 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.serializer.types; + +import java.lang.reflect.Type; +import java.util.List; + +import org.eclipse.yasson.internal.JsonbContext; +import org.eclipse.yasson.internal.model.customization.Customization; + +/** + * Type serializer data holder object used during serializer creation. + */ +class TypeSerializerBuilder { + + private final List chain; + private final Class clazz; + private final Customization customization; + private final JsonbContext jsonbContext; + private final boolean key; + + TypeSerializerBuilder(List chain, + Class clazz, + Customization customization, + JsonbContext jsonbContext, + boolean key) { + this.chain = chain; + this.clazz = clazz; + this.customization = customization; + this.jsonbContext = jsonbContext; + this.key = key; + } + + public List getChain() { + return chain; + } + + public Class getClazz() { + return clazz; + } + + public Customization getCustomization() { + return customization; + } + + public JsonbContext getJsonbContext() { + return jsonbContext; + } + + public boolean isKey() { + return key; + } +} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/types/TypeSerializers.java b/src/main/java/org/eclipse/yasson/internal/serializer/types/TypeSerializers.java new file mode 100644 index 000000000..c25fc897a --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/serializer/types/TypeSerializers.java @@ -0,0 +1,228 @@ +/* + * 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.serializer.types; + +import java.lang.reflect.Type; +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.MonthDay; +import java.time.OffsetDateTime; +import java.time.OffsetTime; +import java.time.Period; +import java.time.YearMonth; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.util.Calendar; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +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 java.util.function.Function; + +import javax.xml.datatype.XMLGregorianCalendar; + +import jakarta.json.JsonNumber; +import jakarta.json.JsonString; +import jakarta.json.JsonValue; +import jakarta.json.bind.JsonbException; + +import org.eclipse.yasson.internal.JsonbContext; +import org.eclipse.yasson.internal.model.customization.Customization; +import org.eclipse.yasson.internal.serializer.ModelSerializer; +import org.eclipse.yasson.internal.serializer.SerializationModelCreator; + +import static org.eclipse.yasson.internal.BuiltInTypes.isClassAvailable; + +/** + * Specific type serializers. + */ +public class TypeSerializers { + + private static final Map, Function> SERIALIZERS; + private static final Set> SUPPORTED_MAP_KEYS; + + private static final Map, Class> OPTIONALS; + + static { + Map, Function> cache = new HashMap<>(); + cache.put(Byte.class, ByteSerializer::new); + cache.put(Byte.TYPE, ByteSerializer::new); + cache.put(BigDecimal.class, BigDecimalSerializer::new); + cache.put(BigInteger.class, BigIntegerSerializer::new); + cache.put(Boolean.class, BooleanSerializer::new); + cache.put(Boolean.TYPE, BooleanSerializer::new); + cache.put(Calendar.class, CalendarSerializer::new); + cache.put(Character.class, CharSerializer::new); + cache.put(Character.TYPE, CharSerializer::new); + cache.put(Date.class, DateSerializer::new); + cache.put(Double.class, DoubleSerializer::new); + cache.put(Double.TYPE, DoubleSerializer::new); + cache.put(Duration.class, DurationSerializer::new); + cache.put(Float.class, FloatSerializer::new); + cache.put(Float.TYPE, FloatSerializer::new); + cache.put(Integer.class, IntegerSerializer::new); + cache.put(Integer.TYPE, IntegerSerializer::new); + cache.put(Instant.class, InstantSerializer::new); + cache.put(LocalDateTime.class, LocalDateTimeSerializer::new); + cache.put(LocalDate.class, LocalDateSerializer::new); + cache.put(LocalTime.class, LocalTimeSerializer::new); + cache.put(Long.class, LongSerializer::new); + cache.put(Long.TYPE, LongSerializer::new); + cache.put(MonthDay.class, MonthDayTypeSerializer::new); + cache.put(Number.class, NumberSerializer::new); + cache.put(Object.class, ObjectTypeSerializer::new); + cache.put(OffsetDateTime.class, OffsetDateTimeSerializer::new); + cache.put(OffsetTime.class, OffsetTimeSerializer::new); + cache.put(Path.class, PathSerializer::new); + cache.put(Period.class, PeriodSerializer::new); + cache.put(Short.class, ShortSerializer::new); + cache.put(Short.TYPE, ShortSerializer::new); + cache.put(String.class, StringSerializer::new); + cache.put(TimeZone.class, TimeZoneSerializer::new); + cache.put(URI.class, UriSerializer::new); + cache.put(URL.class, UrlSerializer::new); + cache.put(UUID.class, UuidSerializer::new); + if (isClassAvailable("javax.xml.datatype.XMLGregorianCalendar")) { + cache.put(XMLGregorianCalendar.class, XmlGregorianCalendarSerializer::new); + } + cache.put(YearMonth.class, YearMonthTypeSerializer::new); + cache.put(ZonedDateTime.class, ZonedDateTimeSerializer::new); + cache.put(ZoneId.class, ZoneIdSerializer::new); + cache.put(ZoneOffset.class, ZoneOffsetSerializer::new); + if (isClassAvailable("java.sql.Date")) { + cache.put(Date.class, SqlDateSerializer::new); + cache.put(java.sql.Date.class, SqlDateSerializer::new); + cache.put(java.sql.Timestamp.class, SqlTimestampSerializer::new); + } + SERIALIZERS = Map.copyOf(cache); + + Map, Class> optionals = new HashMap<>(); + optionals.put(OptionalDouble.class, Double.class); + optionals.put(OptionalInt.class, Integer.class); + optionals.put(OptionalLong.class, Long.class); + OPTIONALS = Map.copyOf(optionals); + + Set> mapKeys = new HashSet<>(SERIALIZERS.keySet()); + mapKeys.addAll(optionals.keySet()); + mapKeys.add(JsonNumber.class); + mapKeys.add(JsonString.class); + mapKeys.remove(Object.class); + SUPPORTED_MAP_KEYS = Set.copyOf(mapKeys); + + } + + private TypeSerializers() { + throw new IllegalStateException("Util class cannot be instantiated"); + } + + /** + * Whether type is the supported key type. + * + * @param clazz key type + * @return whether type is supported key type + */ + public static boolean isSupportedMapKey(Class clazz) { + return Enum.class.isAssignableFrom(clazz) || SUPPORTED_MAP_KEYS.contains(clazz); + } + + /** + * Create new type serializer. + * + * @param clazz type of the serializer + * @param customization serializer customization + * @param jsonbContext jsonb context + * @return new type serializer + */ + public static ModelSerializer getTypeSerializer(Class clazz, Customization customization, JsonbContext jsonbContext) { + return getTypeSerializer(Collections.emptyList(), clazz, customization, jsonbContext, false); + } + + /** + * Create new type serializer. + * + * @param chain chain of the type predecessors + * @param clazz type of the serializer + * @param customization serializer customization + * @param jsonbContext jsonb context + * @param key whether serializer is a key + * @return new type serializer + */ + public static ModelSerializer getTypeSerializer(List chain, + Class clazz, + Customization customization, + JsonbContext jsonbContext, + boolean key) { + Class current = clazz; + List chainClone = new LinkedList<>(chain); + TypeSerializerBuilder builder = new TypeSerializerBuilder(chainClone, clazz, customization, jsonbContext, key); + ModelSerializer typeSerializer = null; + if (Object.class.equals(current)) { + return SERIALIZERS.get(current).apply(builder); + } + if (OPTIONALS.containsKey(current)) { + Class optionalInner = OPTIONALS.get(current); + ModelSerializer serializer = getTypeSerializer(chainClone, optionalInner, customization, jsonbContext, key); + if (OptionalInt.class.equals(current)) { + return new OptionalIntSerializer(serializer); + } else if (OptionalLong.class.equals(current)) { + return new OptionalLongSerializer(serializer); + } else if (OptionalDouble.class.equals(current)) { + return new OptionalDoubleSerializer(serializer); + } else { + throw new JsonbException("Unsupported Optional type for serialization: " + clazz); + } + } + + if (Enum.class.isAssignableFrom(clazz)) { + typeSerializer = new EnumSerializer(builder); + } else if (JsonValue.class.isAssignableFrom(clazz)) { + typeSerializer = new JsonValueSerializer(builder); + } + if (typeSerializer == null) { + do { + if (SERIALIZERS.containsKey(current)) { + typeSerializer = SERIALIZERS.get(current).apply(builder); + break; + } + current = current.getSuperclass(); + } while (!Object.class.equals(current) && current != null); + } + + if (key) { + //We do not want any other special serializers around our type serializer if it will be used as a key + return typeSerializer; + } + return typeSerializer == null + ? null + : SerializationModelCreator.wrapInCommonSet(typeSerializer, customization, jsonbContext); + } + +} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/types/UriSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/types/UriSerializer.java new file mode 100644 index 000000000..01a98441e --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/serializer/types/UriSerializer.java @@ -0,0 +1,35 @@ +/* + * 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.serializer.types; + +import java.net.URI; + +import jakarta.json.stream.JsonGenerator; + +import org.eclipse.yasson.internal.SerializationContextImpl; + +/** + * Serializer of the {@link URI} type. + */ +class UriSerializer extends TypeSerializer { + + UriSerializer(TypeSerializerBuilder serializerBuilder) { + super(serializerBuilder); + } + + @Override + void serializeValue(URI value, JsonGenerator generator, SerializationContextImpl context) { + generator.write(value.toString()); + } + +} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/types/UrlSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/types/UrlSerializer.java new file mode 100644 index 000000000..37f9ef1a7 --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/serializer/types/UrlSerializer.java @@ -0,0 +1,35 @@ +/* + * 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.serializer.types; + +import java.net.URL; + +import jakarta.json.stream.JsonGenerator; + +import org.eclipse.yasson.internal.SerializationContextImpl; + +/** + * Serializer of the {@link URL} type. + */ +class UrlSerializer extends TypeSerializer { + + UrlSerializer(TypeSerializerBuilder serializerBuilder) { + super(serializerBuilder); + } + + @Override + void serializeValue(URL value, JsonGenerator generator, SerializationContextImpl context) { + generator.write(value.toString()); + } + +} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/types/UuidSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/types/UuidSerializer.java new file mode 100644 index 000000000..1a46f1b2f --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/serializer/types/UuidSerializer.java @@ -0,0 +1,35 @@ +/* + * 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.serializer.types; + +import java.util.UUID; + +import jakarta.json.stream.JsonGenerator; + +import org.eclipse.yasson.internal.SerializationContextImpl; + +/** + * Serializer of the {@link UUID} type. + */ +class UuidSerializer extends TypeSerializer { + + UuidSerializer(TypeSerializerBuilder serializerBuilder) { + super(serializerBuilder); + } + + @Override + void serializeValue(UUID value, JsonGenerator generator, SerializationContextImpl context) { + generator.write(value.toString()); + } + +} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/XMLGregorianCalendarTypeSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/types/XmlGregorianCalendarSerializer.java similarity index 68% rename from src/main/java/org/eclipse/yasson/internal/serializer/XMLGregorianCalendarTypeSerializer.java rename to src/main/java/org/eclipse/yasson/internal/serializer/types/XmlGregorianCalendarSerializer.java index e41d2de73..479bd48cc 100644 --- a/src/main/java/org/eclipse/yasson/internal/serializer/XMLGregorianCalendarTypeSerializer.java +++ b/src/main/java/org/eclipse/yasson/internal/serializer/types/XmlGregorianCalendarSerializer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 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,7 +10,7 @@ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ -package org.eclipse.yasson.internal.serializer; +package org.eclipse.yasson.internal.serializer.types; import java.time.Instant; import java.time.ZonedDateTime; @@ -20,20 +20,13 @@ import javax.xml.datatype.XMLGregorianCalendar; -import org.eclipse.yasson.internal.model.customization.Customization; - /** - * Serializer for {@link XMLGregorianCalendar} type. + * Serializer of the {@link XMLGregorianCalendar} type. */ -public class XMLGregorianCalendarTypeSerializer extends AbstractDateTimeSerializer { - - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public XMLGregorianCalendarTypeSerializer(Customization customization) { - super(customization); +class XmlGregorianCalendarSerializer extends AbstractDateSerializer { + + XmlGregorianCalendarSerializer(TypeSerializerBuilder serializerBuilder) { + super(serializerBuilder); } @Override @@ -52,11 +45,8 @@ protected String formatDefault(XMLGregorianCalendar value, Locale locale) { @Override protected TemporalAccessor toTemporalAccessor(XMLGregorianCalendar object) { - return toZonedDateTime(object); - } - - private ZonedDateTime toZonedDateTime(XMLGregorianCalendar object) { return ZonedDateTime.ofInstant(Instant.ofEpochMilli(object.toGregorianCalendar().getTimeInMillis()), object.toGregorianCalendar().getTimeZone().toZoneId()); } + } diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/YearMonthTypeSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/types/YearMonthTypeSerializer.java similarity index 63% rename from src/main/java/org/eclipse/yasson/internal/serializer/YearMonthTypeSerializer.java rename to src/main/java/org/eclipse/yasson/internal/serializer/types/YearMonthTypeSerializer.java index a4e9b7048..fd357ef4e 100644 --- a/src/main/java/org/eclipse/yasson/internal/serializer/YearMonthTypeSerializer.java +++ b/src/main/java/org/eclipse/yasson/internal/serializer/types/YearMonthTypeSerializer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. + * 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 @@ -10,29 +10,22 @@ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ -package org.eclipse.yasson.internal.serializer; +package org.eclipse.yasson.internal.serializer.types; import java.time.Instant; import java.time.YearMonth; import java.time.format.DateTimeFormatter; import java.util.Locale; -import org.eclipse.yasson.internal.model.customization.Customization; - /** - * Serializer for {@link YearMonth} type. + * Serializer of the {@link YearMonth} type. */ -public class YearMonthTypeSerializer extends AbstractDateTimeSerializer { +class YearMonthTypeSerializer extends AbstractDateSerializer { private static final DateTimeFormatter DEFAULT_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM").withZone(UTC); - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public YearMonthTypeSerializer(Customization customization) { - super(customization); + YearMonthTypeSerializer(TypeSerializerBuilder serializerBuilder) { + super(serializerBuilder); } @Override diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/types/ZoneIdSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/types/ZoneIdSerializer.java new file mode 100644 index 000000000..4a34917ac --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/serializer/types/ZoneIdSerializer.java @@ -0,0 +1,35 @@ +/* + * 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.serializer.types; + +import java.time.ZoneId; + +import jakarta.json.stream.JsonGenerator; + +import org.eclipse.yasson.internal.SerializationContextImpl; + +/** + * Serializer of the {@link ZoneId} type. + */ +class ZoneIdSerializer extends TypeSerializer { + + ZoneIdSerializer(TypeSerializerBuilder serializerBuilder) { + super(serializerBuilder); + } + + @Override + void serializeValue(ZoneId value, JsonGenerator generator, SerializationContextImpl context) { + generator.write(value.getId()); + } + +} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/types/ZoneOffsetSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/types/ZoneOffsetSerializer.java new file mode 100644 index 000000000..420485d37 --- /dev/null +++ b/src/main/java/org/eclipse/yasson/internal/serializer/types/ZoneOffsetSerializer.java @@ -0,0 +1,34 @@ +/* + * 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.serializer.types; + +import java.time.ZoneOffset; + +import jakarta.json.stream.JsonGenerator; + +import org.eclipse.yasson.internal.SerializationContextImpl; + +/** + * Serializer of the {@link ZoneOffset} type. + */ +class ZoneOffsetSerializer extends TypeSerializer { + + ZoneOffsetSerializer(TypeSerializerBuilder serializerBuilder) { + super(serializerBuilder); + } + + @Override + void serializeValue(ZoneOffset value, JsonGenerator generator, SerializationContextImpl context) { + generator.write(value.getId()); + } +} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/ZonedDateTimeTypeSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/types/ZonedDateTimeSerializer.java similarity index 61% rename from src/main/java/org/eclipse/yasson/internal/serializer/ZonedDateTimeTypeSerializer.java rename to src/main/java/org/eclipse/yasson/internal/serializer/types/ZonedDateTimeSerializer.java index 29b27e272..08911039c 100644 --- a/src/main/java/org/eclipse/yasson/internal/serializer/ZonedDateTimeTypeSerializer.java +++ b/src/main/java/org/eclipse/yasson/internal/serializer/types/ZonedDateTimeSerializer.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 @@ -10,27 +10,20 @@ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ -package org.eclipse.yasson.internal.serializer; +package org.eclipse.yasson.internal.serializer.types; import java.time.Instant; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.util.Locale; -import org.eclipse.yasson.internal.model.customization.Customization; - /** - * Serializer for {@link ZonedDateTime} type. + * Serializer of the {@link ZonedDateTime} type. */ -public class ZonedDateTimeTypeSerializer extends AbstractDateTimeSerializer { +class ZonedDateTimeSerializer extends AbstractDateSerializer { - /** - * Creates a new instance. - * - * @param customization Model customization. - */ - public ZonedDateTimeTypeSerializer(Customization customization) { - super(customization); + ZonedDateTimeSerializer(TypeSerializerBuilder serializerBuilder) { + super(serializerBuilder); } @Override diff --git a/src/main/java9/org/eclipse/yasson/internal/model/ModulesUtil.java b/src/main/java9/org/eclipse/yasson/internal/model/ModulesUtil.java deleted file mode 100644 index 33852de29..000000000 --- a/src/main/java9/org/eclipse/yasson/internal/model/ModulesUtil.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2021 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.model; - -import java.lang.invoke.MethodHandles; - -class ModulesUtil { - - private ModulesUtil() { - } - - static MethodHandles.Lookup lookup(){ - return MethodHandles.publicLookup(); - } -} diff --git a/src/main/resources/yasson-messages.properties b/src/main/resources/yasson-messages.properties index 18f5d9ea3..4d224493e 100644 --- a/src/main/resources/yasson-messages.properties +++ b/src/main/resources/yasson-messages.properties @@ -39,6 +39,7 @@ adapterException=Problem adapting object of type {0} to {1} in class {2} adapterFound=Found adapter from type {0} to type {1}. adapterIncompatible=Adapter of runtime type {0} does not match property type {1} propertyOrder=Property order strategy with name {0} was not recognized +unknownVisibilityStrategy=Property visibility strategy with name {0} was not recognized unsupportedJsonpSerializerValue=Unsupported value of type {0} for JSON serializer. noJndiEnvironment=No JNDI environment ({0}) found to look for CDI provider. noCdiApiProvider=CDI API not found on class or module path {0}. diff --git a/src/test/java/org/eclipse/yasson/SimpleTest.java b/src/test/java/org/eclipse/yasson/SimpleTest.java index e51fc769f..ca11319f6 100644 --- a/src/test/java/org/eclipse/yasson/SimpleTest.java +++ b/src/test/java/org/eclipse/yasson/SimpleTest.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 @@ -12,9 +12,11 @@ package org.eclipse.yasson; -import org.junit.jupiter.api.*; -import static org.junit.jupiter.api.Assertions.*; -import static org.eclipse.yasson.Jsonbs.*; +import org.junit.jupiter.api.Test; + +import static org.eclipse.yasson.Jsonbs.bindingJsonb; +import static org.eclipse.yasson.Jsonbs.defaultJsonb; +import static org.junit.jupiter.api.Assertions.assertEquals; /** * @author Roman Grigoriadi @@ -25,7 +27,6 @@ public class SimpleTest { public void testSimpleSerialize() { final StringWrapper wrapper = new StringWrapper(); wrapper.setValue("abc"); - bindingJsonb.toJson(wrapper); final String val = bindingJsonb.toJson(wrapper); assertEquals("{\"value\":\"abc\"}", val); } @@ -33,11 +34,11 @@ public void testSimpleSerialize() { @Test public void testSimpleDeserializer() { final StringWrapper stringWrapper = defaultJsonb.fromJson("{\"value\":\"abc\"}", StringWrapper.class); - assertEquals("abc", stringWrapper.getValue()); + assertEquals("abc", stringWrapper.value); } - - + public static class StringWrapper { + public String value; public String getValue() { diff --git a/src/test/java/org/eclipse/yasson/customization/JsonbCreatorTest.java b/src/test/java/org/eclipse/yasson/customization/JsonbCreatorTest.java index d6001b5ef..de4c44aea 100644 --- a/src/test/java/org/eclipse/yasson/customization/JsonbCreatorTest.java +++ b/src/test/java/org/eclipse/yasson/customization/JsonbCreatorTest.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 @@ -12,20 +12,34 @@ package org.eclipse.yasson.customization; -import org.junit.jupiter.api.*; -import static org.junit.jupiter.api.Assertions.*; -import static org.eclipse.yasson.Jsonbs.*; - -import org.eclipse.yasson.customization.model.*; +import java.math.BigDecimal; +import java.time.LocalDate; +import java.util.Set; import jakarta.json.bind.JsonbException; import jakarta.json.bind.annotation.JsonbCreator; import jakarta.json.bind.annotation.JsonbDateFormat; import jakarta.json.bind.annotation.JsonbNumberFormat; import jakarta.json.bind.annotation.JsonbProperty; -import java.math.BigDecimal; -import java.time.LocalDate; -import java.util.Set; + +import org.eclipse.yasson.customization.model.CreatorConstructorPojo; +import org.eclipse.yasson.customization.model.CreatorFactoryMethodPojo; +import org.eclipse.yasson.customization.model.CreatorIncompatibleTypePojo; +import org.eclipse.yasson.customization.model.CreatorMultipleDeclarationErrorPojo; +import org.eclipse.yasson.customization.model.CreatorPackagePrivateConstructor; +import org.eclipse.yasson.customization.model.CreatorWithoutJavabeanProperty; +import org.eclipse.yasson.customization.model.CreatorWithoutJsonbProperty1; +import org.eclipse.yasson.customization.model.ParameterNameTester; +import org.junit.jupiter.api.Test; + +import static org.eclipse.yasson.Jsonbs.defaultJsonb; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; /** * @author Roman Grigoriadi @@ -86,7 +100,11 @@ public void testMultipleCreatorsError() { @Test public void testCreatorWithoutJsonbParameters1() { //arg2 is missing in json document - assertThrows(JsonbException.class, () -> defaultJsonb.fromJson("{\"arg0\":\"abc\", \"s2\":\"def\"}", CreatorWithoutJsonbProperty1.class)); + CreatorWithoutJsonbProperty1 object = defaultJsonb.fromJson("{\"arg0\":\"abc\", \"s2\":\"def\"}", + CreatorWithoutJsonbProperty1.class); + assertThat(object.getPar1(), is("abc")); + assertThat(object.getPar2(), is("def")); + assertThat(object.getPar3(), is((byte) 0)); } @Test diff --git a/src/test/java/org/eclipse/yasson/customization/YassonSpecificConfigTests.java b/src/test/java/org/eclipse/yasson/customization/YassonSpecificConfigTests.java new file mode 100644 index 000000000..4364ebb01 --- /dev/null +++ b/src/test/java/org/eclipse/yasson/customization/YassonSpecificConfigTests.java @@ -0,0 +1,61 @@ +/* + * 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.customization; + +import java.util.Optional; + +import jakarta.json.bind.Jsonb; +import jakarta.json.bind.JsonbBuilder; +import jakarta.json.bind.serializer.JsonbSerializer; +import jakarta.json.bind.serializer.SerializationContext; +import jakarta.json.stream.JsonGenerator; +import org.eclipse.yasson.YassonConfig; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Tests for Yasson specific config properties. + */ +public class YassonSpecificConfigTests { + + private static final String NULL_VALUE_STRING = "null value handled"; + private static final String NULL_VALUE_SERIALIZED = "\"" + NULL_VALUE_STRING + "\""; + + @Test + public void nullRootSerializerTest() { + Jsonb jsonb = JsonbBuilder.create(new YassonConfig().withNullRootSerializer(new RootNullSerializer())); + assertEquals(NULL_VALUE_SERIALIZED, jsonb.toJson(null)); + } + + @Test + public void emptyOptionalRootSerializerTest() { + Jsonb jsonb = JsonbBuilder.create(new YassonConfig().withNullRootSerializer(new RootNullSerializer())); + assertEquals(NULL_VALUE_SERIALIZED, jsonb.toJson(Optional.empty())); + } + + @Test + public void nullSerializerNotUsedTest() { + Jsonb jsonb = JsonbBuilder.create(new YassonConfig().withNullRootSerializer(new RootNullSerializer())); + assertEquals("[null]", jsonb.toJson(new String[] {null})); + } + + private static final class RootNullSerializer implements JsonbSerializer { + + @Override + public void serialize(Object obj, JsonGenerator generator, SerializationContext ctx) { + generator.write(NULL_VALUE_STRING); + } + } + +} diff --git a/src/test/java/org/eclipse/yasson/customization/model/CollectionsWithFormatters.java b/src/test/java/org/eclipse/yasson/customization/model/CollectionsWithFormatters.java new file mode 100644 index 000000000..17f8db705 --- /dev/null +++ b/src/test/java/org/eclipse/yasson/customization/model/CollectionsWithFormatters.java @@ -0,0 +1,28 @@ +/* + * 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.customization.model; + +import java.util.List; + +import jakarta.json.bind.annotation.JsonbNumberFormat; + +@JsonbNumberFormat(value = "000.000", locale = "en-us") +public class CollectionsWithFormatters { + + public List doubleList; + + @JsonbNumberFormat(locale = "da-da") + public List doubleList2; + + public List doubleList3; +} diff --git a/src/test/java/org/eclipse/yasson/customization/polymorphism/AnnotationPolymorphismTest.java b/src/test/java/org/eclipse/yasson/customization/polymorphism/AnnotationPolymorphismTest.java new file mode 100644 index 000000000..db13e409e --- /dev/null +++ b/src/test/java/org/eclipse/yasson/customization/polymorphism/AnnotationPolymorphismTest.java @@ -0,0 +1,147 @@ +/* + * 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.customization.polymorphism; + +import java.time.LocalDate; + +import jakarta.json.bind.JsonbException; +import jakarta.json.bind.annotation.JsonbCreator; +import jakarta.json.bind.annotation.JsonbDateFormat; +import jakarta.json.bind.annotation.JsonbProperty; +import jakarta.json.bind.annotation.JsonbSubtype; +import jakarta.json.bind.annotation.JsonbTypeInfo; + +import org.eclipse.yasson.Jsonbs; +import org.junit.jupiter.api.Test; + +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.startsWith; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; + +/** + * Tests for verification of proper polymorphism handling based on annotation. + */ +public class AnnotationPolymorphismTest { + + public static final String ARRAY_EXPECTED = "[{\"@type\":\"dog\",\"isDog\":true},{\"@type\":\"cat\",\"isCat\":true}," + + "{\"@type\":\"dog\",\"isDog\":true}]"; + + @Test + public void testBasicSerialization() { + Dog dog = new Dog(); + assertThat(Jsonbs.defaultJsonb.toJson(dog), is("{\"@type\":\"dog\",\"isDog\":true}")); + Cat cat = new Cat(); + assertThat(Jsonbs.defaultJsonb.toJson(cat), is("{\"@type\":\"cat\",\"isCat\":true}")); + } + + @Test + public void testBasicDeserialization() { + Animal dog = Jsonbs.defaultJsonb.fromJson("{\"@type\":\"dog\",\"isDog\":false}", Animal.class); + assertThat(dog, instanceOf(Dog.class)); + assertThat(((Dog) dog).isDog, is(false)); + Animal cat = Jsonbs.defaultJsonb.fromJson("{\"@type\":\"cat\",\"isCat\":false}", Animal.class); + assertThat(cat, instanceOf(Cat.class)); + assertThat(((Cat) cat).isCat, is(false)); + } + + @Test + public void testExactTypeDeserialization() { + Dog dog = Jsonbs.defaultJsonb.fromJson("{\"isDog\":false}", Dog.class); + assertThat(dog.isDog, is(false)); + dog = Jsonbs.defaultJsonb.fromJson("{\"@type\":\"dog\", \"isDog\":false}", Dog.class); + assertThat(dog.isDog, is(false)); + } + + @Test + public void testUnknownAliasDeserialization() { + JsonbException exception = assertThrows(JsonbException.class, + () -> Jsonbs.defaultJsonb.fromJson("{\"@type\":\"rat\",\"isDog\":false}", + Animal.class)); + assertThat(exception.getMessage(), startsWith("Unknown alias \"rat\" known aliases: [")); + } + + @Test + public void testUnknownAliasSerialization() { + Rat rat = new Rat(); + assertThat(Jsonbs.defaultJsonb.toJson(rat), is("{\"isRat\":true}")); + } + + @Test + public void testCreatorDeserialization() { + SomeDateType creator = Jsonbs.defaultJsonb + .fromJson("{\"@dateType\":\"constructor\",\"localDate\":\"26-02-2021\"}", SomeDateType.class); + assertThat(creator, instanceOf(DateConstructor.class)); + } + + @Test + public void testArraySerialization() { + Animal[] animals = new Animal[] {new Dog(), new Cat(), new Dog()}; + assertThat(Jsonbs.defaultJsonb.toJson(animals), is(ARRAY_EXPECTED)); + } + + @Test + public void testArrayDeserialization() { + Animal[] deserialized = Jsonbs.defaultJsonb.fromJson(ARRAY_EXPECTED, Animal[].class); + assertThat(deserialized.length, is(3)); + assertThat(deserialized[0], instanceOf(Dog.class)); + assertThat(deserialized[1], instanceOf(Cat.class)); + assertThat(deserialized[2], instanceOf(Dog.class)); + } + + @JsonbTypeInfo({ + @JsonbSubtype(alias = "dog", type = Dog.class), + @JsonbSubtype(alias = "cat", type = Cat.class) + }) + public interface Animal { + + } + + public static class Dog implements Animal { + + public boolean isDog = true; + + } + + public static class Cat implements Animal { + + public boolean isCat = true; + + } + + public static class Rat implements Animal { + + public boolean isRat = true; + + } + + @JsonbTypeInfo(key = "@dateType", value = { + @JsonbSubtype(alias = "constructor", type = DateConstructor.class) + }) + public interface SomeDateType { + + } + + public static final class DateConstructor implements SomeDateType { + + public LocalDate localDate; + + @JsonbCreator + public DateConstructor(@JsonbProperty("localDate") @JsonbDateFormat(value = "dd-MM-yyyy", locale = "nl-NL") LocalDate localDate) { + this.localDate = localDate; + } + + } + +} diff --git a/src/test/java/org/eclipse/yasson/customization/polymorphism/MultiplePolymorphicInfoTest.java b/src/test/java/org/eclipse/yasson/customization/polymorphism/MultiplePolymorphicInfoTest.java new file mode 100644 index 000000000..0b8f53c0d --- /dev/null +++ b/src/test/java/org/eclipse/yasson/customization/polymorphism/MultiplePolymorphicInfoTest.java @@ -0,0 +1,68 @@ +/* + * 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.customization.polymorphism; + +import jakarta.json.bind.Jsonb; +import jakarta.json.bind.JsonbBuilder; +import jakarta.json.bind.annotation.JsonbSubtype; +import jakarta.json.bind.annotation.JsonbTypeInfo; + +import org.junit.jupiter.api.Test; + +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; + +/** + * TODO javadoc + */ +public class MultiplePolymorphicInfoTest { + + private static final Jsonb JSONB = JsonbBuilder.create(); + + @Test + public void testMultiplePolymorphicInfoPropertySerialization() { + String expected = "{\"@something\":\"animal\",\"@animal\":\"dog\",\"@dogRace\":\"labrador\",\"isLabrador\":true}"; + Labrador labrador = new Labrador(); + assertThat(JSONB.toJson(labrador), is(expected)); + } + + @Test + public void testMultiplePolymorphicInfoPropertyDeserialization() { + String json = "{\"@something\":\"animal\",\"@animal\":\"dog\",\"@dogRace\":\"labrador\",\"isLabrador\":true}"; + assertThat(JSONB.fromJson(json, Labrador.class), instanceOf(Labrador.class)); + } + + @JsonbTypeInfo(key = "@something", value = { + @JsonbSubtype(alias = "animal", type = Animal.class) + }) + public interface Something { } + + @JsonbTypeInfo(key = "@animal", value = { + @JsonbSubtype(alias = "dog", type = Dog.class) + }) + public interface Animal extends Something { + } + + @JsonbTypeInfo(key = "@dogRace", value = { + @JsonbSubtype(alias = "labrador", type = Labrador.class) + }) + public interface Dog extends Animal { + } + + public static class Labrador implements Dog { + + public boolean isLabrador = true; + + } +} diff --git a/src/test/java/org/eclipse/yasson/defaultmapping/SecurityManagerTest.java b/src/test/java/org/eclipse/yasson/defaultmapping/SecurityManagerTest.java index 0f2d4fadb..029e55402 100644 --- a/src/test/java/org/eclipse/yasson/defaultmapping/SecurityManagerTest.java +++ b/src/test/java/org/eclipse/yasson/defaultmapping/SecurityManagerTest.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 @@ -29,6 +29,7 @@ /** * Created by Roman Grigoriadi (roman.grigoriadi@oracle.com) on 28/04/2017. */ + public class SecurityManagerTest { static final String classesDir = SecurityManagerTest.class.getProtectionDomain().getCodeSource().getLocation().getFile(); diff --git a/src/test/java/org/eclipse/yasson/defaultmapping/basic/BooleanTest.java b/src/test/java/org/eclipse/yasson/defaultmapping/basic/BooleanTest.java index 40b415e26..c89d32f95 100644 --- a/src/test/java/org/eclipse/yasson/defaultmapping/basic/BooleanTest.java +++ b/src/test/java/org/eclipse/yasson/defaultmapping/basic/BooleanTest.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 @@ -13,6 +13,9 @@ package org.eclipse.yasson.defaultmapping.basic; import org.junit.jupiter.api.*; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.CoreMatchers.is; import static org.junit.jupiter.api.Assertions.*; import static org.eclipse.yasson.Jsonbs.*; @@ -43,8 +46,8 @@ public void testBooleanDeserializationFromBooleanAsStringValue() throws Exceptio @Test public void testBooleanDeserializationFromBooleanRawValue() throws Exception { BooleanModel booleanModel = defaultJsonb.fromJson("{\"field1\":false,\"field2\":false}", BooleanModel.class); - assertEquals(false, booleanModel.field1); - assertEquals(false, booleanModel.field2); + assertThat(booleanModel.field1, is(false)); + assertThat(booleanModel.field2, is(false)); } @Test diff --git a/src/test/java/org/eclipse/yasson/defaultmapping/basic/SingleValueTest.java b/src/test/java/org/eclipse/yasson/defaultmapping/basic/SingleValueTest.java index f88a53bcb..a08e4e8e7 100644 --- a/src/test/java/org/eclipse/yasson/defaultmapping/basic/SingleValueTest.java +++ b/src/test/java/org/eclipse/yasson/defaultmapping/basic/SingleValueTest.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 @@ -75,7 +75,7 @@ public void testMarshallPrimitives() { assertEquals("1", bindingJsonb.toJson(1)); // null - //assertEquals("null", jsonb.toJson(null)); + assertEquals("null", bindingJsonb.toJson(null)); } @Test diff --git a/src/test/java/org/eclipse/yasson/defaultmapping/collections/CollectionsTest.java b/src/test/java/org/eclipse/yasson/defaultmapping/collections/CollectionsTest.java index f4ac39d26..0e7fdb422 100644 --- a/src/test/java/org/eclipse/yasson/defaultmapping/collections/CollectionsTest.java +++ b/src/test/java/org/eclipse/yasson/defaultmapping/collections/CollectionsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 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 @@ -65,6 +65,7 @@ public void testMarshallMap() { assertEquals("{\"1\":1,\"2\":2,\"3\":3}", nullableJsonb.toJson(stringIntegerMap)); assertEquals(stringIntegerMap, nullableJsonb.fromJson("{\"1\":1,\"2\":2,\"3\":3}", new LinkedHashMap(){}.getClass().getGenericSuperclass())); + System.out.println(); } @Test diff --git a/src/test/java/org/eclipse/yasson/defaultmapping/collections/MapKeyTypesTest.java b/src/test/java/org/eclipse/yasson/defaultmapping/collections/MapKeyTypesTest.java new file mode 100644 index 000000000..9bdd7df66 --- /dev/null +++ b/src/test/java/org/eclipse/yasson/defaultmapping/collections/MapKeyTypesTest.java @@ -0,0 +1,99 @@ +/* + * 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.defaultmapping.collections; + +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.UUID; + +import org.eclipse.yasson.Jsonbs; +import org.eclipse.yasson.TestTypeToken; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Tests to verify proper map key serialization and deserialization. + */ +public class MapKeyTypesTest { + + @Test + public void uuidMapKey() { + String expected = "{\"ccf3e2d3-3589-4c91-9ba9-1250ef515327\":{\"firstName\":\"FirstName1\",\"sureName\":\"SureName1\"}," + + "\"0bb54cee-d538-428b-9719-5cc38c988522\":{\"firstName\":\"FirstName2\",\"sureName\":\"SureName2\"}}"; + Map map = new HashMap<>(); + Person person = new Person(); + person.firstName = "FirstName1"; + person.sureName = "SureName1"; + Person person2 = new Person(); + person2.firstName = "FirstName2"; + person2.sureName = "SureName2"; + map.put(UUID.fromString("ccf3e2d3-3589-4c91-9ba9-1250ef515327"), person); + map.put(UUID.fromString("0bb54cee-d538-428b-9719-5cc38c988522"), person2); + assertEquals(expected, Jsonbs.defaultJsonb.toJson(map)); + assertEquals(map, Jsonbs.defaultJsonb.fromJson(expected, new TestTypeToken>() { }.getType())); + } + + @Test + public void zonedDateTimeMapKey() { + ZonedDateTime zonedDateTime = ZonedDateTime.of(2020, 9, 14, + 9, 33, 12, 0, + ZoneId.of("UTC")); + ZonedDateTime zonedDateTime2 = ZonedDateTime.of(2019, 8, 13, + 8, 32, 11, 1234, + ZoneId.of("UTC")); + String expected = "{\"2020-09-14T09:33:12Z[UTC]\":{\"firstName\":\"FirstName1\"," + + "\"sureName\":\"SureName1\"}," + + "\"2019-08-13T08:32:11.000001234Z[UTC]\":{\"firstName\":\"FirstName2\"," + + "\"sureName\":\"SureName2\"}}"; + Map map = new HashMap<>(); + Person person = new Person(); + person.firstName = "FirstName1"; + person.sureName = "SureName1"; + Person person2 = new Person(); + person2.firstName = "FirstName2"; + person2.sureName = "SureName2"; + map.put(zonedDateTime, person); + map.put(zonedDateTime2, person2); + assertEquals(expected, Jsonbs.defaultJsonb.toJson(map)); + assertEquals(map, Jsonbs.defaultJsonb.fromJson(expected, new TestTypeToken>() { }.getType())); + } + + public static final class Person { + + public String firstName; + public String sureName; + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Person person = (Person) o; + return Objects.equals(firstName, person.firstName) && + Objects.equals(sureName, person.sureName); + } + + @Override + public int hashCode() { + return Objects.hash(firstName, sureName); + } + } + +} diff --git a/src/test/java/org/eclipse/yasson/defaultmapping/dates/DatesTest.java b/src/test/java/org/eclipse/yasson/defaultmapping/dates/DatesTest.java index 77a4ea8da..2d92fa856 100644 --- a/src/test/java/org/eclipse/yasson/defaultmapping/dates/DatesTest.java +++ b/src/test/java/org/eclipse/yasson/defaultmapping/dates/DatesTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 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 @@ -12,36 +12,6 @@ package org.eclipse.yasson.defaultmapping.dates; -import org.eclipse.yasson.defaultmapping.dates.model.MonthDayPojo; -import org.eclipse.yasson.defaultmapping.dates.model.YearMonthPojo; -import org.junit.jupiter.api.*; -import static org.junit.jupiter.api.Assertions.*; -import static org.eclipse.yasson.Jsonbs.*; - -import org.eclipse.yasson.TestTypeToken; -import org.eclipse.yasson.defaultmapping.dates.model.CalendarPojo; -import org.eclipse.yasson.defaultmapping.dates.model.ClassLevelDateAnnotation; -import org.eclipse.yasson.defaultmapping.dates.model.DatePojo; -import org.eclipse.yasson.defaultmapping.dates.model.DateWithZonePojo; -import org.eclipse.yasson.defaultmapping.dates.model.InstantPojo; -import org.eclipse.yasson.defaultmapping.dates.model.LocalDatePojo; -import org.eclipse.yasson.defaultmapping.dates.model.LocalDateTimePojo; -import org.eclipse.yasson.defaultmapping.dates.model.LocalTimePojo; -import org.eclipse.yasson.defaultmapping.dates.model.OffsetDateTimePojo; -import org.eclipse.yasson.defaultmapping.dates.model.OffsetTimePojo; -import org.eclipse.yasson.defaultmapping.dates.model.ZonedDateTimePojo; -import org.eclipse.yasson.defaultmapping.generics.model.ScalarValueWrapper; -import org.eclipse.yasson.internal.serializer.SqlDateTypeDeserializer; - -import jakarta.json.bind.Jsonb; -import jakarta.json.bind.JsonbBuilder; -import jakarta.json.bind.JsonbConfig; -import jakarta.json.bind.annotation.JsonbDateFormat; -import jakarta.json.bind.annotation.JsonbTypeDeserializer; -import jakarta.json.bind.config.PropertyVisibilityStrategy; -import javax.xml.datatype.DatatypeConfigurationException; -import javax.xml.datatype.DatatypeFactory; -import javax.xml.datatype.XMLGregorianCalendar; import java.io.Serializable; import java.lang.reflect.Field; import java.lang.reflect.Method; @@ -63,7 +33,6 @@ import java.time.ZoneOffset; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; -import java.time.temporal.ChronoField; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; @@ -73,6 +42,39 @@ import java.util.SimpleTimeZone; import java.util.TimeZone; +import javax.xml.datatype.DatatypeConfigurationException; +import javax.xml.datatype.DatatypeFactory; +import javax.xml.datatype.XMLGregorianCalendar; + +import jakarta.json.bind.Jsonb; +import jakarta.json.bind.JsonbBuilder; +import jakarta.json.bind.JsonbConfig; +import jakarta.json.bind.annotation.JsonbDateFormat; +import jakarta.json.bind.annotation.JsonbTypeDeserializer; +import jakarta.json.bind.config.PropertyVisibilityStrategy; +import org.eclipse.yasson.TestTypeToken; +import org.eclipse.yasson.defaultmapping.dates.model.CalendarPojo; +import org.eclipse.yasson.defaultmapping.dates.model.ClassLevelDateAnnotation; +import org.eclipse.yasson.defaultmapping.dates.model.DatePojo; +import org.eclipse.yasson.defaultmapping.dates.model.DateWithZonePojo; +import org.eclipse.yasson.defaultmapping.dates.model.InstantPojo; +import org.eclipse.yasson.defaultmapping.dates.model.LocalDatePojo; +import org.eclipse.yasson.defaultmapping.dates.model.LocalDateTimePojo; +import org.eclipse.yasson.defaultmapping.dates.model.LocalTimePojo; +import org.eclipse.yasson.defaultmapping.dates.model.MonthDayPojo; +import org.eclipse.yasson.defaultmapping.dates.model.OffsetDateTimePojo; +import org.eclipse.yasson.defaultmapping.dates.model.OffsetTimePojo; +import org.eclipse.yasson.defaultmapping.dates.model.YearMonthPojo; +import org.eclipse.yasson.defaultmapping.dates.model.ZonedDateTimePojo; +import org.eclipse.yasson.defaultmapping.generics.model.ScalarValueWrapper; +import org.eclipse.yasson.internal.deserializer.types.SqlDateDeserializer; +import org.junit.jupiter.api.Test; + +import static org.eclipse.yasson.Jsonbs.bindingJsonb; +import static org.eclipse.yasson.Jsonbs.defaultJsonb; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; + /** * This class contains tests for marshalling/unmarshalling dates. * @@ -91,7 +93,7 @@ public static class LocalDateObj implements Serializable { public static class SqlDateObj implements Serializable { public java.sql.Date sqlDate = java.sql.Date.valueOf("2018-01-31"); //no way for runtime to choose java.sql.Date deserializer here without a hint - @JsonbTypeDeserializer(SqlDateTypeDeserializer.class) + @JsonbTypeDeserializer(SqlDateDeserializer.class) public java.util.Date utilDate = java.sql.Date.valueOf("2018-01-31"); } diff --git a/src/test/java/org/eclipse/yasson/defaultmapping/generics/GenericsTest.java b/src/test/java/org/eclipse/yasson/defaultmapping/generics/GenericsTest.java index becfc3af2..3bc88a049 100644 --- a/src/test/java/org/eclipse/yasson/defaultmapping/generics/GenericsTest.java +++ b/src/test/java/org/eclipse/yasson/defaultmapping/generics/GenericsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 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 @@ -12,12 +12,23 @@ package org.eclipse.yasson.defaultmapping.generics; -import org.eclipse.yasson.defaultmapping.generics.model.FinalMember; -import org.eclipse.yasson.defaultmapping.generics.model.FinalGenericWrapper; -import org.junit.jupiter.api.*; -import static org.junit.jupiter.api.Assertions.*; -import static org.eclipse.yasson.Jsonbs.*; +import java.lang.reflect.Type; +import java.math.BigDecimal; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.TimeZone; +import jakarta.json.bind.Jsonb; +import jakarta.json.bind.JsonbBuilder; +import jakarta.json.bind.JsonbConfig; import org.eclipse.yasson.TestTypeToken; import org.eclipse.yasson.adapters.model.GenericBox; import org.eclipse.yasson.defaultmapping.generics.model.AnotherGenericTestClass; @@ -26,6 +37,8 @@ import org.eclipse.yasson.defaultmapping.generics.model.CollectionWrapper; import org.eclipse.yasson.defaultmapping.generics.model.ColoredCircle; import org.eclipse.yasson.defaultmapping.generics.model.CyclicSubClass; +import org.eclipse.yasson.defaultmapping.generics.model.FinalGenericWrapper; +import org.eclipse.yasson.defaultmapping.generics.model.FinalMember; import org.eclipse.yasson.defaultmapping.generics.model.GenericArrayClass; import org.eclipse.yasson.defaultmapping.generics.model.GenericTestClass; import org.eclipse.yasson.defaultmapping.generics.model.GenericWithUnboundedWildcardClass; @@ -38,23 +51,12 @@ import org.eclipse.yasson.defaultmapping.generics.model.WildcardMultipleBoundsClass; import org.eclipse.yasson.serializers.model.Box; import org.eclipse.yasson.serializers.model.Crate; +import org.junit.jupiter.api.Test; -import jakarta.json.bind.Jsonb; -import jakarta.json.bind.JsonbBuilder; -import jakarta.json.bind.JsonbConfig; -import java.lang.reflect.Type; -import java.math.BigDecimal; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.TimeZone; +import static org.eclipse.yasson.Jsonbs.defaultJsonb; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; /** * This class contains JSONB default mapping generics tests. diff --git a/src/test/java/org/eclipse/yasson/defaultmapping/inheritance/InheritanceTest.java b/src/test/java/org/eclipse/yasson/defaultmapping/inheritance/InheritanceTest.java index 24d1c3a7c..9652fe540 100644 --- a/src/test/java/org/eclipse/yasson/defaultmapping/inheritance/InheritanceTest.java +++ b/src/test/java/org/eclipse/yasson/defaultmapping/inheritance/InheritanceTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 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 @@ -221,4 +221,44 @@ public void testPropOrderPartiallyOverriddenProperty() { assertEquals("{\"zero\":\"ZERO\",\"zeroPartiallyOverriddenInFirst\":\"ZERO_PARTIALLY_OVERRIDDEN_IN_FIRST\",\"first\":\"FIRST\",\"second\":\"SECOND\",\"zeroOverriddenInSecond\":\"ZERO_OVERRIDDEN_IN_SECOND\"}", result); } + + @Test + public void testInheritanceSerialization() { + AnimalWrapper animalWrapper = new AnimalWrapper(); + animalWrapper.animal = new Dog(); + //Just initialize serializer cache for Animal and Dog + defaultJsonb.toJson(animalWrapper); + + //Check if the Dog instance is dynamically resolved even though Dog serializer has been created before + DogWrapper dogWrapper = new DogWrapper(); + dogWrapper.dog = new Dog(); + assertEquals("{\"dog\":{\"isDog\":true}}", defaultJsonb.toJson(dogWrapper)); + dogWrapper.dog = new SmallDog(); + assertEquals("{\"dog\":{\"isDog\":true,\"isSmallDog\":true}}", defaultJsonb.toJson(dogWrapper)); + + } + + public static class AnimalWrapper { + + public Animal animal; + + } + + public static class DogWrapper { + + public Dog dog; + + } + + public static class Animal { + + } + + public static class Dog extends Animal { + public boolean isDog = true; + } + + public static class SmallDog extends Dog { + public boolean isSmallDog = true; + } } diff --git a/src/test/java/org/eclipse/yasson/defaultmapping/jsonp/JsonpTest.java b/src/test/java/org/eclipse/yasson/defaultmapping/jsonp/JsonpTest.java index e22c3d9f3..45a02a2b0 100644 --- a/src/test/java/org/eclipse/yasson/defaultmapping/jsonp/JsonpTest.java +++ b/src/test/java/org/eclipse/yasson/defaultmapping/jsonp/JsonpTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 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 @@ -13,6 +13,10 @@ package org.eclipse.yasson.defaultmapping.jsonp; import org.junit.jupiter.api.*; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.jupiter.api.Assertions.*; import static org.eclipse.yasson.Jsonbs.*; @@ -45,7 +49,7 @@ public JsonValueWrapper() { @Test public void testInnerJsonObject() { - + final JsonBuilderFactory factory = Json.createBuilderFactory(null); final JsonObject jsonObject = factory.createObjectBuilder() .add("name", "home") @@ -76,7 +80,7 @@ public void testInnerJsonObject() { @Test public void testMarshallJsonArray() { - + final JsonBuilderFactory factory = Json.createBuilderFactory(null); final JsonArray jsonArray = factory.createArrayBuilder() .add(1) @@ -238,4 +242,16 @@ public void testJsonValueAsArray() { assertEquals("b", resultArray.getJsonObject(3).getString("a")); } + + @Test + public void testJsonNullValue() { + JsonValueWrapper pojo = new JsonValueWrapper(null); + String expected = "{}"; + String json = defaultJsonb.toJson(pojo); + assertThat(json, is(expected)); + JsonValueWrapper deserialized = defaultJsonb.fromJson(expected, JsonValueWrapper.class); + assertThat(deserialized.jsonValue, nullValue()); + deserialized = defaultJsonb.fromJson("{\"jsonValue\":null}", JsonValueWrapper.class); + assertThat(deserialized.jsonValue, is(JsonValue.NULL)); + } } diff --git a/src/test/java/org/eclipse/yasson/defaultmapping/specific/NullTest.java b/src/test/java/org/eclipse/yasson/defaultmapping/specific/NullTest.java index 1c2751931..34be5dcc8 100644 --- a/src/test/java/org/eclipse/yasson/defaultmapping/specific/NullTest.java +++ b/src/test/java/org/eclipse/yasson/defaultmapping/specific/NullTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2022 Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2019, 2020 Payara Foundation and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the @@ -13,6 +13,7 @@ package org.eclipse.yasson.defaultmapping.specific; +import org.eclipse.yasson.defaultmapping.specific.model.StreetWithPrimitives; import org.junit.jupiter.api.*; import static org.junit.jupiter.api.Assertions.*; import static org.eclipse.yasson.Jsonbs.*; @@ -37,6 +38,16 @@ public void testSetsNullIntoFields() { assertNull(result.getName()); assertNull(result.getNumber()); } +// +// @Test +// public void testSetsNullToPrimitives() { +// String json = "{\"name\":null,\"number\":null}"; +// +// StreetWithPrimitives result = defaultJsonb.fromJson(json, StreetWithPrimitives.class); +// //these have default initialization value +// assertNull(result.getName()); +// assertNull(result.getNumber()); +// } @Test public void testDeserializeNull() { diff --git a/src/test/java/org/eclipse/yasson/defaultmapping/specific/ObjectGraphTest.java b/src/test/java/org/eclipse/yasson/defaultmapping/specific/ObjectGraphTest.java index 67d7612c3..632207e30 100644 --- a/src/test/java/org/eclipse/yasson/defaultmapping/specific/ObjectGraphTest.java +++ b/src/test/java/org/eclipse/yasson/defaultmapping/specific/ObjectGraphTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 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 @@ -47,4 +47,22 @@ public void testObjectFromJson() { assertCustomerValues(customer.getFriends().get("firstFriend"), "Jasons first friend"); assertCustomerValues(customer.getFriends().get("secondFriend"), "Jasons second friend"); } + + @Test + public void testSimpleObject() { + Person person = new Person(); + person.name = "David"; + person.surname = "Kral"; + String json = bindingJsonb.toJson(person); + Person deser = bindingJsonb.fromJson(json, Person.class); + System.out.println(); + } + + public static class Person { + + public String name; + + public String surname; + + } } diff --git a/src/test/java/org/eclipse/yasson/defaultmapping/specific/RecursiveReferenceTest.java b/src/test/java/org/eclipse/yasson/defaultmapping/specific/RecursiveReferenceTest.java index 3cf15ff1d..b70ae396d 100644 --- a/src/test/java/org/eclipse/yasson/defaultmapping/specific/RecursiveReferenceTest.java +++ b/src/test/java/org/eclipse/yasson/defaultmapping/specific/RecursiveReferenceTest.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 @@ -34,10 +34,12 @@ public class RecursiveReferenceTest { private static final Jsonb userSerializerJsonb = JsonbBuilder.create(new JsonbConfig() - .withSerializers(new ChainSerializer(), new FooSerializer())); + .withSerializers(new ChainSerializer(), + new FooSerializer())); private static final Jsonb adapterSerializerJsonb = JsonbBuilder.create(new JsonbConfig() - .withAdapters(new ChainAdapter(), new FooAdapter())); - + .withAdapters(new ChainAdapter(), + new FooAdapter())); + @Test public void testSerializeRecursiveReference() { Chain recursive = new Chain("test"); @@ -54,7 +56,7 @@ public void testSerializeRecursiveReference() { e.getCause().getMessage()); } } - + @Test public void testSerializeRecursiveReferenceCustomAdapter() { Chain recursive = new Chain("test"); @@ -63,12 +65,12 @@ public void testSerializeRecursiveReferenceCustomAdapter() { adapterSerializerJsonb.toJson(recursive); fail("Exception should be caught"); } catch (JsonbException e) { - assertEquals( - "Problem adapting object of type class org.eclipse.yasson.adapters.model.Chain to java.util.Map in class class org.eclipse.yasson.adapters.model.ChainAdapter", + assertEquals("Problem adapting object of type class org.eclipse.yasson.adapters.model.Chain to java.util.Map in class class org.eclipse.yasson.adapters.model.ChainAdapter", e.getMessage()); } } - + @Test public void testSerializeRecursiveReferenceCustomSerializer() { Chain recursive = new Chain("test"); @@ -77,22 +79,28 @@ public void testSerializeRecursiveReferenceCustomSerializer() { userSerializerJsonb.toJson(recursive); fail("Exception should be caught"); } catch (JsonbException e) { - assertEquals("Recursive reference has been found in class class org.eclipse.yasson.adapters.model.Chain.", e.getMessage()); + assertEquals("Recursive reference has been found in class class org.eclipse.yasson.adapters.model.Chain.", + e.getMessage()); } } @Test public void testSerializeRepeatedInstance() { - checkSerializeRepeatedInstance(Jsonbs.defaultJsonb); - checkSerializeRepeatedInstance(adapterSerializerJsonb); - checkSerializeRepeatedInstance(userSerializerJsonb); + String noNulls = "[{\"linksTo\":{\"name\":\"test\"},\"name\":\"test\"},{\"linksTo\":{\"name\":\"test\"}," + + "\"name\":\"test\"}]"; + String withNulls = "[{\"has\":null,\"linksTo\":{\"has\":null,\"linksTo\":null,\"name\":\"test\"},\"name\":\"test\"}," + + "{\"has\":null,\"linksTo\":{\"has\":null,\"linksTo\":null,\"name\":\"test\"},\"name\":\"test\"}]"; + checkSerializeRepeatedInstance(Jsonbs.defaultJsonb, noNulls); + //Since ChainAdapter is adapting Chain to Map, the produced json will contain nulls + checkSerializeRepeatedInstance(adapterSerializerJsonb, withNulls); + checkSerializeRepeatedInstance(userSerializerJsonb, noNulls); } - - private void checkSerializeRepeatedInstance(Jsonb jsonb) { + + private void checkSerializeRepeatedInstance(Jsonb jsonb, String expected) { Chain recursive = new Chain("test"); recursive.setLinksTo(new Chain("test")); String result = jsonb.toJson(Arrays.asList(recursive, recursive)); - assertEquals("[{\"linksTo\":{\"name\":\"test\"},\"name\":\"test\"},{\"linksTo\":{\"name\":\"test\"},\"name\":\"test\"}]", result); + assertEquals(expected, result); } @Test @@ -104,15 +112,19 @@ public void testSerialize2ReferencesSameObject() { String result = Jsonbs.defaultJsonb.toJson(a); assertEquals("{\"ref1\":{\"bar\":\"foo\"},\"ref2\":{\"bar\":\"foo\"}}", result); } - + @Test public void testChain() { - checkChain(Jsonbs.defaultJsonb); - checkChain(adapterSerializerJsonb); - checkChain(userSerializerJsonb); + String noNulls = "{\"has\":{\"bar\":\"foo\"},\"linksTo\":{\"has\":{\"bar\":\"foo\"},\"name\":\"c2\"},\"name\":\"c1\"}"; + String withNulls = "{\"has\":{\"bar\":\"foo\"},\"linksTo\":{\"has\":{\"bar\":\"foo\"},\"linksTo\":null," + + "\"name\":\"c2\"},\"name\":\"c1\"}"; + checkChain(Jsonbs.defaultJsonb, noNulls); + //Since ChainAdapter is adapting Chain to Map, the produced json will contain nulls + checkChain(adapterSerializerJsonb, withNulls); + checkChain(userSerializerJsonb, noNulls); } - - private void checkChain(Jsonb jsonb) { + + private void checkChain(Jsonb jsonb, String expected) { Foo foo = new Foo("foo"); Chain c1 = new Chain("c1"); Chain c2 = new Chain("c2"); @@ -120,17 +132,22 @@ private void checkChain(Jsonb jsonb) { c1.setHas(foo); c2.setHas(foo); String result = jsonb.toJson(c1); - assertEquals("{\"has\":{\"bar\":\"foo\"},\"linksTo\":{\"has\":{\"bar\":\"foo\"},\"name\":\"c2\"},\"name\":\"c1\"}", result); + assertEquals(expected, result); } - + @Test public void testDeeperChain() { - checkDeeperChain(Jsonbs.defaultJsonb); - checkDeeperChain(adapterSerializerJsonb); - checkDeeperChain(userSerializerJsonb); + String noNulls = "{\"has\":{\"bar\":\"foo\"},\"linksTo\":{\"has\":{\"bar\":\"foo\"},\"linksTo\":{\"name\":\"c3\"}," + + "\"name\":\"c2\"},\"name\":\"c1\"}"; + String withNulls = "{\"has\":{\"bar\":\"foo\"},\"linksTo\":{\"has\":{\"bar\":\"foo\"},\"linksTo\":{\"has\":null," + + "\"linksTo\":null,\"name\":\"c3\"},\"name\":\"c2\"},\"name\":\"c1\"}"; + checkDeeperChain(Jsonbs.defaultJsonb, noNulls); + //Since ChainAdapter is adapting Chain to Map, the produced json will contain nulls + checkDeeperChain(adapterSerializerJsonb, withNulls); + checkDeeperChain(userSerializerJsonb, noNulls); } - - private void checkDeeperChain(Jsonb jsonb) { + + private void checkDeeperChain(Jsonb jsonb, String expected) { Foo foo = new Foo("foo"); Chain c1 = new Chain("c1"); Chain c2 = new Chain("c2"); @@ -140,7 +157,7 @@ private void checkDeeperChain(Jsonb jsonb) { c2.setHas(foo); c2.setLinksTo(c3); String result = jsonb.toJson(c1); - assertEquals("{\"has\":{\"bar\":\"foo\"},\"linksTo\":{\"has\":{\"bar\":\"foo\"},\"linksTo\":{\"name\":\"c3\"},\"name\":\"c2\"},\"name\":\"c1\"}", result); + assertEquals(expected, result); } public static class A { diff --git a/src/test/java/org/eclipse/yasson/defaultmapping/specific/UnmarshallingUnsupportedTypesTest.java b/src/test/java/org/eclipse/yasson/defaultmapping/specific/UnmarshallingUnsupportedTypesTest.java index e7b05fb6e..b6bbf1729 100644 --- a/src/test/java/org/eclipse/yasson/defaultmapping/specific/UnmarshallingUnsupportedTypesTest.java +++ b/src/test/java/org/eclipse/yasson/defaultmapping/specific/UnmarshallingUnsupportedTypesTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 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 @@ -186,19 +186,19 @@ public void testEmptyStringAsBigInteger() { @Test public void testEmptyStringAsOptionalDouble() { Type type = new TestTypeToken>(){}.getType(); - assertFail("{\"field1\":\"\"}", type,"field1", OptionalDouble.class); + assertFail("{\"field1\":\"\"}", type,"field1", Double.class); //We are reusing Double deserializer } @Test public void testEmptyStringAsOptionalInt() { Type type = new TestTypeToken>(){}.getType(); - assertFail("{\"field1\":\"\"}", type, "field1", OptionalInt.class); + assertFail("{\"field1\":\"\"}", type, "field1", Integer.class); //We are reusing Integer deserializer } @Test public void testEmptyStringAsOptionalLong() { Type type = new TestTypeToken>(){}.getType(); - assertFail("{\"field1\":\"\"}", type,"field1", OptionalLong.class); + assertFail("{\"field1\":\"\"}", type,"field1", Long.class); //We are reusing Long deserializer } private void assertFail(String json, Type type, String failureProperty, Class failurePropertyClass) { diff --git a/src/test/java/org/eclipse/yasson/defaultmapping/specific/model/StreetWithPrimitives.java b/src/test/java/org/eclipse/yasson/defaultmapping/specific/model/StreetWithPrimitives.java new file mode 100644 index 000000000..fe4c87296 --- /dev/null +++ b/src/test/java/org/eclipse/yasson/defaultmapping/specific/model/StreetWithPrimitives.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2015, 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.defaultmapping.specific.model; + +/** + * @author Roman Grigoriadi + */ +public class StreetWithPrimitives { + private String name = "defaultName"; + private int number = 11; + + public StreetWithPrimitives() { + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getNumber() { + return number; + } + + public void setNumber(int number) { + this.number = number; + } +} diff --git a/src/test/java/org/eclipse/yasson/internal/ClassParserTest.java b/src/test/java/org/eclipse/yasson/internal/ClassParserTest.java index 49e7bd054..5dd8f42e0 100644 --- a/src/test/java/org/eclipse/yasson/internal/ClassParserTest.java +++ b/src/test/java/org/eclipse/yasson/internal/ClassParserTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 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 @@ -12,6 +12,7 @@ package org.eclipse.yasson.internal; +import org.eclipse.yasson.internal.model.customization.ClassCustomization; import org.junit.jupiter.api.*; import static org.junit.jupiter.api.Assertions.*; @@ -38,7 +39,8 @@ public class ClassParserTest { @Test public void testDefaultMappingFieldModifiers() { final JsonbAnnotatedElement> clsElement = introspector.collectAnnotations(FieldModifiersClass.class); - ClassModel model = new ClassModel(FieldModifiersClass.class, introspector.introspectCustomization(clsElement), null, null); + ClassModel model = new ClassModel(FieldModifiersClass.class, introspector.introspectCustomization(clsElement, + ClassCustomization.empty()), null, null); classParser.parseProperties(model, clsElement); assertTrue(model.getPropertyModel("finalString").isReadable()); assertFalse(model.getPropertyModel("finalString").isWritable()); @@ -51,7 +53,8 @@ public void testDefaultMappingFieldModifiers() { @Test public void testDefaultMappingMethodModifiers() { final JsonbAnnotatedElement> clsElement = introspector.collectAnnotations(MethodModifiersClass.class); - ClassModel model = new ClassModel(FieldModifiersClass.class, introspector.introspectCustomization(clsElement), null, null); + ClassModel model = new ClassModel(FieldModifiersClass.class, introspector.introspectCustomization(clsElement, + ClassCustomization.empty()), null, null); classParser.parseProperties(model, clsElement); assertFalse(model.getPropertyModel("publicFieldWithPrivateMethods").isReadable()); assertFalse(model.getPropertyModel("publicFieldWithPrivateMethods").isWritable()); diff --git a/src/test/java/org/eclipse/yasson/internal/cdi/JndiBeanManager.java b/src/test/java/org/eclipse/yasson/internal/cdi/JndiBeanManager.java index 4de1fabb6..86986244a 100644 --- a/src/test/java/org/eclipse/yasson/internal/cdi/JndiBeanManager.java +++ b/src/test/java/org/eclipse/yasson/internal/cdi/JndiBeanManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 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 @@ -83,11 +83,6 @@ public void validate(InjectionPoint injectionPoint) { } - @Override - public void fireEvent(Object event, Annotation... qualifiers) { - - } - @Override public Set> resolveObserverMethods(T event, Annotation... qualifiers) { throw new UnsupportedOperationException("Not implemented"); @@ -183,15 +178,9 @@ public AnnotatedType createAnnotatedType(Class type) { return null; } - @Override - @SuppressWarnings("unchecked") - public InjectionTarget createInjectionTarget(AnnotatedType type) { - return (InjectionTarget) new MockInjectionTarget(); - } - @Override public InjectionTargetFactory getInjectionTargetFactory(AnnotatedType annotatedType) { - throw new UnsupportedOperationException("Not implemented"); + return new MockInjectionTargetFactory<>(); } @Override diff --git a/src/test/java/org/eclipse/yasson/internal/cdi/MockInjectionTargetFactory.java b/src/test/java/org/eclipse/yasson/internal/cdi/MockInjectionTargetFactory.java new file mode 100644 index 000000000..3a6d8bc99 --- /dev/null +++ b/src/test/java/org/eclipse/yasson/internal/cdi/MockInjectionTargetFactory.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 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.cdi; + +import jakarta.enterprise.inject.spi.Bean; +import jakarta.enterprise.inject.spi.InjectionTarget; +import jakarta.enterprise.inject.spi.InjectionTargetFactory; + +/** + * TODO javadoc + */ +public class MockInjectionTargetFactory implements InjectionTargetFactory { + @Override + public InjectionTarget createInjectionTarget(Bean bean) { + return (InjectionTarget) new MockInjectionTarget(); + } +} diff --git a/src/test/java/org/eclipse/yasson/internal/model/ModulesUtil.java b/src/test/java/org/eclipse/yasson/internal/model/ModulesUtil.java new file mode 100644 index 000000000..094b629ee --- /dev/null +++ b/src/test/java/org/eclipse/yasson/internal/model/ModulesUtil.java @@ -0,0 +1,44 @@ +/* + * 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.model; + +import java.lang.invoke.MethodHandles; + +/** + * Why is this class here?. + * + * This class is here to replace existing classes in test-runtime: + * - src/main/java/org/eclipse/yasson/internal/model/ModulesUtil.java + * - src/main/java9/org/eclipse/yasson/internal/model/ModulesUtil.java + * + * When tests are executed with maven-surefire-plugin the content of + * 'classes' is in a different module-path than 'test-classes'. + * + * This causes the MethodHandles#publicLookup to fail. The reason is that + * test classes to serialize/deserialize are coming from module 'test-classes' + * and the module 'classes' has no access to it. The 'publicLookup' makes some + * validations and because of this different modules, it fails. + * + * It should work if 'classes' and 'test-classes' are merged in one unique module. + * + */ +class ModulesUtil { + + + private ModulesUtil() { + } + + static MethodHandles.Lookup lookup(){ + return MethodHandles.lookup(); + } +} diff --git a/src/test/java/org/eclipse/yasson/jsonpsubstitution/PreinstantiatedJsonpTest.java b/src/test/java/org/eclipse/yasson/jsonpsubstitution/PreinstantiatedJsonpTest.java index 23d0407d6..93c02bb40 100644 --- a/src/test/java/org/eclipse/yasson/jsonpsubstitution/PreinstantiatedJsonpTest.java +++ b/src/test/java/org/eclipse/yasson/jsonpsubstitution/PreinstantiatedJsonpTest.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 @@ -172,13 +172,16 @@ public void testRuntimeTypeParser() { assertEquals("Adapted string", result.getValue()); } + /** + * This test tests that provided generator is actually used. + */ @Test public void testRuntimeTypeGenerator() { Wrapper stringWrapper = new Wrapper<>(); stringWrapper.setValue("String value"); ByteArrayOutputStream out = new ByteArrayOutputStream(); JsonGenerator generator = new SuffixJsonGenerator("Appended value.", out); - bindingYassonJsonb.toJson(stringWrapper, new TestTypeToken>(){}.getType(), generator); + bindingYassonJsonb.toJson(stringWrapper, new TestTypeToken>(){}.getType(), generator); generator.close(); assertEquals("{\"value\":\"String value\",\"suffix\":\"Appended value.\"}", out.toString()); } diff --git a/src/test/java/org/eclipse/yasson/serializers/MapToEntriesArraySerializerTest.java b/src/test/java/org/eclipse/yasson/serializers/MapToEntriesArraySerializerTest.java index eb430aba9..3961dd2af 100644 --- a/src/test/java/org/eclipse/yasson/serializers/MapToEntriesArraySerializerTest.java +++ b/src/test/java/org/eclipse/yasson/serializers/MapToEntriesArraySerializerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021 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 @@ -25,7 +25,6 @@ import java.util.Map; import java.util.Objects; import java.util.Set; -import java.util.TreeMap; import jakarta.json.Json; import jakarta.json.JsonArray; @@ -221,8 +220,8 @@ private static final void verifyMapArrayValues(V[] value, V[] sourceValue, C /** * Build Map key as an array. Get corresponding key from source Map. * - * @param keyArray Map key parsed as JsonArray - * @param source source Map + * @param jentry Map key parsed as JsonArray + * @param sourceEntry source Map */ @SuppressWarnings("unchecked") private static final void verifyMapArrayValue(JsonObject jentry, final JsonArray valueArray, Map.Entry sourceEntry) { @@ -369,21 +368,21 @@ private static final void verifySerialization(Map source, JsonArray assertTrue(keys.isEmpty()); } - - /** - * Test serialization of Map with Number keys and String values. - */ - @Test - public void testSerializeNumberStringMapToEntriesArray() { - Map map = new TreeMap<>(CMP_NUM); - Jsonb jsonb = JsonbBuilder.create(new JsonbConfig().withFormatting(true)); - map.put(Integer.valueOf(12), "twelve"); - map.put(Short.valueOf((short)48), "forty eight"); - map.put(Long.valueOf(256), "two hundred fifty-six"); - String json = jsonb.toJson(map); - JsonArray jarr = Json.createReader(new StringReader(json)).read().asJsonArray(); - verifySerialization(map, jarr); - } +//No longer valid test +// /** +// * Test serialization of Map with Number keys and String values. +// */ +// @Test +// public void testSerializeNumberStringMapToEntriesArray() { +// Map map = new TreeMap<>(CMP_NUM); +// Jsonb jsonb = JsonbBuilder.create(new JsonbConfig().withFormatting(true)); +// map.put(Integer.valueOf(12), "twelve"); +// map.put(Short.valueOf((short)48), "forty eight"); +// map.put(Long.valueOf(256), "two hundred fifty-six"); +// String json = jsonb.toJson(map); +// JsonArray jarr = Json.createReader(new StringReader(json)).read().asJsonArray(); +// verifySerialization(map, jarr); +// } /** * Test serialization of Map with PoJo keys and PoJo values. @@ -406,14 +405,14 @@ public void testSerializePoJoPoJoMapToEntriesArray() { */ @Test public void testSerializeSimpleSimpleMapToEntriesArray() { + String expected = "{\"false\":true,\"10\":24,\"Name\":\"John Smith\"}"; Map map = new HashMap<>(); - Jsonb jsonb = JsonbBuilder.create(new JsonbConfig().withFormatting(true)); + Jsonb jsonb = JsonbBuilder.create(new JsonbConfig()); map.put("Name", "John Smith"); map.put(Integer.valueOf(10), Long.valueOf(24l)); map.put(Boolean.FALSE, Boolean.TRUE); String json = jsonb.toJson(map); - JsonArray jarr = Json.createReader(new StringReader(json)).read().asJsonArray(); - verifySerialization(map, jarr); + assertEquals(expected, json); } /** @@ -460,15 +459,15 @@ public void testDeSerializePrimitivesMapToEntriesArray() { // Make sure that all 3 pokemons were checked. int valueCheck = 0x00; for (Map.Entry entry : map.entrySet()) { - if ((entry.getKey() instanceof String) && "first".equals((String) entry.getKey())) { + if ((entry.getKey() instanceof String) && "first".equals(entry.getKey())) { assertEquals("Peter Parker", entry.getValue()); valueCheck |= 0x01; } - if ((entry.getKey() instanceof Number) && ((Number) entry.getKey()).equals(new BigDecimal(42))) { + if ((entry.getKey() instanceof Number) && entry.getKey().equals(new BigDecimal(42))) { assertEquals(true, entry.getValue()); valueCheck |= 0x02; } - if ((entry.getKey() instanceof Boolean) && ((Boolean) entry.getKey()).equals(false)) { + if ((entry.getKey() instanceof Boolean) && entry.getKey().equals(false)) { assertEquals(new BigDecimal(21), entry.getValue()); valueCheck |= 0x04; } diff --git a/src/test/java/org/eclipse/yasson/serializers/SerializersTest.java b/src/test/java/org/eclipse/yasson/serializers/SerializersTest.java index 4d92ed282..453da85c7 100644 --- a/src/test/java/org/eclipse/yasson/serializers/SerializersTest.java +++ b/src/test/java/org/eclipse/yasson/serializers/SerializersTest.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 @@ -37,6 +37,8 @@ import java.util.TimeZone; import java.util.TreeMap; +import jakarta.json.bind.annotation.JsonbTypeDeserializer; +import jakarta.json.bind.annotation.JsonbTypeSerializer; import org.eclipse.yasson.TestTypeToken; import org.eclipse.yasson.YassonConfig; import org.eclipse.yasson.internal.model.ReverseTreeMap; @@ -370,7 +372,7 @@ public void testSupertypeSerializer() { } @Test - public void testObjectDerializerWithLexOrderStrategy() { + public void testObjectDeserializerWithLexOrderStrategy() { Jsonb jsonb = JsonbBuilder.create(new JsonbConfig().withPropertyOrderStrategy(PropertyOrderStrategy.LEXICOGRAPHICAL)); Object pojo = jsonb.fromJson("{\"first\":{},\"third\":{},\"second\":{\"second\":2,\"first\":1}}", Object.class); assertTrue(pojo instanceof TreeMap, "Pojo is not of type TreeMap"); @@ -381,7 +383,7 @@ public void testObjectDerializerWithLexOrderStrategy() { } @Test - public void testObjectDerializerWithReverseOrderStrategy() { + public void testObjectDeserializerWithReverseOrderStrategy() { Jsonb jsonb = JsonbBuilder.create(new JsonbConfig().withPropertyOrderStrategy(PropertyOrderStrategy.REVERSE)); Object pojo = jsonb.fromJson("{\"first\":{},\"second\":{\"first\":1,\"second\":2},\"third\":{}}", Object.class); assertTrue(pojo instanceof ReverseTreeMap, "Pojo is not of type ReverseTreeMap"); @@ -392,7 +394,7 @@ public void testObjectDerializerWithReverseOrderStrategy() { } @Test - public void testObjectDerializerWithAnyOrNoneOrderStrategy() { + public void testObjectDeserializerWithAnyOrNoneOrderStrategy() { String json = "{\"first\":{},\"second\":{\"first\":1,\"second\":2},\"third\":{}}"; // ANY Jsonb jsonb = JsonbBuilder.create(new JsonbConfig().withPropertyOrderStrategy(PropertyOrderStrategy.ANY)); diff --git a/src/test/java/org/eclipse/yasson/serializers/model/AnnotatedWithSerializerTypeDeserializer.java b/src/test/java/org/eclipse/yasson/serializers/model/AnnotatedWithSerializerTypeDeserializer.java index 63214eaf5..a006d99c4 100644 --- a/src/test/java/org/eclipse/yasson/serializers/model/AnnotatedWithSerializerTypeDeserializer.java +++ b/src/test/java/org/eclipse/yasson/serializers/model/AnnotatedWithSerializerTypeDeserializer.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 @@ -33,7 +33,8 @@ public class AnnotatedWithSerializerTypeDeserializer implements JsonbDeserialize @Override public AnnotatedWithSerializerType deserialize(JsonParser parser, DeserializationContext ctx, Type rtType) { AnnotatedWithSerializerType result = new AnnotatedWithSerializerType(); - parser.next(); parser.next(); + parser.next(); + parser.next(); result.value = parser.getString(); return result; } diff --git a/src/test/java/org/eclipse/yasson/serializers/model/SimpleContainerArrayDeserializer.java b/src/test/java/org/eclipse/yasson/serializers/model/SimpleContainerArrayDeserializer.java old mode 100755 new mode 100644 index 301479abc..04ecebd6e --- a/src/test/java/org/eclipse/yasson/serializers/model/SimpleContainerArrayDeserializer.java +++ b/src/test/java/org/eclipse/yasson/serializers/model/SimpleContainerArrayDeserializer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020 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 diff --git a/src/test/java/org/eclipse/yasson/serializers/model/SimpleContainerArraySerializer.java b/src/test/java/org/eclipse/yasson/serializers/model/SimpleContainerArraySerializer.java old mode 100755 new mode 100644 index d265ea45f..dc0704c90 --- a/src/test/java/org/eclipse/yasson/serializers/model/SimpleContainerArraySerializer.java +++ b/src/test/java/org/eclipse/yasson/serializers/model/SimpleContainerArraySerializer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020 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 diff --git a/src/test/java16/org/eclipse/yasson/records/RecordTest.java b/src/test/java16/org/eclipse/yasson/records/RecordTest.java index 5087c8387..39710414b 100644 --- a/src/test/java16/org/eclipse/yasson/records/RecordTest.java +++ b/src/test/java16/org/eclipse/yasson/records/RecordTest.java @@ -19,6 +19,8 @@ import org.eclipse.yasson.internal.properties.Messages; import org.junit.jupiter.api.Test; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -52,9 +54,9 @@ public void testRecordProcessingWithExtraMethod() { String expected = "{\"color\":\"green\",\"type\":\"skoda\"}"; String json = Jsonbs.defaultJsonb.toJson(car); - assertEquals(expected, json); + assertThat(json, is(expected)); CarWithExtraMethod deserialized = Jsonbs.defaultJsonb.fromJson(expected, CarWithExtraMethod.class); - assertEquals(car, deserialized); + assertThat(deserialized, is(car)); } @Test @@ -63,12 +65,12 @@ public void testRecordMultipleConstructors() { String expected = "{\"color\":\"red\",\"type\":\"skoda\"}"; String json = Jsonbs.defaultJsonb.toJson(car); - assertEquals(expected, json); + assertThat(json, is(expected)); JsonbException jsonbException = assertThrows(JsonbException.class, () -> Jsonbs.defaultJsonb.fromJson(expected, CarWithMultipleConstructors.class)); String expectedMessage = Messages.getMessage(MessageKeys.RECORD_MULTIPLE_CONSTRUCTORS, CarWithMultipleConstructors.class); - assertEquals(expectedMessage, jsonbException.getMessage()); + assertThat(jsonbException.getMessage(), is(expectedMessage)); } @Test @@ -77,10 +79,10 @@ public void testRecordMultipleConstructorsWithJsonbCreator() { String expected = "{\"color\":\"red\",\"type\":\"skoda\"}"; String json = Jsonbs.defaultJsonb.toJson(car); - assertEquals(expected, json); + assertThat(json, is(expected)); CarWithMultipleConstructorsAndCreator deserialized = Jsonbs.defaultJsonb .fromJson(expected, CarWithMultipleConstructorsAndCreator.class); - assertEquals(car, deserialized); + assertThat(car, is(deserialized)); } @Test @@ -89,9 +91,9 @@ public void testRecordJsonbCreator() { String expected = "{\"color\":\"red\",\"type\":\"skoda\"}"; String json = Jsonbs.defaultJsonb.toJson(car); - assertEquals(expected, json); + assertThat(json, is(expected)); CarWithCreator deserialized = Jsonbs.defaultJsonb.fromJson(expected, CarWithCreator.class); - assertEquals(car, deserialized); + assertThat(deserialized, is(car)); } } diff --git a/src/test/resources/test.policy b/src/test/resources/test.policy index 7435edf22..98f0a53ff 100644 --- a/src/test/resources/test.policy +++ b/src/test/resources/test.policy @@ -8,4 +8,6 @@ grant { permission java.lang.RuntimePermission "setSecurityManager"; permission "java.lang.RuntimePermission" "getProtectionDomain"; permission "java.util.PropertyPermission" "*", "write"; + + permission "java.util.PropertyPermission" "jsonb.creator-parameters-required", "read"; }; \ No newline at end of file diff --git a/yasson-jmh/pom.xml b/yasson-jmh/pom.xml index 6f1cf3761..dcdd30361 100644 --- a/yasson-jmh/pom.xml +++ b/yasson-jmh/pom.xml @@ -14,7 +14,7 @@ 1.21 - 1.0.7-SNAPSHOT + 2.0.2-SNAPSHOT diff --git a/yasson-tck/pom.xml b/yasson-tck/pom.xml index ddf84be1c..b3b508890 100644 --- a/yasson-tck/pom.xml +++ b/yasson-tck/pom.xml @@ -10,12 +10,12 @@ 1.0.0-SNAPSHOT - 2.0.0-SNAPSHOT - 2.0.3-SNAPSHOT - 1.8 - 1.8 + 3.0.0-SNAPSHOT + 3.0.0-SNAPSHOT + 11 + 11 - + diff --git a/yasson-tck/src/main/java/ee/jakarta/tck/json/bind/customizedmapping/numberformat/NumberFormatCustomizationTest.java b/yasson-tck/src/main/java/ee/jakarta/tck/json/bind/customizedmapping/numberformat/NumberFormatCustomizationTest.java new file mode 100644 index 000000000..a49d25168 --- /dev/null +++ b/yasson-tck/src/main/java/ee/jakarta/tck/json/bind/customizedmapping/numberformat/NumberFormatCustomizationTest.java @@ -0,0 +1,222 @@ +/* + * 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 + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +/* + * $Id$ + */ + +package ee.jakarta.tck.json.bind.customizedmapping.numberformat; + +import java.text.DecimalFormatSymbols; +import java.util.Locale; + +import jakarta.json.bind.Jsonb; +import jakarta.json.bind.JsonbBuilder; + +import ee.jakarta.tck.json.bind.customizedmapping.numberformat.model.AccessorCustomizedDoubleContainer; +import ee.jakarta.tck.json.bind.customizedmapping.numberformat.model.FieldCustomizedDoubleContainer; +import ee.jakarta.tck.json.bind.customizedmapping.numberformat.model.TypeCustomizedDoubleContainer; +import ee.jakarta.tck.json.bind.customizedmapping.numberformat.model.TypeCustomizedFieldOverriddenDoubleContainer; +import ee.jakarta.tck.json.bind.customizedmapping.numberformat.model.customized.PackageCustomizedDoubleContainer; +import ee.jakarta.tck.json.bind.customizedmapping.numberformat.model.customized.PackageCustomizedTypeOverriddenDoubleContainer; +import ee.jakarta.tck.json.bind.customizedmapping.numberformat.model.customized.PackageCustomizedTypeOverriddenFieldOverriddenDoubleContainer; +import org.junit.jupiter.api.Test; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.matchesPattern; + +/** + * @test + * @sources NumberFormatCustomizationTest.java + * @executeClass com.sun.ts.tests.jsonb.customizedmapping.numberformat.NumberFormatCustomizationTest + **/ +public class NumberFormatCustomizationTest { + + private static final String FRENCH_NUMBER = "\"123\\u00a0456,789\""; + + private final Jsonb jsonb = JsonbBuilder.create(); + + /* + * @testName: testNumberFormatPackage + * + * @assertion_ids: JSONB:SPEC:JSB-4.9-1 + * + * @test_Strategy: Assert that package annotation with JsonbNumberFormat is + * correctly applied + */ + @Test + public void testNumberFormatPackage() { + String jsonString = jsonb.toJson(new PackageCustomizedDoubleContainer() {{ + setInstance(123456.789); + }}); + assertThat("Failed to correctly customize number format during marshalling using JsonbNumberFormat annotation on " + + "package.", + jsonString, matchesPattern("\\{\\s*\"instance\"\\s*:\\s*\"123.456,8\"\\s*\\}")); + + PackageCustomizedDoubleContainer unmarshalledObject = jsonb.fromJson("{ \"instance\" : \"123.456,789\" }", + PackageCustomizedDoubleContainer.class); + + assertThat( + "Failed to correctly customize number format during unmarshalling using JsonbNumberFormat annotation on package.", + unmarshalledObject.getInstance(), + is(123456.789)); + } + + /* + * @testName: testNumberFormatType + * + * @assertion_ids: JSONB:SPEC:JSB-4.9-1 + * + * @test_Strategy: Assert that type annotation with JsonbNumberFormat is + * correctly applied + */ + @Test + public void testNumberFormatType() { + String jsonString = jsonb.toJson(new TypeCustomizedDoubleContainer() {{ + setInstance(123456.789); + }}); + assertThat("Failed to correctly customize number format during marshalling using JsonbNumberFormat annotation on type.", + jsonString, matchesPattern("\\{\\s*\"instance\"\\s*:\\s*\"123,456.79\"\\s*\\}")); + + TypeCustomizedDoubleContainer unmarshalledObject = jsonb.fromJson("{ \"instance\" : \"123,456.789\" }", + TypeCustomizedDoubleContainer.class); + assertThat("Failed to correctly customize number format during unmarshalling using JsonbNumberFormat annotation on type.", + unmarshalledObject.getInstance(), is(123456.789)); + + } + + /* + * @testName: testNumberFormatField + * + * @assertion_ids: JSONB:SPEC:JSB-4.9-1 + * + * @test_Strategy: Assert that field annotation with JsonbNumberFormat is + * correctly applied + */ + @Test + public void testNumberFormatField() { + char separator = DecimalFormatSymbols.getInstance(Locale.FRENCH).getGroupingSeparator(); + String jsonString = jsonb.toJson(new FieldCustomizedDoubleContainer() {{ + setInstance(123456.789); + }}); + assertThat("Failed to correctly customize number format during marshalling using JsonbNumberFormat annotation on field.", + jsonString, matchesPattern("\\{\\s*\"instance\"\\s*:\\s*\"123" + separator + "456,789\"\\s*\\}")); + + FieldCustomizedDoubleContainer unmarshalledObject = jsonb.fromJson("{ \"instance\" : " + FRENCH_NUMBER + " }", + FieldCustomizedDoubleContainer.class); + assertThat("Failed to correctly customize number format during unmarshalling using JsonbNumberFormat annotation on " + + "field.", + unmarshalledObject.getInstance(), is(123456.789)); + } + + /* + * @testName: testNumberFormatAccessors + * + * @assertion_ids: JSONB:SPEC:JSB-4.9-1 + * + * @test_Strategy: Assert that accessor annotation with JsonbNumberFormat is + * correctly individually applied for marshalling and unmarshalling + */ + @Test + public void testNumberFormatAccessors() { + String jsonString = jsonb.toJson(new AccessorCustomizedDoubleContainer() {{ + setInstance(123456.789); + }}); + assertThat("Failed to correctly customize number format during marshalling using JsonbNumberFormat annotation on getter.", + jsonString, matchesPattern("\\{\\s*\"instance\"\\s*:\\s*\"123,456.79\"\\s*\\}")); + + AccessorCustomizedDoubleContainer unmarshalledObject = jsonb.fromJson("{ \"instance\" : " + FRENCH_NUMBER + " }", + AccessorCustomizedDoubleContainer.class); + assertThat( + "Failed to correctly customize number format during unmarshalling using JsonbNumberFormat annotation on setter.", + unmarshalledObject.getInstance(), + is(123456.789)); + } + + /* + * @testName: testNumberFormatPackageTypeOverride + * + * @assertion_ids: JSONB:SPEC:JSB-4.9-1; JSONB:SPEC:JSB-4.9-2 + * + * @test_Strategy: Assert that package annotation with JsonbNumberFormat is + * correctly overridden by type annotation with JsonbNumberFormat + */ + @Test + public void testNumberFormatPackageTypeOverride() { + String jsonString = jsonb.toJson(new PackageCustomizedTypeOverriddenDoubleContainer() {{ + setInstance(123456.789); + }}); + assertThat("Failed to correctly override number format customization using JsonbNumberFormat annotation on " + + "package during marshalling using JsonbNumberFormat annotation on type.", + jsonString, matchesPattern("\\{\\s*\"instance\"\\s*:\\s*\"123,456.79\"\\s*\\}")); + + PackageCustomizedTypeOverriddenDoubleContainer unmarshalledObject = jsonb.fromJson("{ \"instance\" : \"123,456.789\" }", + PackageCustomizedTypeOverriddenDoubleContainer.class); + assertThat("Failed to correctly override number format customization using JsonbNumberFormat annotation on " + + "package during unmarshalling using JsonbNumberFormat annotation on type.", + unmarshalledObject.getInstance(), is(123456.789)); + } + + /* + * @testName: testNumberFormatTypeFieldOverride + * + * @assertion_ids: JSONB:SPEC:JSB-4.9-1; JSONB:SPEC:JSB-4.9-2 + * + * @test_Strategy: Assert that type annotation with JsonbNumberFormat is + * correctly overridden by field annotation with JsonbNumberFormat + */ + @Test + public void testNumberFormatTypeFieldOverride() { + String jsonString = jsonb.toJson(new TypeCustomizedFieldOverriddenDoubleContainer() {{ + setInstance(123456.789); + }}); + assertThat("Failed to correctly customize number format during marshalling using JsonbNumberFormat annotation on type.", + jsonString, matchesPattern("\\{\\s*\"instance\"\\s*:\\s*\"123,456.8\"\\s*\\}")); + + TypeCustomizedFieldOverriddenDoubleContainer unmarshalledObject = jsonb.fromJson("{ \"instance\" : \"123,456.789\" }", + TypeCustomizedFieldOverriddenDoubleContainer.class); + assertThat("Failed to correctly customize number format during unmarshalling using JsonbNumberFormat annotation on type.", + unmarshalledObject.getInstance(), is(123456.789)); + } + + /* + * @testName: testNumberFormatPackageTypeOverrideFieldOverride + * + * @assertion_ids: JSONB:SPEC:JSB-4.9-1; JSONB:SPEC:JSB-4.9-2 + * + * @test_Strategy: Assert that package and type annotation with + * JsonbNumberFormat is correctly overridden by field annotation with + * JsonbNumberFormat + */ + @Test + public void testNumberFormatPackageTypeOverrideFieldOverride() { + String jsonString = jsonb.toJson(new PackageCustomizedTypeOverriddenFieldOverriddenDoubleContainer() {{ + setInstance(123456.789); + }}); + assertThat("Failed to correctly override number format customization using JsonbNumberFormat annotation on " + + "package during marshalling using JsonbNumberFormat annotation on type.", + jsonString, matchesPattern("\\{\\s*\"instance\"\\s*:\\s*\"123.456,789\"\\s*\\}")); + + PackageCustomizedTypeOverriddenFieldOverriddenDoubleContainer unmarshalledObject = + jsonb.fromJson("{ \"instance\" : \"123.456,789\" }", + PackageCustomizedTypeOverriddenFieldOverriddenDoubleContainer.class); + assertThat("Failed to correctly override number format customization using JsonbNumberFormat annotation on " + + "package during unmarshalling using JsonbNumberFormat annotation on type.", + unmarshalledObject.getInstance(), is(123456.789)); + } + +} diff --git a/yasson-tck/src/main/java/jakarta/json/bind/tck/customizedmapping/numberformat/NumberFormatCustomizationTest.java b/yasson-tck/src/main/java/jakarta/json/bind/tck/customizedmapping/numberformat/NumberFormatCustomizationTest.java deleted file mode 100644 index 3501d43ce..000000000 --- a/yasson-tck/src/main/java/jakarta/json/bind/tck/customizedmapping/numberformat/NumberFormatCustomizationTest.java +++ /dev/null @@ -1,293 +0,0 @@ -/* - * Copyright (c) 2017, 2018 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. - * - * This Source Code may also be made available under the following Secondary - * Licenses when the conditions for such availability set forth in the - * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, - * version 2 with the GNU Classpath Exception, which is available at - * https://www.gnu.org/software/classpath/license.html. - * - * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 - */ - -/* - * $Id$ - */ - -package jakarta.json.bind.tck.customizedmapping.numberformat; - -import static org.junit.Assert.fail; - -import java.lang.invoke.MethodHandles; -import java.text.DecimalFormatSymbols; -import java.util.Locale; - -import org.jboss.arquillian.container.test.api.Deployment; -import org.jboss.arquillian.junit.Arquillian; -import org.jboss.shrinkwrap.api.ShrinkWrap; -import org.jboss.shrinkwrap.api.spec.WebArchive; -import org.junit.Test; -import org.junit.runner.RunWith; - -import jakarta.json.bind.Jsonb; -import jakarta.json.bind.JsonbBuilder; -import jakarta.json.bind.tck.customizedmapping.numberformat.model.AccessorCustomizedDoubleContainer; -import jakarta.json.bind.tck.customizedmapping.numberformat.model.FieldCustomizedDoubleContainer; -import jakarta.json.bind.tck.customizedmapping.numberformat.model.TypeCustomizedDoubleContainer; -import jakarta.json.bind.tck.customizedmapping.numberformat.model.TypeCustomizedFieldOverriddenDoubleContainer; -import jakarta.json.bind.tck.customizedmapping.numberformat.model.customized.PackageCustomizedDoubleContainer; -import jakarta.json.bind.tck.customizedmapping.numberformat.model.customized.PackageCustomizedTypeOverriddenDoubleContainer; -import jakarta.json.bind.tck.customizedmapping.numberformat.model.customized.PackageCustomizedTypeOverriddenFieldOverriddenDoubleContainer; - -/** - * This is just temporal work around for failing test testNumberFormatField. - * - * It is failing due to changed FR number format separator. - **/ -@RunWith(Arquillian.class) -public class NumberFormatCustomizationTest { - - @Deployment - public static WebArchive createTestArchive() { - return ShrinkWrap.create(WebArchive.class) - .addPackages(true, MethodHandles.lookup().lookupClass().getPackage().getName()); - } - - private static final String FRENCH_NUMBER = "\"123\\u00a0456,789\""; - - private final Jsonb jsonb = JsonbBuilder.create(); - - /* - * @testName: testNumberFormatPackage - * - * @assertion_ids: JSONB:SPEC:JSB-4.9-1 - * - * @test_Strategy: Assert that package annotation with JsonbNumberFormat is - * correctly applied - */ - @Test - public void testNumberFormatPackage() { - String jsonString = jsonb.toJson(new PackageCustomizedDoubleContainer() { - { - setInstance(123456.789); - } - }); - if (!jsonString - .matches("\\{\\s*\"instance\"\\s*:\\s*\"123.456,8\"\\s*\\}")) { - fail( - "Failed to correctly customize number format during marshalling using JsonbNumberFormat annotation on package."); - } - - PackageCustomizedDoubleContainer unmarshalledObject = jsonb.fromJson( - "{ \"instance\" : \"123.456,789\" }", - PackageCustomizedDoubleContainer.class); - if (unmarshalledObject.getInstance() != 123456.789) { - fail( - "Failed to correctly customize number format during unmarshalling using JsonbNumberFormat annotation on package."); - } - - return; // passed - } - - /* - * @testName: testNumberFormatType - * - * @assertion_ids: JSONB:SPEC:JSB-4.9-1 - * - * @test_Strategy: Assert that type annotation with JsonbNumberFormat is - * correctly applied - */ - @Test - public void testNumberFormatType() { - String jsonString = jsonb.toJson(new TypeCustomizedDoubleContainer() { - { - setInstance(123456.789); - } - }); - if (!jsonString - .matches("\\{\\s*\"instance\"\\s*:\\s*\"123,456.79\"\\s*\\}")) { - fail( - "Failed to correctly customize number format during marshalling using JsonbNumberFormat annotation on type."); - } - - TypeCustomizedDoubleContainer unmarshalledObject = jsonb.fromJson( - "{ \"instance\" : \"123,456.789\" }", - TypeCustomizedDoubleContainer.class); - if (unmarshalledObject.getInstance() != 123456.789) { - fail( - "Failed to correctly customize number format during unmarshalling using JsonbNumberFormat annotation on type."); - } - - return; // passed - } - - /* - * @testName: testNumberFormatField - * - * @assertion_ids: JSONB:SPEC:JSB-4.9-1 - * - * @test_Strategy: Assert that field annotation with JsonbNumberFormat is - * correctly applied - */ - @Test - public void testNumberFormatField() { - //Franch group separator has been changed in JDK 13 and it is now backwords incompatible. - char frenchGroupingSeparator = DecimalFormatSymbols.getInstance(Locale.FRENCH).getGroupingSeparator(); - String jsonString = jsonb.toJson(new FieldCustomizedDoubleContainer() { - { - setInstance(123456.789); - } - }); - if (!jsonString - .matches("\\{\\s*\"instance\"\\s*:\\s*\"123"+frenchGroupingSeparator+"456,789\"\\s*\\}")) { - fail( - "Failed to correctly customize number format during marshalling using JsonbNumberFormat annotation on field."); - } - - FieldCustomizedDoubleContainer unmarshalledObject = jsonb.fromJson( - "{ \"instance\" : " + FRENCH_NUMBER + " }", - FieldCustomizedDoubleContainer.class); - if (unmarshalledObject.getInstance() != 123456.789) { - fail( - "Failed to correctly customize number format during unmarshalling using JsonbNumberFormat annotation on field."); - } - - return; // passed - } - - /* - * @testName: testNumberFormatAccessors - * - * @assertion_ids: JSONB:SPEC:JSB-4.9-1 - * - * @test_Strategy: Assert that accessor annotation with JsonbNumberFormat is - * correctly individually applied for marshalling and unmarshalling - */ - @Test - public void testNumberFormatAccessors() { - String jsonString = jsonb.toJson(new AccessorCustomizedDoubleContainer() { - { - setInstance(123456.789); - } - }); - if (!jsonString - .matches("\\{\\s*\"instance\"\\s*:\\s*\"123,456.79\"\\s*\\}")) { - fail( - "Failed to correctly customize number format during marshalling using JsonbNumberFormat annotation on getter."); - } - - AccessorCustomizedDoubleContainer unmarshalledObject = jsonb.fromJson( - "{ \"instance\" : " + FRENCH_NUMBER + " }", - AccessorCustomizedDoubleContainer.class); - if (unmarshalledObject.getInstance() != 123456.789) { - fail( - "Failed to correctly customize number format during unmarshalling using JsonbNumberFormat annotation on setter."); - } - - return; // passed - } - - /* - * @testName: testNumberFormatPackageTypeOverride - * - * @assertion_ids: JSONB:SPEC:JSB-4.9-1; JSONB:SPEC:JSB-4.9-2 - * - * @test_Strategy: Assert that package annotation with JsonbNumberFormat is - * correctly overridden by type annotation with JsonbNumberFormat - */ - @Test - public void testNumberFormatPackageTypeOverride() { - String jsonString = jsonb - .toJson(new PackageCustomizedTypeOverriddenDoubleContainer() { - { - setInstance(123456.789); - } - }); - if (!jsonString - .matches("\\{\\s*\"instance\"\\s*:\\s*\"123,456.79\"\\s*\\}")) { - fail( - "Failed to correctly override number format customization using JsonbNumberFormat annotation on package during marshalling using JsonbNumberFormat annotation on type."); - } - - PackageCustomizedTypeOverriddenDoubleContainer unmarshalledObject = jsonb - .fromJson("{ \"instance\" : \"123,456.789\" }", - PackageCustomizedTypeOverriddenDoubleContainer.class); - if (unmarshalledObject.getInstance() != 123456.789) { - fail( - "Failed to correctly override number format customization using JsonbNumberFormat annotation on package during unmarshalling using JsonbNumberFormat annotation on type."); - } - - return; // passed - } - - /* - * @testName: testNumberFormatTypeFieldOverride - * - * @assertion_ids: JSONB:SPEC:JSB-4.9-1; JSONB:SPEC:JSB-4.9-2 - * - * @test_Strategy: Assert that type annotation with JsonbNumberFormat is - * correctly overridden by field annotation with JsonbNumberFormat - */ - @Test - public void testNumberFormatTypeFieldOverride() { - String jsonString = jsonb - .toJson(new TypeCustomizedFieldOverriddenDoubleContainer() { - { - setInstance(123456.789); - } - }); - if (!jsonString - .matches("\\{\\s*\"instance\"\\s*:\\s*\"123,456.8\"\\s*\\}")) { - fail( - "Failed to correctly customize number format during marshalling using JsonbNumberFormat annotation on type."); - } - - TypeCustomizedFieldOverriddenDoubleContainer unmarshalledObject = jsonb - .fromJson("{ \"instance\" : \"123,456.789\" }", - TypeCustomizedFieldOverriddenDoubleContainer.class); - if (unmarshalledObject.getInstance() != 123456.789) { - fail( - "Failed to correctly customize number format during unmarshalling using JsonbNumberFormat annotation on type."); - } - - return; // passed - } - - /* - * @testName: testNumberFormatPackageTypeOverrideFieldOverride - * - * @assertion_ids: JSONB:SPEC:JSB-4.9-1; JSONB:SPEC:JSB-4.9-2 - * - * @test_Strategy: Assert that package and type annotation with - * JsonbNumberFormat is correctly overridden by field annotation with - * JsonbNumberFormat - */ - @Test - public void testNumberFormatPackageTypeOverrideFieldOverride() { - String jsonString = jsonb.toJson( - new PackageCustomizedTypeOverriddenFieldOverriddenDoubleContainer() { - { - setInstance(123456.789); - } - }); - if (!jsonString - .matches("\\{\\s*\"instance\"\\s*:\\s*\"123.456,789\"\\s*\\}")) { - fail( - "Failed to correctly override number format customization using JsonbNumberFormat annotation on package during marshalling using JsonbNumberFormat annotation on type."); - } - - PackageCustomizedTypeOverriddenFieldOverriddenDoubleContainer unmarshalledObject = jsonb - .fromJson("{ \"instance\" : \"123.456,789\" }", - PackageCustomizedTypeOverriddenFieldOverriddenDoubleContainer.class); - if (unmarshalledObject.getInstance() != 123456.789) { - fail( - "Failed to correctly override number format customization using JsonbNumberFormat annotation on package during unmarshalling using JsonbNumberFormat annotation on type."); - } - - return; // passed - } -}