MessageBodyReader如何知道泛型类型是什么?

时间:2016-05-13 21:05:06

标签: java jersey

我有一个MessageBodyReader,其中包含以下类:

@Provider
@Consumes(MediaType.APPLICATION_JSON)
public class TransactionMessageBodyReader implements MessageBodyReader<Transaction<Customer>> 

boolean isReadable(Class<?> type,
                       Type genericType,
                       Annotation[] annotations,
                       MediaType mediaType)

我有以下REST端点:

@POST
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
@Path("trans")
public Response checkStatus(Transaction<Customer> transaction) { ... }

在我的调试器中,我在isReadable上有一个断点,它在调用checkStatus方法之前命中断点。目前很好。我可以在调试器中看到genericTypeTransaction<Customer> ...换句话说,它知道类型信息。当Java类型擦除在运行时将其删除为Transaction时,它怎么可能知道类型信息?我看到genericTypeParameterizedType组成,我认为它用于传递类型信息(以解决类型擦除问题)。但是,泽西岛如何自动填充genericType?因为我从未指定类型信息,除了我在上面发布的方法标题中。

另外,第二个问题:如果泽西岛'自动'了解我的类型,为什么我需要一个MessageBodyReader?是不是有一些更简单的方法来使用泛型与Jersey / REST端点并使其“正常工作”?

1 个答案:

答案 0 :(得分:4)

查看javadoc

  

genericType - 要生成的实例类型。例如。如果要将邮件正文转换为方法参数,这将是Method.getGenericParameterTypes 返回的方法参数的正式类型。

类,方法和字段中的通用参数化保留在相应的.class文件中。这显然是编译所必需的。如果不是这种情况,您将无法打包和使用Java类作为库。

Reflection公开了这种类型信息(以及更多)。

Jersey基本上会扫描您的类中的处理程序方法,使用@POST注释的方法等,并检索相应的Method个对象。一旦有了,就可以使用Method#getGenericParameterTypes()

  

返回表示形式参数的Type个对象数组   声明顺序的类型,由此表示的可执行文件   宾语。如果是底层可执行文件,则返回长度为0的数组   没有参数。

     

如果形式参数类型是参数化类型,则为Type对象   返回它必须准确反映实际的类型参数   在源代码中使用。

换句话说,Type必须表示参数的原始类型及其参数化(如果有)。

因此,Jersey会检索这些类型并将其输入您的MessageBodyReader。期望您的实现应该能够处理genericType

我不太了解Jersey,但如果它遵循与Spring MVC相同的策略,它将简单地遍历已注册的所有MessageBodyReader个实例。它实际上并不关心它的类型(例如你的TransactionMessageBodyReader),这就是它依赖isReadable的原因。从理论上讲,它可以保持类型到MessageBodyReader实现的映射,但最终变得难以处理并且不够灵活。在任何情况下,应用程序通常不具有可以序列化的许多类型/格式,因此迭代一些对象并不是一件大事。

从Java 8开始,您还可以访问Executable#getParametersMethodExecutable的子类型。)

以下是泽西岛可以做的一个例子

public class StackOverflow {
    public static void main(String[] args) throws Exception {
        Method method = StackOverflow.class.getDeclaredMethod("method", List.class);
        Type[] parameterTypes = method.getGenericParameterTypes();
        for (Type parameterType : parameterTypes) {
            System.out.println(parameterType.getClass());
            System.out.println(parameterType);
            ParameterizedType parameterizedType = (ParameterizedType) parameterType;
            System.out
                    .println(parameterizedType.getRawType().getTypeName() + "<" + parameterizedType.getActualTypeArguments()[0].getTypeName() + ">");
        }
    }

    public String method(List<StackOverflow> parameter) {
        return "example";

    }
}

打印

class sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl
java.util.List<com.example.StackOverflow>
java.util.List<com.example.StackOverflow>