Resteasy (JBoss AS 6) validation - jboss

I'm looking for a good pattern of providing custom validation of input for Resteasy services.
Let's say I've this service:
#Local
#Path("/example")
public interface IExample {
public Response doSomething ( #QueryParam("arg1") String arg1, #QueryParam("arg2") Integer arg2);
}
which I've implemented:
#Stateless
public class Example implements IExample {
#Override
public Response doSomething ( String arg1, Integer arg2 ) { ... }
}
What's the best practice to validate arg1 and arg2?
My ideas:
Validate inside doSomething(...) method. Drawback: when I add some parameter (ex. arg3) in the future, I could easily forget to validate it.
In custom javax.servlet.Filter. Drawback: I cannot access arg1 and arg2 there as they're not yet parsed by Resteasy framework.
I came up with this concept:
public class ExampleValidator implements IExample {
public static class ValidationError extends RuntimeException { ... }
#Override
public Response doSomething ( String arg1, Integer arg2 ) {
// here do validation. In case of failure, throw ValidationError
return null;
}
}
which can be used as follows:
#Stateless
public class Example implements IExample {
#Override
public Response doSomething ( String arg1, Integer arg2 ) {
try {
(new ExampleValidator()).doSomething(arg1, arg2);
} catch ( ValidationError e ) {
// return Response with 400
}
}
}
In that way, when I change IExample.doSomething method signature, I have to update Validator because of compile time error. In order for Resteasy NOT TO interpret ExampleValidator as a service, I used resteasy.jndi.resources instead of resteasy.scan, but it fails (Example bean is loaded after resteasy attempts to use it on deploy time).
Any ideas - are there any good patterns of validation?
Or is it possible to somehow get my concept to work?
EDIT: Or, which would be the best, there is some Filter counterpart in Resteasy? Some scheme by which my method (Filter) would be called before actual implementation, but with parameters (arg1, arg2) already parsed?
Thanks in advance, sorry for a lengthy post ;)
Kamil

(1) Probably the cleanest approach is to use Java EE 6 Bean Validation framework. This would require writing custom validation interceptor. In this case you would have to change your methods, so instead of
public Response doSomething ( String arg1, Integer arg2 )
you would use domain object as an argument
public Response doSomething ( JAXBElement<MyDomainObject> myOJaxb )
Then you need to trasform your request, so they provide XML or JSON formatted data, which can ba automatically converted to actual object.
(2) Another option is to use normal ServletFilter.
(3) Prepare custom annotations a'la Bean Validation, then you need to plug-in custom annotations processor (look at project Lombok, as an inspiration).
(4) The simplest solution is to use built-in REST validation
#Path("users/{username: [a-zA-Z][a-zA-Z_0-9]}")
but this applies to path parameters, not query parameters (I think, but didn't check with JAX-RS spec)
Your choice depends on how much flexibility you have with your interfaces and how many time you have.
If you would come up with a generic, pluggable to Resteasy solution similar to suggested in option (3) and make it open source on GitHub many people would love you :)

Related

How can I use then() block with RestAssured while using POJO classes?

While working on RestAssured I came across the concept of Serialization and DeSerialization(POJO Classes) to read and validate the response. I went through some tutorial and was able to create the POJO class based on my response.
However, when I use the POJO class reference in my Tests I am not able to use the then() block for different assertions. Below details might clear things bit more :
TestMethod without POJO :
public void listUsers() {
RestAssured.baseURI="https://reqres.in/";
Response res = RestAssured.given()
.contentType("application/json")
.queryParam("page", 2)
.when()
.get("/api/users")
.then()
.assertThat().statusCode(200).and()
.body("page", Matchers.equalTo(2)).and()
.body("total", Matchers.greaterThanOrEqualTo(1))
.body("data.email", Matchers.hasItem("george.edwards#reqres.in"))
.extract().response();
JsonPath jsonpath = new JsonPath(res.asString());
System.out.println(jsonpath.get("data[0].email"));
}
Test Method with POJO :
public void listUserswithPOJO() {
RestAssured.baseURI="https://reqres.in/";
ListUsers res = RestAssured.given()
.contentType("application/json")
.queryParam("page", 2)
.when()
.get("/api/users").as(ListUsers.class);
System.out.println(res.getData().get(1).getEmail());
}
Test Class :
#Test
public void listUsersTest() {
ReqResApi TS1 = new ReqResApi();
TS1.listUserswithPOJO();
}
I want to keep the assertions of the then block as it is while using POJO classes as well. When I try to do so after as(ListUser.class), it gives the compilation error that then() is undefined for ListUser class.
Is there any way in which I can use both POJO class as well as then() block in my rest assured tests.
This is not possible because Return types of these options are different.
MainPojo m1 =RestAssured.given().contentType("application/json").queryParam("page", 2).when().get("/api/users")
.as(MainPojo.class)==> Return Type is ur Class, in this example Main Pojo
System.out.println(m1.getData().get(0).getFirst_name());
RestAssured.given().contentType("application/json").queryParam("page", 2).when()
.get("/api/users").then().assertThat().statusCode(200).and().body("page", Matchers.equalTo(2)).and()
.body("total", Matchers.greaterThanOrEqualTo(1))
.body("data.email", Matchers.hasItem("george.edwards#reqres.in")).extract().response();---> Return Type is Response

Dumping bad requests

I have a service implemented with Dropwizard and I need to dump incorrect requests somewhere.
I saw that there is a possibility to customise the error message by registering ExceptionMapper<JerseyViolationException>. But I need to have the complete request (headers, body) and not only ConstraintViolations.
You can inject ContainerRequest into the ExceptionMapper. You need to inject it as a javax.inject.Provider though, so that you can lazily retrieve it. Otherwise you will run into scoping problems.
#Provider
public class Mapper implements ExceptionMapper<ConstraintViolationException> {
#Inject
private javax.inject.Provider<ContainerRequest> requestProvider;
#Override
public Response toResponse(ConstraintViolationException ex) {
ContainerRequest request = requestProvider.get();
}
}
(This also works with constructor argument injection instead of field injection.)
In the ContainerRequest, you can get headers with getHeaderString() or getHeaders(). If you want to get the body, you need to do a little hack because the entity stream is already read by Jersey by the time the mapper is reached. So we need to implement a ContainerRequestFilter to buffer the entity.
public class EntityBufferingFilter implements ContainerRequestFilter {
#Override
public void filter(ContainerRequestContext containerRequestContext) throws IOException {
ContainerRequest request = (ContainerRequest) containerRequestContext;
request.bufferEntity();
}
}
You might not want this filter to be called for all requests (for performance reasons), so you might want to use a DynamicFeature to register the filter just on methods that use bean validation (or use Name Binding).
Once you have this filter registered, you can read the body using ContainerRequest#readEntity(Class). You use this method just like you would on the client side with Response#readEntity(). So for the class, if you want to keep it generic, you can use String.class or InputStream.class and convert the InputStream to a String.
ContainerRequest request = requestProvider.get();
String body = request.readEntity(String.class);

Get Annotation Parameter with AspectJ

I read many question in this forum but nothing works.
public #interface MyAnnotation {
String value() default "";
Class[] exceptionList;
}
#MyAnnotation(value="hello", exceptionList={TimeOutException.class})
public void method() {}
#Aspect
public class MyAspect {
#Around("#annotation(MyAnnotation)")
public Object handle(ProceedingJoinPoint joinPoint, MyAnnotation myAnnotation) {
System.out.println(myAnnotation.exceptionList); // should print out TimeOutException
}
}
How can I get the value and the exceptionList of the #MyAnnotation while executing the advice?
I'm using Spring 4.0.6, AspectJ 1.7.4
The solution for this is making sure the advice method's parameter name match the parameter name in AspectJ expression. In my case, the advice method should look like this:
#Aspect
public class MyAspect {
#Around("#annotation(myAnnotation)")
public Object handle(ProceedingJoinPoint joinPoint, MyAnnotation myAnnotation) {
System.out.println(myAnnotation.exceptionList); // should print out TimeOutException
}
}
You are already almost there. Probably.
You are using the correct way to retrieve the annotation, so you have the values available.
Your problem - if I interpret the very minimalistic problem description(!) you only provide via the comment in your code snippet(!) correctly - is the (wrong) assumption that sticking an array of the type Class into System.out.println() will print out the names of the Classes it contains. It does not. Instead it prints information about the reference:
[Ljava.lang.Class;#15db9742
If you want the names of the Classes, you will have to iterate over the elements of that array and use .getName(), .getSimpleName() or one of the other name providing methods of Class.
Further information on how to print elements of an array is here:
What's the simplest way to print a Java array?
Granted, this whole answer could be entirely besides the point if the problem is that you are getting null values from the annotation fields. But since you have not provided an adequate problem description ("nothing works" is not a problem description!), we can only guess at what your problem is.

Interface query parameter parsing?

I believe this is not possible, but I just wanted to verify.
I would like to do something like...
#Path("/awesome")
public class MyRestResource {
#GET
public void coolQuery(#QueryParam("user") User) {
// ...
}
}
public interface User {
String name();
Address address();
}
(Please don't comment on the example... it's completely made-up and not my use case.)
I imagine this is not possible because Jersey/JAX-RS generally requires a static method public static T valueOf(String input) which obviously is not possible with interfaces.
That said, is there any work-around for this to have a query parameter be an interface? And if so, how do you specify the parser / parsing logic?
Thanks
According to the documentation there are more ways than just the static valueOf method:
Be a primitive type;
Have a constructor that accepts a single String argument;
Have a static method named valueOf or fromString that accepts a single String argument (see, for example, Integer.valueOf(String) and java.util.UUID.fromString(String));
Have a registered implementation of javax.ws.rs.ext.ParamConverterProvider JAX-RS extension SPI that returns a javax.ws.rs.ext.ParamConverter instance capable of a "from string" conversion for the type. or
Be List<T>, Set<T> or SortedSet<T>, where T satisfies 2 or 3 above. The resulting collection is read-only.
The solution using a ParamConverterProvider should work in this case.

#Category in AutoBean

Am totally lost trying to understand the #Category annotation of AutoBean. Can somebody please tell me how exactly it can be used?
I went through the example in wiki as well. My doubt is like this.
Say I am having a proxy interface in the client side which extends entity proxy, and I want to insert a non setter/getter method in that interface, how can I do that?
#ProxyFor( value = CacheStrategy.class )
public interface CacheStrategyProxy extends EntityProxy
{
// setters and getters
CacheStrategyProxy fetchObject(int id);
}
#Category(CacheStrategyProxyCategory.class)
interface MyFactory extends AutoBeanFactory {
AutoBean<CacheStrategyProxy> fetchObject();
}
class CacheStrategyProxyCategory {
public static CacheStrategyProxy fetchObject (AutoBean<CacheStrategyProxy> instance, int id) {
// return data
}
}
Am writing all this in my CacheStrategyProxy file. But I still get the error "Only setters and getters allowed". Pardon me if I have done something silly here. I am totally new to this world.
#Category cannot be used with Request Factory (at least not currently).
Request Factory makes use of AutoBeans (and your proxies will be AutoBean instances) but the AutoBeanFactory (factories actually) is/are internal to the RequestFactory, and you cannot tweak them.