java.lang.AssertionError: Cannot construct instance of java.lang.Enum

时间:2015-06-15 15:20:07

标签: java jackson resteasy

I am developing a client/server application, that in the backend has some REST methods developed with RESTeasy.

Particularly, there is a POST method that, as input, takes a JSON string, and then returns another JSON to the calling client.

The conversion from JSON to a Java class is performed by Jackson in a transparent way, but I have this problem:

java.lang.AssertionError: Can not construct instance of java.lang.Enum, problem: abstract types can only be instantiated with additional type information

The JUnit Test that fails with this error is:

/**
 * Test for creation of json of {@link FindRequestBody}.
 */
@Test
public void testJackson2(){
    try {
        FindRequestBody findRequestBody = new FindRequestBody();        

        ObjectMapper jacksonMapper = new ObjectMapper();
        ObjectMapper mapper = new ObjectMapper();

        File file = new File("c:\\testFindRequestBody.json");
        jacksonMapper.writeValue(file, findRequestBody);

        Path path = Paths.get("c:\\testFindRequestBody.json");
        byte[] data = Files.readAllBytes(path);

        FindRequestBody returned = jacksonMapper.readValue(data, FindRequestBody.class);

        Assert.assertNotNull(returned);

    } 
    catch (JsonGenerationException e) {
        e.printStackTrace();
        Assert.fail(e.getMessage());
    } 
    catch (JsonMappingException e) {
        e.printStackTrace();
        Assert.fail(e.getMessage());
    } 
    catch (IOException e) {
        e.printStackTrace();
        Assert.fail(e.getMessage());
    } 

The REST method is:

 /**
 * {@inheritDoc}
 */
@POST
@Path("/filter")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@Override
public List<Object> find(FindRequestBody findRequestBody){
    return service.find(findRequestBody);
}

The JSON taken as input from the method is, for example:

{     
   "orderReadContext":{  
      "valid":"VALID_ONLY"
   },
   "queryControl":{  
      "firstResult":0,
      "maxResults":-1,
      "sortOrder":[      
      ]
   }
}

The field valid is a field that maps an Enum. The FieldRequestBody class contains the OrderReadContext class that is:

public class OrderReadContext implements Serializable
{
    protected ValidOrAll valid = ValidOrAll.VALID_ONLY;

    public ValidOrAll getValid()
    {
        return this.valid;
    }

   public void setValid(ValidOrAll arg)
   {
        if (arg == null)
        {
            this.valid = ValidOrAll.VALID_ONLY;
        }
        else
        {
            this.valid = arg;
         }
    }
}

Probably caused by the fact that, in the Java class corresponding to the JSON, there are some fields that are Enum.

I cannot use annotations, so I want to know if it is possible to use some Providers, or Interceptors, etc.

1 个答案:

答案 0 :(得分:0)

我已经解决了创建此类提供程序的问题:

@Provider
@Produces(MediaType.APPLICATION_JSON)
public class JacksonJsonProvider implements ContextResolver<ObjectMapper> {

    private ObjectMapper objectMapper;

    public JacksonJsonProvider() throws Exception {
        this.objectMapper = new ObjectMapper();

        System.out.println("JacksonJsonProvider():: Enter Into Constructor");        
        /*
         * First, you can globally declare that certain types always require additional type information:           
         * objectMapper.enableDefaultTyping(); // default to using DefaultTyping.OBJECT_AND_NON_CONCRETE
         * what this means is that for all types specified (for no-args, "Object.class" and all non-final classes), certain amount of default type information (Java class name, more specifically), is included, using default inclusion mechanism (additional wrapper array in JSON). This global default can be overridden by per-class annotations (more on this in next section).
         * 
         * The only thing you can configure, then, is just which types (classes) are affected. Choices are:
         * JAVA_LANG_OBJECT: only affects properties of type Object.class
         * OBJECT_AND_NON_CONCRETE: affects Object.class and all non-concrete types (abstract classes, interfaces)
         * NON_CONCRETE_AND+_ARRAYS: same as above, and all array types of the same (direct elements are non-concrete types or Object.class)
         * NON_FINAL: affects all types that are not declared 'final', and array types of non-final element types. 
         * This is often simplest initial way to enable enough type information to get things going. 
         */
         getObjectMapperForSerialization();

         System.out.println("JacksonJsonProvider():: Enabled Default Typing And Exit Constructor");
    }

    protected void getObjectMapperForSerialization() {
        System.out.println("JacksonJsonProvider():: Enter Into getObjectMapperForSerialization()");
        StdTypeResolverBuilder typeResolverBuilder = new ObjectMapper.DefaultTypeResolverBuilder(ObjectMapper.DefaultTyping.OBJECT_AND_NON_CONCRETE);
        typeResolverBuilder = typeResolverBuilder.inclusion(JsonTypeInfo.As.PROPERTY);
        typeResolverBuilder.init(JsonTypeInfo.Id.CLASS, new ClassNameIdResolver(SimpleType.construct(Base.class), TypeFactory.defaultInstance()));
        this.objectMapper.setDefaultTyping(typeResolverBuilder);
    }

    public ObjectMapper getContext(Class<?> objectType) {
        return objectMapper;
    }
}

将其注册到web.xml中,在resteasy-providers之间。