`JacksonSerializer` does not respect `JsonTypeInfo`
Author: beroalCreated Jul 15, 2026Updated Aug 24, 2026
To Reproduce
final MacAlgorithm macAlgorithm = Jwts.SIG.HS256;
final SecretKey secretKey = macAlgorithm.key().build();
final ObjectMapper objectMapper = new ObjectMapper();
objectMapper.addMixIn(SimpleGrantedAuthority.class, SimpleGrantedAuthorityMixin.class);
final String NAME = "additional";
final JacksonSerializer jacksonSerializer = new JacksonSerializer(objectMapper);
final JacksonDeserializer jacksonDeserializer = new JacksonDeserializer(
objectMapper,
Map.of(NAME, SimpleGrantedAuthority.class)
);
final JwtBuilder builder = Jwts.builder().json(jacksonSerializer);
builder.claims().add(NAME, new SimpleGrantedAuthority("ROLE_ADMIN"));
final String jwt = builder.signWith(secretKey, macAlgorithm).compact();
final JwtParser parser = Jwts.parser().json(jacksonDeserializer).verifyWith(secretKey).build();
final Object payload = parser.parse(jwt).getPayload();
System.out.println(new String((byte[]) payload));The above program prints
{"additional":{"authority":"ROLE_ADMIN"}}In the above program, JwtParser returns a byte[] payload.
Expected behavior
It should return Claims.
Explanation
The reason is that Jackson can't parse the payload because the JSON object corresponding to SimpleGrantedAuthority doesn't contain the "@class" property. The exception that Jackson throws is
com.fasterxml.jackson.databind.exc.InvalidTypeIdException: Could not resolve subtype of [simple type, class org.springframework.security.core.authority.SimpleGrantedAuthority]: missing type id property '@class' at [Source: UNKNOWN; line: -1, column: -1]The SimpleGrantedAuthorityMixin has the following annotation on it:
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)so the JSON object should contain the "@class" property.
BTW, JJWT drops this exception. This makes harder to understand why parsing of the payload failed.
For reference:
public final class SimpleGrantedAuthority implements GrantedAuthority {
private static final long serialVersionUID = 620L;
private final String role;
public SimpleGrantedAuthority(String authority) {
Assert.hasText(authority, "A granted authority textual representation is required");
this.role = authority;
}
@Override
public String getAuthority() {
return this.role;
}
@Override
public boolean equals(@Nullable Object obj) {
/* skipped */
}
@Override
public int hashCode() {
return this.role.hashCode();
}
@Override
public String toString() {
return this.role;
}
}
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.NONE,
getterVisibility = JsonAutoDetect.Visibility.PUBLIC_ONLY, isGetterVisibility = JsonAutoDetect.Visibility.NONE)
public abstract class SimpleGrantedAuthorityMixin {
@JsonCreator
public SimpleGrantedAuthorityMixin(@JsonProperty("authority") String role) {
}
}Source: jwtk/jjwt