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

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

我正在开发一个 client/server 应用程序,它在后端有一些使用 RESTeasy 开发的 REST 方法。

特别是,有一个 POST 方法,作为输入,接受一个 JSON 字符串,然后 returns 另一个 JSON 到调用客户端。

从 JSON 到 Java class 的转换是由 Jackson 以透明的方式执行的,但我遇到了这个问题:

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

因此错误而失败的 JUnit 测试是:

/**
 * 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());
    } 

REST 方法是:

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

作为方法输入的JSON例如:

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

有效字段是映射 Enum 的字段。 FieldRequestBody class 包含 OrderReadContext class 即:

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;
         }
    }
}

可能是因为在JSON对应的Javaclass中,有一些字段是Enum.

我不能使用注解,所以我想知道是否可以使用一些提供者,或者拦截器等

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

@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 之间。