问题
I have an immutable object SimpleGrantedAuthority from spring which does not have a no-arg constructor. Instead it is an immutable object with only 1 single-arg constructor like this:
public SimpleGrantedAuthority(String role) {
Assert.hasText(role, "A granted authority textual representation is required");
this.role = role;
}
I'm trying to deserialize a string to this object and I don't have access to the source code of this file. Here's the exception I get:
Caused by: com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of org.springframework.security.core.authority.SimpleGrantedAuthority: no suitable constructor found, can not deserialize from Object value (missing default constructor or creator, or perhaps need to add/enable type information?)
at [Source: java.util.zip.GZIPInputStream@e1fb329; line: 7, column: 7] (through reference chain: com.nemesis.platform.facade.email.data.EnrichedEmailMessageContextData["customer"]->com.nemesis.platform.facade.user.data.EnrichedUserDetails["authorities"]->java.util.ArrayList[0])
at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:270)
at com.fasterxml.jackson.databind.DeserializationContext.instantiationException(DeserializationContext.java:1456)
Like I said I don't have the source code and I cannot add the @JsonCreator annotation, so I'm wondering how to configure jackson to understand the correct constructor to use. Something in the likes of:
Module module = new SimpleModule("MyModule") {
@Override
public void setupModule(Module.SetupContext context) {
context.addAbstractTypeResolver(new SimpleAbstractTypeResolver().addMapping(GrantedAuthority.class, SimpleGrantedAuthority.class));
}
};
Thank you
EDIT
I tried the suggestion of Shashank so I created this class:
abstract class SimpleGrantedAuthorityMixIn {
@JsonCreator
SimpleGrantedAuthorityMixIn(@JsonProperty("authority") String authority) {
}
}
and then I registered it like this:
Module module = new SimpleModule("SamplestoreModule") {
@Override
public void setupModule(Module.SetupContext context) {
context.addAbstractTypeResolver(new SimpleAbstractTypeResolver().addMapping(GrantedAuthority.class, SimpleGrantedAuthority.class));
context.setMixInAnnotations(SimpleGrantedAuthority.class, SimpleGrantedAuthorityMixIn.class);
}
};
objectMapper.registerModule(module);
objectMapper.addMixIn(SimpleGrantedAuthority.class, SimpleGrantedAuthorityMixIn.class);
but I still see the same exception.
回答1:
You need to use mixin which will provide all meta data to jackson without modifying actual pojo.
Third party class:
public class SingleArgConstructor {
public int getN() {
return n;
}
int n;
public SingleArgConstructor( int n) {
this.n = n;
}
@Override
public String toString() {
return "SingleArgConstructor{" +
"n=" + n +
'}';
}
}
Mixin in you code:
abstract class MixIn {
@JsonCreator
MixIn(@JsonProperty("n") int n) { }
}
Configuring mapper:
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.addMixIn(SingleArgConstructor.class,MixIn.class);
Reading value:
System.out.println(objectMapper.readValue("{\"n\":10}",SingleArgConstructor.class));
I hope this helps.
EDITED Sharing complete code:
Abstract class
/**
* Created by shashankt on 6/12/16.
*/
public abstract class AbstractArgsConstructor {
int n;
public AbstractArgsConstructor( int n) {
this.n = n;
}
}
Concrete implementation
import com.fasterxml.jackson.databind.Module;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleAbstractTypeResolver;
import com.fasterxml.jackson.databind.module.SimpleModule;
import java.io.IOException;
/**
* Created by shashankt on 4/12/16.
*/
public class SingleArgConstructor extends AbstractArgsConstructor{
public SingleArgConstructor(int n) {
super(n);
}
public int getN() {
return n;
}
public static void main(String[] args) throws IOException {
Module module = new SimpleModule("SamplestoreModule") {
@Override
public void setupModule(Module.SetupContext context) {
context.addAbstractTypeResolver(new SimpleAbstractTypeResolver().addMapping(AbstractArgsConstructor.class, SingleArgConstructor.class));
}
};
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(module);
objectMapper.addMixIn(SingleArgConstructor.class,Mixin.class);
System.out.println(objectMapper.getDeserializationConfig().findMixInClassFor(AbstractArgsConstructor.class));
System.out.println(objectMapper.getDeserializationConfig().findMixInClassFor(SingleArgConstructor.class));
SingleArgConstructor pojo = new SingleArgConstructor(10);
System.out.println(objectMapper.readValue(" {\"p\":10}",AbstractArgsConstructor.class));
}
@Override
public String toString() {
return "SingleArgConstructor{" +
"n=" + n +
'}';
}
}
with mixin
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
/**
* Created by shashankt on 4/12/16.
*/
abstract class Mixin {
@JsonCreator
Mixin(@JsonProperty("p") int n) { }
}
Output
null
class Mixin
SingleArgConstructor{n=10}
Process finished with exit code 0
来源:https://stackoverflow.com/questions/40959022/configure-jackson-to-use-single-arg-constructor