Generics using wildcard not correctly resolved #5285
Copy link
Copy link
Closed
Description
Search before asking
- I searched in the issues and found nothing similar.
Describe the bug
I opened a Spring Boot issue, but it seems the issue is Jackson related. See spring-projects/spring-boot#46994 (comment) for the full details and a reproducer.
Version Information
2.19.2
Reproduction
package com.example.jsontesterbug;
import static org.assertj.core.api.Assertions.assertThat;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.Arrays;
import org.junit.jupiter.api.Test;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
class MessageWrapperTest {
private MessageWrapper<?> wildcardWrapper;
private MessageWrapper<EmailSettings> specificWrapper;
private ObjectMapper objectMapper = new ObjectMapper();
@Test
void wildcardWrapper() throws NoSuchFieldException, SecurityException, JsonProcessingException {
serializeWithTypeFromField("wildcardWrapper");
}
@Test
void specificWrapper() throws NoSuchFieldException, SecurityException, JsonProcessingException {
serializeWithTypeFromField("specificWrapper");
}
private void serializeWithTypeFromField(String field) throws NoSuchFieldException, SecurityException, JsonProcessingException {
MessageWrapper<EmailSettings> wrapper = new MessageWrapper<>(new EmailSettings("me@me.com"),
"Sample Message");
Type genericType = MessageWrapperTest.class.getDeclaredField(field).getGenericType();
TypeVariable<?>[] typeParameters = ((Class<?>)((ParameterizedType)genericType).getRawType()).getTypeParameters();
Type[] bounds = typeParameters[0].getBounds();
System.out.println(field);
System.out.println(" Generic type: " + genericType);
System.out.println(" Bounds: " + Arrays.toString(bounds));
JavaType jacksonType = this.objectMapper.constructType(genericType);
System.out.println(" Jackson type: " + jacksonType);
String json = this.objectMapper.writerFor(jacksonType).writeValueAsString(wrapper);
System.out.println(" JSON: " + json);
assertThat(json).contains("\"type\":\"EMAIL\"");
assertThat(json).contains("\"email\":\"me@me.com\"");
}
}Running this gives this output:
wildcardWrapper
Generic type: com.example.jsontesterbug.MessageWrapper<?>
Bounds: [interface com.example.jsontesterbug.Settings]
Jackson type: [simple type, class com.example.jsontesterbug.MessageWrapper<java.lang.Object>]
JSON: {"settings":{"email":"me@me.com"},"message":"Sample Message"}
specificWrapper
Generic type: com.example.jsontesterbug.MessageWrapper<com.example.jsontesterbug.EmailSettings>
Bounds: [interface com.example.jsontesterbug.Settings]
Jackson type: [simple type, class com.example.jsontesterbug.MessageWrapper<com.example.jsontesterbug.EmailSettings>]
JSON: {"settings":{"type":"EMAIL","email":"me@me.com"},"message":"Sample Message"}
Expected behavior
The JSON output should be the same in both cases.
Additional context
No response
Reactions are currently unavailable
Activity
pjfanning commentedon Aug 29, 2025
Can you provide the definition of the MessageWrapper class?
wimdeblauwe commentedon Aug 29, 2025
You can view it in the zip file of the Spring Boot issue as well, but here it is:
This is the
Settingsinterface:With
EmailSettings:and
PhoneSettings:cowtowncoder commentedon Sep 6, 2025
Probably makes no difference, but there is now 2.20.0 release to try out.
cowtowncoder commentedon Sep 6, 2025
This:
shows underlying problem: type is resolved as
MessageWrapper<?>and that's why@JsonTypeInfodoes not take effect. This is from gettingmethod signature, which for some reason does not handle bounds for
MessageWrappertype parameter.Test could probably be simplified to just that type resolution problem.
@yawkat might be familiar with this problem actually.
Add failing test for wildcard generic type resolution (#5285)
Fixes #5285
cowtowncoder commentedon Feb 4, 2026
Fixed in 3.x for 3.1.0 (post -rc1)
Fixes FasterXML#5285 (FasterXML#5639)