Unexpected error using newRequest in FunctionalTests - exception

I don't understand why I have this error.
When I use newRequest, I have a RuntimeException when calling the
makeRequest(request); method.
The exception message is : "play.mvc.results.NotFound : POST /"
But what is odd, is that in the .url, I specify "/dashboard", not
"/" (and of course, the url is well indicated in the routes file for POST requests!)
Thanks for your help.
Here is my test class :
public class DashboardTest extends FunctionalTest {
protected Request ajaxRequest;
#Before
public void _setUp() {
Fixtures.deleteDatabase();
Fixtures.loadModels("fixtures/accounts.yml");
ajaxRequest = newRequest();
//ajaxRequest.headers.put("X-Requested-With", new Header("X-
Requested-With", "XMLHttpRequest"));
ajaxRequest.method = "POST";
ajaxRequest.url = "/dashboard";
}
#Test
public void testAuthenticateWithValidDataAjax() {
ajaxRequest.params.put("email", "john.sm...#gmail.com");
Response response = makeRequest(ajaxRequest);
assertIsOk(response);
assertContentType("application/json", response);
}
}

Looking at the API documentation, the .url specifies that it needs the Full URL. What I would suggest you do instead, is to use the .action instead.
The Javadoc for the this is
Full action (ex: Application.index)
or specify the full URL, which would include
http://localhost:9000/dashboard
Your final option, if you are still having problems, is to use the createRequest method on the Http.Request object, which gives you complete control over the Request object you are creating. The signature looks like this
createRequest
public static Http.Request createRequest(java.lang.String _remoteAddress,
java.lang.String _method,
java.lang.String _path,
java.lang.String _querystring,
java.lang.String _contentType,
java.io.InputStream _body,
java.lang.String _url,
java.lang.String _host,
boolean _isLoopback,
int _port,
java.lang.String _domain,
boolean _secure,
java.util.Map<java.lang.String,Http.Header> _headers,
java.util.Map<java.lang.String,Http.Cookie> _cookies)

Related

Is it possible to get an InvalidFormatException not as a HttpMessageNotReadableException in Spring when processing JSON?

I have a simple RestController:
#RestController
public class MailboxController{
#RequestMapping(value = "/mailbox/{id}", method = RequestMethod.PUT)
public void createMailbox(#PathVariable #NotNull String mailboxID, #Validated #RequestBody Mailbox mailbox){
//do something with Mailbox here
}
}
The Mailbox class looks as follows:
#Validated
public class Mailbox{
#JsonProperty("email")
#EmailValidator //some validation of EMail String
public String email;
#JsonProperty("type")
public Type type; //Type is an enum
}
If I post a valid JSON-String where the value of type is not listed in the enumeration then I get a 400 (Bad Request) error. Internally a HttpMessageNotReadableException with a InvalidFormatException gets thrown. If I post a JSON-String where the email doesn't get accepted by the EmailValidator I get a 400 (Bad Request) error as well (from a MethodArgumentNotValidException). In both cases I would expect a 422 since the JSON is well formatted but the content is semantically wrong.
Either way I try to handle both cases similary and wonder if there is a way to redirect the InvalidFormatException in a way that I get MethodArgumentNotValidException when the given type is not part of the Type enumeration.
Currently I have a ResponseEntityExceptionHandler with one method that catchest the HttpMessageNotReadableException and builds the ResponseEntity depending on the causing exception and a method that handles the MethodArgumentNotValidException. I would prefer it if the InvalidFormatException could be handled in the method where I handle the MethodArgumentNotValidException as well.

Spring Boot JSONP with MappingJacksonValue response and strict MIME type error

I've been reading a lot about JSONP support with Spring 4, but I still lack a clean explanation to make it work with the right media-type (under chrome)
1) I added the JsonpAdvice cfr Jackson JSONP Support
#ControllerAdvice
public class JsonpAdvice extends AbstractJsonpResponseBodyAdvice {
public JsonpAdvice() {
super("callback");
}
}
2) My controller is wrapping the response with MappingJacksonValue*
#RequestMapping(value = '/api/test', method = RequestMethod.GET)
#ResponseBody
public Object test(HttpServletRequest request) {
List<String> result = new ArrayList<String>();
result.add("hello");
result.add("world");
if(request.getParameter('callback')){
MappingJacksonValue value = new MappingJacksonValue(result)
value.setJsonpFunction(request.getParameter('callback'))
return value
}
return result
}
not sure the MappingJacksonValue is necessary or if MappingJackson2HttpMessageConverter will take care of that?
3) I added explicit media-types in application.yml:
spring:
profiles.active: development
jackson.property-naming-strategy: SNAKE_CASE
mvc:
media-types:
json: 'application/json'
xml: 'application/xml'
jsonp: 'application/javascript'
However I still get the following error in Chrome:
Refused to execute script from 'https://example.com/api/test?callback=jQuery22406993800323428312_1481922214995&_=1481922214996'
because its MIME type ('application/json') is not executable, and strict MIME type checking is enabled.
Any step missing? or too much configuration?
After debugging my JsonpAdvice.groovy, I found out that AbstractJsonpResponseBodyAdvice is expecting a list of String: private final String[] jsonpQueryParamNames;
My initial code was using a simple String. Here is the fix:
#ControllerAdvice
public class JsonpAdvice extends AbstractJsonpResponseBodyAdvice {
public JsonpAdvice() {
super(["callback"])
}
}

Get json content of request and response on annotated Spring Controller

I want to build a library that will save the Json content of request and response on annotated Spring controller.
So i've build my own annotation #Foo and put it on some controllers:
#Foo
#RequestMapping(method = RequestMethod.POST, value = "/doSomeThing", produces = {
MediaType.APPLICATION_JSON_VALUE, MediaType.TEXT_XML_VALUE,
MediaType.APPLICATION_XML_VALUE})
public ResponseEntity<T> doSomething(/*some parameters*/) {
T t = doSomeJob(T.class);
return new ResponseEntity<T>(t, HttpStatus.OK);
}
I have no guarantee that request and response are in Contrellor's parameters!
And i'm catching the call on any Controller having that annotation within an #AfterReturning AOP pointcut.
#Component
#Aspect
public class XYInterceptor
#AfterReturning(
pointcut = "execution(#my.annotation.Foo)")
public void doSomethingWithJsonContent(JoinPoint joinPoint) throws Throwable {
//How can i get json value of request and response here?
}
How can I get request and response content formatted in json (such as it is send/returned to the client) ?
Thanx for your help!
Well, you need request and response somehow accessible from your controller method, either via an injected class member, method parameter or method return value. It has got to be somewhere. Because you did not explain where you intend to get it from, I can just post a general answer showing how to determine method arguments and return value from an #AfterReturning advice. If you update the question with more detailed information, I can also update the answer accordingly.
My pointcut (the commented-out one also works, choose your favourite one) binds the return value to a parameter and just assumes that both request and response are of String type. Feel free to replace by your favourite. Furthermore, you can bind a parameter from your intercepted method (no matter where it is in the signature) to a typed advice method parameter if you know that the parameter exists and also know its (super) type. This way you can get rid of the slow and ugly loop over getArgs().
//#AfterReturning(pointcut = "execution(#my.annotation.Foo * *(..))", returning = "response")
#AfterReturning(pointcut = "#annotation(my.annotation.Foo)", returning = "response")
public void interceptRequest(String response, JoinPoint thisJoinPoint) {
System.out.println(thisJoinPoint);
for (Object arg : thisJoinPoint.getArgs()) {
if (arg instanceof String)
System.out.println(" request = " + arg);
}
System.out.println(" response = " + response);
}

Dropwizard, Jersey, unit testing - GET throws ConstraintViolationException: The request entity was empty at

I have Dropwizard application and I am writing unit tests for it. I am following Dropwizard's documentation to do so : http://dropwizard.readthedocs.org/en/latest/manual/testing.html
What I am missing is how can I add parameter to my test which invokes GET method?
Here in the documentation :
assertThat(resources.client().resource("/person/blah").get(Person.class))
.isEqualTo(person);
What if my get method has a parameter?
In Jersey's WebResource there are:
#Override
public <T> T get(Class<T> c) throws UniformInterfaceException, ClientHandlerException {
return handle(c, build("GET"));
}
#Override
public <T> T get(GenericType<T> gt) throws UniformInterfaceException, ClientHandlerException {
return handle(gt, build("GET"));
}
Query parameters are part of the resource URI. You can embed them in the string:
assertThat(resources.client().resource("/person/blah?a=b").get(Person.class)).isEqualTo(person);
Or you can build the URI dynamically:
URI resourceUri = UriBuilder.fromPath("/person/blah").queryParam("a", "b").build();
assertThat(resources.client().resource(resourceUri).get(Person.class)).isEqualTo(person);

Exception with REST implementation with jersey

I am building a REST service with jersey and I am stuck with a weird exception.
I want to hit a REST uri similar to:
http://localhost:9889/rest/Users/{userid}
the content to be sent with the request is in JSON similar to:
{
"attr1":"name",
"attr2":"age"
}
The endpoint url code is as shwon below:
#Path("/rest/Users")
class Users
{
#GET
#Produces(MediaType.TEXT_PLAIN)
#Path("/{userId}")
#Consumes(MediaType.APPLICATION_JSON)
public String getUserInfoQuery(
QueryDoc reqJSON,
#PathParam("userId") String userId,
#HeaderParam("Session-Token") String sessionId,
#HeaderParam("Authorization") String authToken)
)
{
.
.
.
.
}
}
And QueryDoc resource looks like this:
#XmlRootElement
#XmlAccessorType(XmlAccessType.NONE)
public class QueryDoc
{
#XmlElement(name = "attr1")
private String attr1;
#XmlElement(name = "attr2")
private String attr2;
//getters and setters
.
.
.
.
}
When I am starting the server, an exception is thrown
com.sun.jersey.api.container.ContainerException: Fatal issues found at
class com.test.Users. See logs for more details.
at com.sun.jersey.server.impl.application.WebApplicationImpl.newResourceClass(WebApplicationIm....
I could find this exception here http://www.skybert.net/java/jersey/
and as mentioned in this link..the reason is
public String getUserInfoQuery(
QueryDoc reqJSON,
reqJSON is not being annotated. If I annotate it with some annotation the exception is not thrown when server is started but in this case url response is meaningless. If i remove this parameter the url works but it doesn't consume the request JSON.
How can I make it work where I want to consume JSON content of the request as well as HeaderParams and PathParams
Is your getUserInfoQuery() method annotated with #GET annotation? If so, it is mapped to HTTP GET request. You cannot send entity in HTTP GET, so the unannotated parameter does not make sense (as Jersey maps entity to the unannotated param, but as said, in case of GET there is no entity).
Change your method getUserInfoQuery() to #PUT. In the QueryDoc class remove all annotations except #XmlRootElement. Since the attribute name you pass in the request body is same as the those in QueryDoc #XmlElement is not required. Moreover #XmlElement should be given to ge getter method.This is a good article on ReST with Jersey.
Try this:
I had the same exception with no additional details on Jersey's 'newResourceClass' method;
after hours of debugging, I realized it happened due to ambiguous URIs.
Check your URIs and eliminate any possible duplicates, such as this one:
#Path("/users")
#GET
#Produces(MediaType.APPLICATION_JSON)
public List<String> getUsers() {
...
}
#Path("/users") // BAD
#GET
#Produces(MediaType.APPLICATION_JSON)
public String getUserById(#QueryParam("userId") String userId) {
...
}