Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, 2023 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 2025 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
Expand All @@ -22,6 +22,7 @@
import java.util.LinkedList;
import java.util.ListIterator;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;

Expand Down Expand Up @@ -142,17 +143,10 @@ private ModelSerializer serializerChainInternal(LinkedList<Type> chain,
boolean rootValue,
boolean isKey,
boolean resolveRootAdapter) {
if (explicitChain.containsKey(type)) {
return explicitChain.get(type);
}
Class<?> rawType = ReflectionUtils.getRawType(type);
Optional<ModelSerializer> serializerBinding = userSerializer(type,
(ComponentBoundCustomization) propertyCustomization);
if (serializerBinding.isPresent()) {
return serializerBinding.get();
}
if (resolveRootAdapter) {
Optional<AdapterBinding> maybeAdapter = adapterBinding(type, (ComponentBoundCustomization) propertyCustomization);
// Check for adapter binding first, even if we have a cached serializer
if (resolveRootAdapter && propertyCustomization instanceof ComponentBoundCustomization) {
ComponentBoundCustomization componentBound = (ComponentBoundCustomization) propertyCustomization;
Optional<AdapterBinding> maybeAdapter = adapterBinding(type, componentBound);
if (maybeAdapter.isPresent()) {
AdapterBinding adapterBinding = maybeAdapter.get();
Type toType = adapterBinding.getToType();
Expand All @@ -170,6 +164,17 @@ private ModelSerializer serializerChainInternal(LinkedList<Type> chain,
}
}

if (explicitChain.containsKey(type)) {
return explicitChain.get(type);
}
Class<?> rawType = ReflectionUtils.getRawType(type);
Optional<ModelSerializer> serializerBinding = propertyCustomization instanceof ComponentBoundCustomization
? userSerializer(type, (ComponentBoundCustomization) propertyCustomization)
: Optional.empty();
if (serializerBinding.isPresent()) {
return serializerBinding.get();
}

ModelSerializer typeSerializer = null;
if (!Object.class.equals(rawType)) {
typeSerializer = TypeSerializers.getTypeSerializer(chain, rawType, propertyCustomization, jsonbContext, isKey);
Expand Down Expand Up @@ -356,6 +361,17 @@ private ModelSerializer memberSerializer(LinkedList<Type> chain,
return serializerBinding.get();
}
Optional<AdapterBinding> maybeAdapter = adapterBinding(resolved, (ComponentBoundCustomization) customization);
// If no adapter found, also check the type's own class customization as a fallback
// This ensures class-level @JsonbTypeAdapter annotations are always considered
if (maybeAdapter.isEmpty()) {
ClassModel classModel = jsonbContext.getMappingContext().getOrCreateClassModel(rawType);
ComponentBoundCustomization classCustomization = classModel.getClassCustomization();
// Only check class customization if it's different from what we already checked
if (customization == null || !Objects.equals(classCustomization, customization)) {
maybeAdapter = adapterBinding(resolved, classCustomization);
}
}

if (maybeAdapter.isPresent()) {
AdapterBinding adapterBinding = maybeAdapter.get();
Type toType = adapterBinding.getToType();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, 2022 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 2025 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
Expand All @@ -21,6 +21,8 @@
import jakarta.json.stream.JsonGenerator;

import org.eclipse.yasson.internal.SerializationContextImpl;
import org.eclipse.yasson.internal.model.ClassModel;
import org.eclipse.yasson.internal.model.customization.ComponentBoundCustomization;
import org.eclipse.yasson.internal.model.customization.Customization;
import org.eclipse.yasson.internal.serializer.ModelSerializer;
import org.eclipse.yasson.internal.serializer.SerializationModelCreator;
Expand Down Expand Up @@ -64,10 +66,26 @@ private void findSerializer(Object key, JsonGenerator generator, SerializationCo
Class<?> clazz = key.getClass();
cache.computeIfAbsent(clazz, aClass -> {
SerializationModelCreator serializationModelCreator = context.getJsonbContext().getSerializationModelCreator();
return serializationModelCreator.serializerChainRuntime(new LinkedList<>(chain), clazz, customization, false, isKey);
// For regular objects, check if the class has its own customization with potential adapter bindings
// This ensures that class-level annotations like @JsonbTypeAdapter are respected
ClassModel classModel = context.getJsonbContext().getMappingContext().getOrCreateClassModel(aClass);
Customization effectiveCustomization = getEffectiveCustomization(classModel);
return serializationModelCreator.serializerChainRuntime(new LinkedList<>(chain), aClass, effectiveCustomization, false, isKey);
}).serialize(key, generator, context);
}

private Customization getEffectiveCustomization(ClassModel classModel) {
Customization classCustomization = classModel.getClassCustomization();

// Use class customization if it has adapter bindings, otherwise use the context customization
boolean hasAdapterBinding = false;
if (classCustomization instanceof ComponentBoundCustomization) {
ComponentBoundCustomization componentBound = (ComponentBoundCustomization) classCustomization;
hasAdapterBinding = componentBound.getSerializeAdapterBinding() != null;
}
return hasAdapterBinding ? classCustomization : customization;
}

/**
* Add serializer to the cache.
*
Expand Down
Loading