Print Spring Http Response with log4j to console - json

How can I configure log4j.properties to automatically pretty print the servlet response body(json) to eclipse/terminal console (wire to DEBUG).
This is a Spring(4.3.3) Rest project which produces JSON response. Have jackson-databind(2.5.0) in pom.xml, to convert a model object to json string.
Controller
#RestController
public class ControllerClass {
public final static Logger logger = Logger.getLogger(ControllerClass.class);
#Postmapping("link")
ResponseModel method (#RequestBody ....){
ResponseModel model ;
// other code
return model;
}
}
log4j.properties (log4j 1.2.17)
log4j.rootCategory=INFO, ERROR, stdout, DEBUG
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %t %c{2}:%L - %m%n
Need to wire HTTP response to log4j DEBUG so that the response can be automatically printed ( not by calling logger.debug() )
Note : There is a filter which extends UsernamePasswordAuthenticationFilter as part of Spring security in my project. If no other option, is it good way to put command to print Response body after chain.doFilter()?

Related

Spring Boot ExceptionHandler is returning XML and not JSON

My whole API generates JSON without any problem, but as soon as an exception is thrown, the controller decides to stringy the object to XML... why?
My controller looks like this:
#RestController
public class Controller{
#ResponseBody
#ExceptionHandler({ IllegalArgumentException.class, MissingServletRequestParameterException.class})
#ResponseStatus(HttpStatus.BAD_REQUEST)
public Map<String, Object> invalid(Exception ex){
return new ObjectResponseBuilder().add("message", ex.getMessage()).get();
}
}
However this is the response I get:
<Map>
<message>Required request parameter 'min' for method parameter type Long is not present</message>
</Map>
I'm making the request directly from the browser, so no header is set... just like for all the others endpoints (that are returning JSON instead)

spring boot return escaped json

my code
#GetMapping(value = {"/metadata"}, produces = MediaType.APPLICATION_JSON_VALUE)
#ResponseStatus(HttpStatus.OK)
#ResponseBody
public String getMetadata() {
return dppService.getMetadata();
}
the method getMetadata will just return a json string. it just read data from the json file, and it is in another library can not be changed.
But when call this api, i got the follow reponse:
"{\"Namespace\":\"com.xxx\"...
the json string was escaped.
expected:
"{"Namespace":"com.xxx"...
How could i make it return the right json? BTW, our other services also return a json string in the controller, but their response will not be escaped which is so confused for me.
You could do this two ways:
From what I could understand you are having this issues because you might be returning the json as a string from from the service method dppService.getMetadata() by converting it manually to a string. If so , change that and instead return a POJO class from the service method as well as the controller, spring default jackson converter should automatically convert it to a json when the request is served. (I would suggest you go with this approach)
Another approach (the hacky less desirable one) if you still want to keep returning a string then you could configure the StringMessageConverter like below to accept json:
#Override
public void configureMessageConverters(
List<HttpMessageConverter<?>> converters) {
StringHttpMessageConverter stringConverter = new StringHttpMessageConverter(
Charset.forName("UTF-8"));
stringConverter.setSupportedMediaTypes(Arrays.asList( //
MediaType.TEXT_PLAIN, //
MediaType.TEXT_HTML, //
MediaType.APPLICATION_JSON));
converters.add(stringConverter);
}
root cause:
There is a configuration file in the project:
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(new MappingJackson2HttpMessageConverter(jacksonBuilder().build()));
converters.stream()
.filter(converter -> converter instanceof MappingJackson2HttpMessageConverter)
.findFirst()
.ifPresent(converter -> ((MappingJackson2HttpMessageConverter) converter).setDefaultCharset(UTF_8));
}
This configuration overrite the defualt jackson behavior. There are two ways to solve this issue:
1.Remove this configuration, then it will be the default behavior
2.Add the StringHttpMessageConverter in this configuration, see Ananthapadmanabhan's option2

No Suitable MessageConverter

I have a spring boot application and am testing integration test. My REST service produces JSON and I can confirm it when testing it in postman.
But when I make a getForObject call by restTemplate:
#Test
public void testGetObject() {
Pet pet = restTemplate.getForObject("http://localhost:9000/pets/10000", User.class, Collections.emptyMap());
assertThat(pet.getName(), is("Bobby"));
}
It fails with following error:
Could not extract response: no suitable HttpMessageConverter found for response type [class petstore.entity.User] and content type [text/html;charset=utf-8]
I read lots of posts in stackoverflow, and having that restTempalte itself has MappingJackson2HttpMessageConverter as one of default converters which has JSON as default media type then I should not get this error.
Is there anything I am missing here?
Well, the message is pretty indicative - you're getting text/html as a response type, make your endpoint return application/json. If you're using Spring MVC then you can do it by adding the produces parameter to the annotation:
#RequestMapping(value = "/pets/{id}", method = RequestMethod.GET, produces = "application/json")
Or, if you're using Jersey, add this annotation to your method:
#Produces("application/json")

how to store JSON into POJO using Jackson

I am developing a module where i am using rest service to get data. i am not getting how to store JSON using Jackson and store it which has Queryparam also. Any help is really appreciated as I am new to this.I am trying to do server side filtering in extjs infinte grid which is sending the below request to rest service.
When the page load first time, it sends:
http://myhost/mycontext/rest/populateGrid?_dc=9999999999999&page=1&start=0&limit=500
When you select filter on name and place, it sends:
http://myhost/mycontext/rest/populateGrid?_dc=9999999999999&filter=[{"type":"string","value":"Tom","field":"name"},{"type":"string","value":"London","field":"Location"}]&page=1&start=0&limit=500
I am trying to save this in POJO and then sending this to database to retrieve data. For this on rest side I have written something like this:
#Provider
#Path("/rest")
public interface restAccessPoint {
#GET
#Path("/populateGrid")
#Produces({MediaType.APPLICATION_JSON})
public Response getallGridData(FilterJsonToJava filterparam,#QueryParam("page") String page,#QueryParam("start") String start,#QueryParam("limit") String limit);
}
public class FilterJsonToJava {
#JsonProperty(value ="filter")
private List<Filter> data;
.. getter and setter below
}
public class Filter {
#JsonProperty("type")
private String type;
#JsonProperty("value")
private String value;
#JsonProperty("field")
private String field;
...getter and setters below
}
I am getting the below error:
The following warnings have been detected with resource and/or provider classes: WARNING: A HTTP GET method, public abstract javax.ws.rs.core.Response com.xx.xx.xx.xxxxx (com.xx.xx.xx.xx.json.FilterJsonToJava ,java.lang.String,java.lang.String,java.lang.String), should not consume any entity.
com.xx.xx.xx.xx.json.FilterJsonToJava, and Java type class com.xx.xx.xx.FilterJsonToJava, and MIME media type application/octet-stream was not found
[11/6/13 17:46:54:065] 0000001c ContainerRequ E The registered message body readers compatible with the MIME media type are:
application/octet-stream
com.sun.jersey.core.impl.provider.entity.ByteArrayProvider com.sun.jersey.core.impl.provider.entity.FileProvider com.sun.jersey.core.impl.provider.entity.InputStreamProvider com.sun.jersey.core.impl.provider.entity.DataSourceProvider com.sun.jersey.core.impl.provider.entity.RenderedImageProvider */* -> com.sun.jersey.core.impl.provider.entity.FormProvider ...
You should try to do it this way:
Response getallGridData(#QueryParam("filter") String filterparam, ...) {
ObjectMapper mapper = new ObjectMapper();
Filter yourObject = mapper.readValue(filterparam, Filter.class);
}
This is the way, because your payload is in the query parameter. The object injected as it is with POST requests when there is a payload.

Why does my response not get zipped when using GZIPContentEncodingFilter

I have a REST method where I want to output gziped content. I have added
<init-param>
<param-name>com.sun.jersey.spi.container.ContainerResponseFilters</param-name>
<param-value>com.sun.jersey.api.container.filter.GZIPContentEncodingFilter</param-value>
</init-param>
To the servlet in web.xml
I can see that the code goes thru the GZIPContentEncodingFilter class by debugging but output does not get the .gzip prefix and content is not compressed, instead it is normal json. I am using Jersey 1.14.
Method looks like:
#GET
#Path("/fundlight")
#Produces(MediaType.APPLICATION_JSON)
public Response getFundLightList() {
StopWatch watch = new StopWatch();
watch.start();
Collection<Object> objectResults = null;
objectResults = getCacheMap("FundLight").values();
List<FundLight> fundLightList = new ArrayList(objectResults);
watch.stop();
GenericEntity<List<FundLight>> entity = new GenericEntity<List<FundLight>>(fundLightList) {
};
ResponseBuilder builder = Response.ok(entity);
return builder.build();
}
I think it depends on the client request header parameters.
If the request contains an Accept-Encoding header containing "gzip" then the response entity (if any) is compressed using gzip and a Content-Encoding header of "gzip" is added to the response.
See:
http://jersey.java.net/nonav/apidocs/latest/jersey/com/sun/jersey/api/container/filter/GZIPContentEncodingFilter.html
The easiest approach is to register GZIPEncoder and EncodingFilter:
public class MyApplication extends Application {
#Override
public Set<Class<?>> getClasses() {
final Set<Class<?>> classes = new HashSet<>();
classes.add(GZipEncoder.class); // this allows gzipped requests and responses
classes.add(EncodingFilter.class); // this enables any registered encoders
return classes;
}
}
Now your server side can process requests with "Content-Encoding:gzip" and respond gzipped when the client request's header had a "Accept-Encoding:gzip".
You could also tell your tomcat / apache / whatever to do response zipping by configuration. Eg. compression="on" in your server.xml's Connectors (Tomcat 7).