Spring: RequestBody marshalling on POST of data specifying xml namespace - java

I am having a problem marshalling a RequestBody when the parent class has a namespace.
Class:
#XmlRootElement(name = "blah")
public class Test {
private String id;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
XML:
<blah>
<id>23333</id>
</blah>
Code:
#RequestMapping( value = "/blah", method = RequestMethod.POST, consumes = { MediaType.TEXT_XML_VALUE }, produces = { MediaType.TEXT_XML_VALUE})
public String getBlah( #RequestBody Test request ) throws Exception
{
assert(null != request.getId());
return "blah";
}
This works fine. However, if I use #XmlRootElement(name = "blah", namespace="home") on the class, and <blah xmlns="home"> in the request, the Test class constructs, but it's ID value is never set.
I'm at a loss.

Before public void setId method add annotation #XmlElement

Related

Convert enum multiple values to Json in Java SpringBoot

Here I have a Rest Controller
#RequestMapping(value = "/mobileNumber", method = RequestMethod.POST, produces = {
MediaType.APPLICATION_JSON_VALUE })
public ResponseEntity<ResponseBack> sentResponse() {
return new ResponseEntity<ResponseBack>(ResponseBack.LOGIN_SUCCESS, HttpStatus.ACCEPTED);
}
My Enum Class
public enum ResponseBack {
LOGIN_SUCCESS(0, " success"), LOGIN_FAILURE(1, " failure");
private long id;
private final String message;
// Enum constructor
ResponseBack(long id, String message) {
this.id = id;
this.message = message;
}
public long getId() {
return id;
}
public String getMessage() {
return message;
}
}
When I get the response back from the controller I am getting it as
"LOGIN_SUCCESS"
What I require is
{
"id": "0",
"message": "success"
}
How can I deserialize it to Json and send response, is there any annotation for it.
Please help, thanks.
You must use JsonFormat annotation
#JsonFormat(shape = JsonFormat.Shape.OBJECT)
public enum ResponseBack {
...
So you tell that the Json representation of this enum will be the whole object. If you want a specific field to be returned (for example message field) you can annotate the method with JsonValue annotation
#JsonValue
public String getMessage() {
return message;
}

using Swagger #ApiResponse responseContainer not working when code is 400

In Swagger Java API, when I use a responsecontainer="List" (Or "Set") with a code=400, I am not getting the model of the response on Swagger-GUI. I am just getting Array[Object].
Here is the concrete case:
#CrossOrigin
#RestController
#RequestMapping(value = "/api")
#Loggable(prepend = true, trim = false)
public class ConfigResource {
private final ConfigResourceDelegate delegate;
#Inject
public ConfigResource(final ConfigResourceDelegate delegate) {
this.delegate = delegate;
}
#RequestMapping(
value = "/v1/config",
method = PUT,
consumes = APPLICATION_JSON_UTF8_VALUE,
produces = APPLICATION_JSON_UTF8_VALUE
)
#ApiResponses(value = {#ApiResponse(code=202,message = "ACCEPTED" ),
#ApiResponse(code=200,response = Rejection.class, responseContainer
= "Set", message = "BAD_REQUEST"),
#ApiResponse(code=500, message = "INTERNAL_SERVER_ERROR")})
public ResponseEntity<?> putConfig(final #RequestBody ConfigDto
configDto){
return delegate.putConfig(riskConfigDto);
}
}
Here is the Rejection Class:
public class Rejection {
private Long id;
private RejectionDTO rejection;
private String originMessage;
public Rejection() {
}
public Long getId() {
return id;
}
public RejectionDTO getRejection() {
return rejection;
}
public String getOriginMessage() {
return originMessage;
}
public void setId(Long id) {
this.id = id;
}
public void setRejection(RejectionDTO rejection) {
this.rejection = rejection;
}
public void setOriginMessage(String originMessage) {
this.originMessage = originMessage;
}
}
So normally i'am supposed to have this model between [] in the swagger UI. However, I am getting Array[Object]:
See screen capture
To make your example work, you need to change your return value from wildcard, ResponseEntity<?>, to a concrete class, ResponseEntity<List<Rejection>>. Also, you need to change responseContainer to a List from Set.
#RequestMapping(
value = "/v1/config",
method = PUT,
consumes = APPLICATION_JSON_UTF8_VALUE,
produces = APPLICATION_JSON_UTF8_VALUE
)
#ApiResponses(value = {#ApiResponse(code=202,message = "ACCEPTED" ),
#ApiResponse(code=200,response = Rejection.class, responseContainer
= "List", message = "BAD_REQUEST"),
#ApiResponse(code=500, message = "INTERNAL_SERVER_ERROR")})
public ResponseEntity<List<Rejection>> putConfig(final #RequestBody ConfigDto
configDto){
return delegate.putConfig(riskConfigDto);
}

Java Spring REST API Status 400 response on POST / PUT

I built a REST API Service using Java Spring Cloud / Boot. Firstly, I made a simple class connected to a MongoDB and a controller with service that should allow me to add, delete, update and get all the objects. When using POSTMAN these all work, however when I want to add or update an object using redux and fetch API I get a status 400 and "bad request" error. This seems to have something to do with the JSON I'm sending in the body but it is the exact same format of JSON that is working with for example POSTMAN.
My action in Redux. For simplicity / test purposes I added an object at the top in stead of using the object being sent from the page.
var assetObject = {
"vendor" : "why dis no work?",
"name": "wtf",
"version": "231",
"category" : "qsd",
"technology" : "whatever"
}
export function addAsset(access_token, asset) {
return dispatch => {
fetch(constants.SERVER_ADDRESS + '/as/asset/add',
{
method: 'POST',
credentials: 'include',
headers: {
'Authorization': 'Bearer' + access_token,
'Content-Type': 'application/json'
},
body: assetObject
})
.then(res => dispatch({
type: constants.ADD_ASSET,
asset
}))
}
}
Controller code in Java Spring:
#RequestMapping(method = RequestMethod.POST, path = "/add")
public void addAsset(#RequestBody Asset asset) {
assetService.addAsset(asset);
}
Status ok while doing it in postman:
The error I get when using Redux / Fetch API (I only removed the directory structure because it has company name in it):
Have been stuck on this for a while, any help is much appreciated!
EDIT Asset Object:
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
#Document(collection = "assets")
public class Asset {
#Id
private String id;
private String vendor;
private String name;
private String version;
private String category;
private String technology;
public Asset() {
}
public Asset(String id,
String vendor,
String name,
String version,
String category,
String technology) {
this.id = id;
this.vendor = vendor;
this.name = name;
this.version = version;
this.category = category;
this.technology = technology;
}
public String getId() {
return id;
}
public String getVendor() {
return vendor;
}
public String getName() {
return name;
}
public String getVersion() {
return version;
}
public String getCategory() {
return category;
}
public String getTechnology() {
return technology;
}
public void setId(String id) {
this.id = id;
}
public void setVendor(String vendor) {
this.vendor = vendor;
}
public void setName(String name) {
this.name = name;
}
public void setVersion(String version) {
this.version = version;
}
public void setCategory(String category) {
this.category = category;
}
public void setTechnology(String technology) {
this.technology = technology;
}
}
your error message says :
; required request body is missing
i think the error happens when your controller method
trying to form an object from the incoming request.
when you are sending the request you have to set each and every field related to the object.
if you are planning on not setting a property you should mark that field with #JsonIgnore annotation.
you can use #JsonIgnore annotation on the variable which will ignore this property
when forming the object as well as when outputing the object.
use #JsonIgnore annotation on the setter method , which i think you should do now since
you are ignoring the id property when making the request.
#JsonIgnore
public void setId(String id) {
this.id = id;
}
and you can return httpstatus code from the controller method,
so that client knows request was successful
#ResponseBody
public ResponseEntity<String> addAsset(#RequestBody Asset asset) {
return new ResponseEntity<String>("your response here", HttpStatus.OK);
}

Marshalling Java object to XML with JAXB returns unexpected output

I am having issues marshalling a bean into XML using JAXB. I have multiple REST API endpoints and I want to return a uniform response from all the endpoints, like the following:
<response>
<responseHeader> <!-- this will be same for all the end points -->
<status>OK</status>
<stausCode>AB-123<statusCode>
</responseHeader>
<responseBody>
<!-- contains end point specific data, could be differnet-->
</responseBody>
</response>
So what I did is created a generic response DTO:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "response")
public class GenericResponseDto implements Serializable {
#XmlElement(name="responseHeader")
private GenericResponseHeaderDto responseHeader;
#XmlAnyElement(name="responseBody")
private Object responseBody;
public GenericResponseHeaderDto getResponseHeader() {
return responseHeader;
}
public void setResponseHeader(GenericResponseHeaderDto responseHeader) {
this.responseHeader = responseHeader;
}
public Object getResponseBody() {
return responseBody;
}
public void setResponseBody(Object responseBody) {
this.responseBody = responseBody;
}
}
Where the response body field will be replaced by the following object for one of the endpoint responses:
#XmlRootElement(name = "responseBody")
#XmlAccessorType(XmlAccessType.FIELD)
public class Person implements Serializable {
#XmlElement(required = false)
private String phoneNumber;
#XmlElement(required = false)
private Integer personId;
public Integer getPersonId() {
return personId;
}
public void setPersonId(Integer personId) {
this.personId = personId;
}
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
#Override
public String toString() {
return ToStringBuilder.reflectionToString(this);
}
}
Here is my Jersey endpoint:
#POST
#Path("/myAPIFirstEndPoint")
#Produces({MediaType.APPLICATION_XML})
public GenericResponseDto myAPIFirstEndPoint(ABC abc) {
// some work and getting person dto
Person person = someWork.doWork();
GenericResponseDto genericResponseDto = new GenericResponseDto();
// not setting any responseHeader for now, so ignore
genericResponseDto.setResponseBody(row);
return genericResponseDto;
}
But it's not working as expected. The toString() method is being called on the Person object, instead of it being marshalled to XML. I'm getting the following incorrect response:
<?xml version="1.0" encoding="UTF-8" ?>
<response>
<responseBody>
path.to.package.Person#36af3690[phoneNumber=+123456789,personId=-1]
</responseBody>
</response>
Can you please tell me what I'm doing wrong? I am using Jersey and JAXB with Spring.
EDIT:
Introduced generics:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "response")
#XmlSeeAlso({Person.class})
public class GenericResponseDto<T> implements Serializable {
#XmlElement(name="responseHeader")
private GenericResponseHeaderDto responseHeader;
#XmlElement(name="responseBody")
private T responseBody;
public GenericResponseHeaderDto getResponseHeader() {
return responseHeader;
}
public void setResponseHeader(GenericResponseHeaderDto responseHeader) {
this.responseHeader = responseHeader;
}
public T getResponseBody() {
return responseBody;
}
public void setResponseBody(T responseBody) {
this.responseBody = responseBody;
}
}
changed Jersey endpoint as follows:
#POST
#Path("/myAPIFirstEndPoint")
#Produces({MediaType.APPLICATION_XML})
public GenericResponseDto<Person> myAPIFirstEndPoint(ABC abc) {
// some work and getting person dto
Person person = someWork.doWork();
GenericResponseDto<Person> genericResponseDto = new GenericResponseDto<Person>();
// not setting any responseHeader for now, so ignore
genericResponseDto.setResponseBody(row);
return genericResponseDto;
}
Still getting the same response as mentioned above.
Now getting this response, after adding #XmlSeeAlso({Person.class}) in GenericResponseDto
<?xml version="1.0" encoding="UTF-8" ?>
<response>
<responseBody xsi:type="Person">
<phoneNumber>+923454502dd0559</phoneNumber>
<personId>-1</personId>
<token />
</responseBody>
</response>

How do I read attributes using jaxb?

Given this XML:
<response>
<detail Id="123" Length="10" Width="20" Height="30" />
</response>
This is what I have now, but it is not working (I'm getting empty result):
#XmlRootElement(name="response")
public class MyResponse {
List<ResponseDetail> response;
//+getters +setters +constructor
}
public class MyResponseDetail {
Integer Id;
Integer Length;
Integer Width;
Integer Height;
//+getters +setters
}
I'm making a call to a remote service using RestOperations and I want to parse the <detail ..> element. I've tried passing both MyResponse and MyResponseDetail classes to RestOperations but the result is always empty.
What should my object structure look like to match that XML?
You need to annotate your classes like that:
#XmlRootElement
public class Response {
private List<Detail> detail;
public void setDetail(List<Detail> detail) {
this.detail = detail;
}
public List<Detail> getDetail() {
return detail;
}
}
public class Detail {
private String id;
/* add other attributes here */
#XmlAttribute(name = "Id")
public void setId(String id) {
this.id = id;
}
public String getId() {
return id;
}
}

Categories

Resources