Configure jackson to use single-arg constructor

ε祈祈猫儿з 提交于 2019-12-12 01:57:14

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!