Spring 3 and JAXB in Web Services - spring

I'm trying to write a simple web service that automagically serializes and deserializes objects using JAXB:
#XmlRootElement
public class SimpleObject {
private int id;
private String name;
/* ... */
}
#Controller
public class SimpleObjectController {
#RequestMapping("submit",method=RequestMethod.POST)
public String doPost(#RequestBody SimpleObject value) {
return value.toString();
}
}
<?xml version="1.0"?>
<beans ...>
<oxm:jaxb2-marshaller id="marshaller" class="path.to.objects"/>
</beans>
When I actually make the request, however, I get the following:
HTTP Status 415
The server refused this request because the request entity is in a format not
supported by the requested resource for the requested method ().
I get no logs back from Spring, making it hard for me to determine the root cause. Is there a critical step in this process which I'm missing?

Typically this is because of a missing Accept header or Content Type header of "application/xml" in your request. Also if you are using Spring 3.1, you can make your annotation even more explicit this way:
#RequestMapping(value="submit",method=RequestMethod.POST, consumes="application/xml", produces="application/xml")

Related

org.springframework.http.InvalidMediaTypeException: Invalid mime type "XML;charset=ISO-8859-1": does not contain '/'

I am creating a REST API using SpringBoot(API1). which calls another Rest API using RestTemplate(API2).
API2, which I am calling require xml input and gives xml output.
XML output which API 2 sends back has a structure like below
<xml>
<IList>
<IDetails>
<Id>INC123</Id>
</IDetails>
<IDetails>
<Id>INC124</Id>
</IDetails>
</IList>
</xml>
The Pojo Class I have created are below ones:
#Data
#XmlRootElement(name="xml")
public class IResponse implements Serializable{
private static final long serialVersionUID = 1L;
#XmlElement(name="IList")
public IList iList;
}
#Data
#XmlRootElement(name="IList")
public class IList implements Serializable{
#XmlElement(name="IDetails")
public List<IDetails> iDetails;
}
#Data
#XmlRootElement(name="IDetails")
public class IDetails implements Serializable{
#XmlElement(name="Id")
public String id;
}
The call I am doing :
ResponseEntity<IList> response = restTemplate.exchange(urlTemplate, HttpMethod.POST, request, IList.class);
url Template is the API2 that I am calling.
When restTemplate.exchange is executed, I get status code if 200 Ok, along with error Invalid mime type "XML;charset=ISO-8859-1": does not contain '/' . When I debugged the code .I found this is being thrown by responseExtractor.extractData(response) in package org.springframework.web.client; and doExecute method.
The headers I am sending are
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_XML);
headers.add(HttpHeaders.ACCEPT, MediaType.APPLICATION_XML_VALUE);
headers.add(HttpHeaders.ACCEPT_CHARSET, StandardCharsets.UTF_8.name());
The API is getting executed successfully, Reason being backend task that the API does is occurring when I executed my flow, but the response I get is Invalid mime type "XML;charset=ISO-8859-1": does not contain '/'.
Can Anyone help me please.
First, mime type is always has the view type/subtype.
I see you use Spring's HttpHeaders and MediaType. Looks like the class MediaType is not from Spring's package, check this. Possibly, in you 'wrong' imported class MimeType the value of MediaType.APPLICATION_XML is not application/xml but XML.
You can check it manually by setting the value application/xml.
2nd observation: if your headers already have ACCEPT header, it will added (will be at least 2 ACCEPT headers). If you want use one header, use .set instead .add.

how to Enforce request header on all spring web RestController equests

Is there an option to specify a request header once in spring web RestController instead of doing it on every request?
e.q.
#RestController("workflowController")
public class MyClass{
public Value list(#RequestHeader(USER_ID_HEADER_PARAM) String user) {
...some code
}
public Workflow create(#RequestBody Workflow workflow, #RequestHeader(USER_ID_HEADER_PARAM) String user) {
... some code
}
}
the #RequestHeader(USER_ID_HEADER_PARAM) will be repeated in every request.
is there a way to specity it in the #RestCotroller level or the class level?
Thanks
Use some kind of filter class that can be configured to wrap around your requests in your servlets based on the URL path.
Here is info about the generic Servlet API filter API:
https://www.oracle.com/technetwork/java/filters-137243.html
If you're using Spring, there's another way to do it:
https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#filters
https://www.baeldung.com/intercepting-filter-pattern-in-java

Method With #PathVariable In SpringBoot Returns Empty Response

I'm trying to write a method which takes a #PathVariable parameter and redirects user to a jsp file.
#Controller
public class MainController
{
#RequestMapping("/user/{customerId}")
// http://localhost:8080/Test/user/5
public String getCustomerById(#PathVariable("customerId") String customerId, Model model)
{
model.addAttribute("customer_id", customerId);
// this is the user_details.jsp file, I need to show this jsp file to visitor
return "user_details";
}
}
When I try to navigate http://localhost:8080/SpringBlog/user/5 It's showing me an empty response. (Nothing Even In Page Source)
When I looked into Spring output console, it's showing me the following message when I'm trying to navigate :
2017-07-19 13:24:56.191 ERROR 6772 --- [io-8080-exec-75]
o.s.boot.web.support.ErrorPageFilter
Cannot forward to error page for request [/user/5] as the response has already been committed. As a result, the response may have the wrong status code. If your application is running on WebSphere Application Server you may be able to resolve this problem by setting com.ibm.ws.webcontainer.invokeFlushAfterService to false
I've already tried following parameter descriptions as the followings :
#PathVariable(value="customerId") String customerId
#PathVariable(name="customerId") String customerId
#PathVariable("customerId") String customerId
#PathVariable String customerId
None of them worked, always empty response with same error message.
I'm sure that all files are in correct place, in my MainController Class
I have several methods with No Parameters, RequestParams, etc.. all of them working as expected. But if I want to create a RequestMapping with #PathVariable, it always returns empty response and same error message in the output console.
But if I try same approach with #RestController it's working as expected:
#RestController
public class RestApi
{
// http://localhost:8080/Test/api/user/56
// Is Working, Returns Hello 56 As Response
#RequestMapping("api/user/{customerId}")
public String apiTest(#PathVariable("customerId") String customerId)
{
return "Hello "+customerId;
}
}
What am I missing ?
Application Details :
<packaging>war</packaging>
...
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.4.RELEASE</version>
<relativePath/>
<!-- lookup parent from repository -->
</parent>
...
Apache Tomcat/7.0.56
JVM 1.8.0_131-b11
Thanks for your help.
The annotation #RestController automatically adds the #ResponseBody to your methods.
What #ResponseBody does is to bind the outgoing returned value to the HTTP response body using a HttpMessageConverter. If you don't add either the #RestController or #ResponseBody annotation then Spring will try to resolve that to a view, commonly a JSP page.
So in your case Spring is trying to find the view matchin "Hello"+customerId instead of printing out the result of "Hello"+customerId.
So you're using the #PathVariable annotation correctly. :)
You can read more here
Please , check your application.properties file ...
prefix and suffix
spring.mvc.view.prefix: (Where are jsp files) Example /WEB-INF/ or /
spring.mvc.view.suffix: .jsp
If you are using #Controller annotation then you need to add #ResponseBody annotation for binding the outgoing returned value to the HTTP response body. So your code with #Controller should look like:
#Controller
public class MainController
{
#RequestMapping("/user/{customerId}")
#ResponseBody
// http://localhost:8080/Test/user/5
public ModelAndView getCustomerById(#PathVariable("customerId") String customerId, ModelAndView model)
{
model.addAttribute("customer_id", customerId);
// this is the user_details.jsp file, I need to show this jsp file to visitor
model.setViewName("user_details");
return model;
}
}

Validating Mongo Documents in Spring Boot

I'm writing a rest service using spring boot with Jersey and MongoDB starter packages. So I have validation working on top level documents by creating the beans:
#Configuration
public class MongoValidationBeans {
#Bean
public ValidatingMongoEventListener validatingMongoEventListener() {
return new ValidatingMongoEventListener(validator());
}
#Bean
public LocalValidatorFactoryBean validator() {
return new LocalValidatorFactoryBean();
}
}
I have a document:
#Document
public class SomeDocument {
#NotEmpty(message="error message that shows on console")
private Set<NonDocumentObject> referencesToOtherDocuments;
}
With set of embedded objects:
public class NonDocumentObject {
#NotNull(message="can't see this error message")
private ObjectId referenceId;
#NotBlank
private String referenceInfo;
}
The validation beans respect the #NotEmpty annotation on my set of objects, but they do not respect #NotNull or #NotBlank annotations on fields on my NonDocumentObject. How can I get validation to work on the fields of my embedded Set of objects.
EDIT: #Valid fixes the above problem.
Also, when a constraint violation happens on my top level document, I can see the specific message on my console but tomcat returns an http error page with response status 400. How can I instead send a json object with more information about the error? I have a class
public class GenericExceptionMapper implements ExceptionMapper<Throwable> {}
which catches 404, 405, etc exceptions and returns a json object with the appropriate information, but does not catch mongo constraint validations. I think I need to throw exceptions from the mongo validation beans but can't find resources that direct me how to.
I also want to be able to embed other objects into NonDocumentObject with its own validation. Would it be possible?
So the #Valid annotation triggers cascade validation, but I still can't figure out how to catch validation errors with an exception mapper, or some other way to catch validation errors.

Parsing JSON request body with Spring MVC

I am using Spring 4.1 framework for developing webservices. When I return a Java object as response, it is automatically converted to JSON and delivered to client, so I assume that JSON parser is in classpath and it is configured properly. However it fails to convert the request body from JSON into Java object and client is getting a HTTP response of 400.
Here is how the webservice looks like:
public class Details{
public Details(){
}
int code;
int area;
}
#RequestMapping(value = "/api/update/{phoneNumber}", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<String> update(#PathVariable final String phoneNumber, #RequestBody Details details)
Here is how the request looks like:
Method: Post
Content-Type: application/json; charset=utf-8
Body: {"code":0,"area":12}
If I collect the request body as string and parse it manually then it works, so it gets the valid JSON but for some reason it is not parsing it automatically. I have no clue on how to fix it. Please help. Thanks in advance.
You have package-private properties in your Details class, so they are probably not recognised by json-converter.
You have several options:
define them as public (not recommended)
provide getters and setters
if you are using jackson, you can annotate them with #JsonProperty, leaving them package-private
Finally I got the reason for this. I was using inner classes which were not static. Making those static fixed the issue.

Resources