回调方法执行后JSON反对泽西JAX RS
问题描述:
我使用泽西休息服务与杰克逊API为JSON
字符串转换为POJO
s转换。需要验证POJO
类的所有成员变量。我已经有了用于验证的框架。回调方法执行后JSON反对泽西JAX RS
我想知道的是,如果有任何回调方法或机制可以调用我的验证API发布JSON
到POJO
转换本身。这样做会使我的工作更轻松,因为我不必在Rest服务类的所有地方调用API。
public class MyPojoClass{
private int interestRateCode;
private String name;
//just edited
private List<TestDTO> testObjs;
//Psuedo code
//@PostDeserialization
public String callbackMethod(Object obj){
if(!ValidationAPI.validate(obj))
return "false";
}
}
的TestDTO:
public class TestDTO {
private int var1;
private String stringVar;
public TestDTO() {
System.out.println("This constructor does get called every time");
}
}
有没有像PostDeserialization任何注解来实现这一目标。这将帮助我使每个POJO
类只有一个回调方法进行验证。
我传递的JSON是
{"interestRateCode": 101,"name": "T",
"testObjs": [
{"var1" :10, "stringVar": "Arunabh"},
{"var1" :15, "stringVar": "Hejib"}
]}
任何人谁可以帮助我在这个问题?谢谢你的帮助。
答
一两件事你可以做的是使用一个Request Filter。在过滤器您可以:
- 利用喷射的
ResourceInfo
- 通过遍历
Method
Parameter
S和检查没有任何注释的方法参数获取实体类获取资源Method
。除非使用bean validation,否则在参数旁边使用@Valid
,则实体参数始终是没有注释的参数。这是我们如何确定实体参数。从参数中,我们得到这个类。 - 从请求中获取实体对象。
- 从实体类,从反射使用,找到
Method
与@PostDeserialization
注解。 - 使用反射调用该方法。
下面是一个完整的测试。 ValidationFilter
是前面提到的步骤。
import org.glassfish.jersey.server.ContainerRequest;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.Test;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.client.Entity;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.ResourceInfo;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import java.io.IOException;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import static org.junit.Assert.assertEquals;
/**
* Run like any other JUnit test. A couple required dependencies.
*
* <dependency>
* <groupId>org.glassfish.jersey.test-framework.providers</groupId>
* <artifactId>jersey-test-framework-provider-grizzly2</artifactId>
* <version>${jersey2.version}</version>
* <scope>test</scope>
* </dependency>
* <dependency>
* <groupId>org.glassfish.jersey.media</groupId>
* <artifactId>jersey-media-json-jackson</artifactId>
* <version>${jersey2.version}</version>
* </dependency>
*/
public class PostDeserializationTest extends JerseyTest {
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface PostDeserialization {}
public static class ValidationError extends RuntimeException {
public ValidationError(String message) {
super(message);
}
}
public static class ValidationErrorMapper
implements ExceptionMapper<ValidationError> {
@Override
public Response toResponse(ValidationError ex) {
return Response.status(Response.Status.BAD_REQUEST)
.entity(ex.getMessage())
.build();
}
}
public static class Bean {
public String value;
@PostDeserialization
public void validate() {
if (!"expected".equals(value)) {
throw new ValidationError("value must be 'expected'");
}
}
}
public static class ValidationFilter implements ContainerRequestFilter {
@Context
private ResourceInfo info;
@Override
public void filter(ContainerRequestContext request) throws IOException {
Class<?> entityClass = getEntityClass();
if (entityClass != null) {
final ContainerRequest cr = (ContainerRequest) request;
cr.bufferEntity();
final Object entity = cr.readEntity(entityClass);
findMethodAndValidate(entity);
}
}
private Class<?> getEntityClass() {
final Method rm = info.getResourceMethod();
final Annotation[][] paramAnnotations = rm.getParameterAnnotations();
for (int i = 0; i < paramAnnotations.length; i++) {
// entity parameters have no annotations.
if (paramAnnotations[i].length == 0) {
return rm.getParameterTypes()[i];
}
}
return null;
}
private void findMethodAndValidate(Object entity) {
final Method[] methods = entity.getClass().getMethods();
for (Method method: methods) {
if (method.isAnnotationPresent(PostDeserialization.class)) {
// validation method should take no parameters.
if (method.getParameterCount() != 0) {
throw new RuntimeException(
"Validation method must not have parameters.");
}
try {
method.invoke(entity);
} catch (InvocationTargetException ex) {
// if an exception happens during invocation,
// an InvocationException is thrown. We want the cause,
// expecting it to be a ValidationError.
Throwable cause = ex.getCause();
if (cause instanceof ValidationError) {
throw (ValidationError) cause;
} else {
throw new RuntimeException(ex);
}
} catch (Exception ex) {
throw new RuntimeException(
"Error calling validation method.", ex);
}
}
}
}
}
@Path("test")
public static class TestResource {
@POST
@Consumes("application/json")
public String post(Bean bean) {
return bean.value;
}
}
@Override
public ResourceConfig configure() {
return new ResourceConfig()
.register(TestResource.class)
.register(ValidationErrorMapper.class)
.register(ValidationFilter.class)
.register(new ExceptionMapper<Throwable>() {
@Override
public Response toResponse(Throwable t) {
t.printStackTrace();
return Response.serverError()
.entity(t.getMessage()).build();
}
});
}
@Test
public void testValidationError() {
final Bean bean = new Bean();
bean.value = "not expected";
final Response response = target("test")
.request()
.post(Entity.json(bean));
assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), response.getStatus());
assertEquals("value must be 'expected'", response.readEntity(String.class));
}
@Test
public void testNoValidationError() {
final Bean bean = new Bean();
bean.value = "expected";
final Response response = target("test")
.request()
.post(Entity.json(bean));
assertEquals(Response.Status.OK.getStatusCode(), response.getStatus());
assertEquals("expected", response.readEntity(String.class));
}
}
感谢。我会尝试实现这一点。 – Arunabh
我得到java.lang.NoSuchMethodError:java.lang.reflect.Method.getParameters()内getEntityClass()方法。任何想法可能是这个原因。我正在使用Java7。 – Arunabh
我用Java8来摆脱这个错误。不知道我的产品是否允许使用Java 8,那么您可以告诉我如何使它适用于Java7。此外,执行停止在这一行final Object entity = cr.readEntity(entityClass);看起来像这条线有问题,但我没有看到任何堆栈跟踪。 – Arunabh