Apache Camel sending marshalled data - java

I'm trying to send marshalled data through a Camel route. I've checked a few tutorials but can't get it to work and receive a RuntimeException.
What I want to accomplish:
Extract the body of the message.
Create a POJO with content and title fields.
Marshall the POJO and send it further along the route.
#Override
public void configure() {
from("Foo")
.bean(TestMessageTransformer.class, "testMessageTransform")
(1).marshal()
.to("Bar")
public class TestMessage {
private String content;
private String title;
public TestMessage(String content, String title) {
this.content = content;
this.title = title;
}
}
public class TestMessageTransformer {
#Bean("testMessageTransform")
public TestMessage transform(String message) {
return new TestMessage(message, "title");
}
}
(1) I've tried using marshal().jaxb(), marshal() with JacksonXMLDataFormat but no dice.

What exactly is the exception you get?
You may need to add public getters to TestMessage for the marshaller to get the fields.

Related

How can I set an optional RequestBody field without it being deleted when I make the call?

I have a small program in spring-boot which through a get call having a #RequestBody returns me a message with all the specifications (in my case of cars)
public class CarsRequest implements Serializable {
private String name;
private String plate ;
private String price;
}
I would like to be able to make sure that if a field is set to null, it can still find the relative message with the other fields having a value, in my case, I wanted to put that the "name" field is optional in the RequestBody, is it possible to do this? I tried setting
public CarsResponse getCars(#RequestBody (required = false) CarsRequest request) throws IOException {
//some code
}
but then when I go to do the get it completely deletes the null field at the time of the get and therefore fails to do it
Just remove the #RequestBody annotation from the function and keep it as it is
public CarsResponse getCars(CarsRequest request) throws IOException {
//some code
}
Now all fields will be converted into query params and all will be optional, because query param by convention are optional
public class CarsRequest implements Serializable {
private String name;
private String plate ;
private String price;
}
And call like this
GET /someEndpoint?name=<value>&plate=null
But still if you want to make some params mandatory, then use javax.annotations or apply validation yourself.
EDIT: As asked in comment, if you are accepting JSON as parameter body then you can do one thing, you can accept it as String and then convert json to object inside function body
public CarsResponse getCars(#RequestParam(required = false) String request) throws IOException {
ObjectMapper mapper = new ObjectMapper();
CarRequest request = mapper.readValue(request,CarRequest.class);
// other code
}
and call it something like this
GET /someEndpoint?request="{ \"name\" : null, \"plate\": \"someValue\" }"
EDIT 2:
You can do one more thing if you want to keep sending json and have it transformed into object, you can declare a binder something like this
// Some controller class
class SomeController {
#Autowired
ObjectMapper mapper;
// Ommited methods here
#GetMapping("/carRequest")
public ResponseEntity<String> testBinder(#RequestParam CarRequest request) {
return ResponseEntity.ok("{\"success\": \"" + request.name+ "\"}");
}
#InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(CarRequest.class, new CarRequestEditor(mapper));
}
static class CarRequestEditor extends PropertyEditorSupport {
private ObjectMapper objectMapper;
public CarRequestEditor(ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
}
#Override
public void setAsText(String text) throws IllegalArgumentException
{
if (StringUtils.isEmpty(text)) {
setValue(new CarRequest());
} else {
try {
setValue(objectMapper.readValue(text, CarRequest.class));
} catch (JsonProcessingException e) {
throw new IllegalArgumentException(e);
}
}
}
}
}
Please note that the client need to send the json URL encoded like this
http://localhost:8180/carRequest?request=%7B%22name%22%3"test"%7D
Hi you are using #RequestBody (required = false) CarsRequest
that means your CarsRequest object itself is optional
rather than you can use
#NotEmpty
private String plate ;
#NotEmpty
private String price;
You can make a single field optional by making it an Optional, in your case Optional<String>. If the field does not appear in the request body, then the Optional will be empty.
public class CarsRequest implements Serializable {
private String name;
private String plate;
private Optional<String> price;
}

Handling invalid http request parameters API Restful

I created a program that communicates through http requests. I use Postman to send requests. When I make a registration, I invoke the API method. If this method throws some exceptions, I manage it with "HandlerMapping" which catches the exception and sends a personalized message about it.
HandlerMapping class:
#Provider
public class HandlerMapper implements ExceptionMapper<InputValidationException>{
#Override
public Response toResponse(InputValidationException exception) {
return Response.status(exception.getStatus().getStatusCode(), exception.getMessage()).build();
}
}
InputValidationException:
public class InputValidationException extends Exception{
private String errorMessage;
private Response.Status status;
#JsonbCreator
public InputValidationException (#JsonbProperty("message") String message, #JsonbProperty("status") Response.Status status) {
this.errorMessage = "Invalid param entered: " + message;
this.status = status;
}
.........
}
Now when it throws an exception from the API method it works and a customer message is sent as I would like. But if I send a message with the wrong param (for example with the name null), a custom response error is not created as I do with the api method, but the default message is created with 500 Server Error. How can I make a general class to handle errors in a personalized way?
Client Client
public class Client {
private String surname;
private String name;
private String city_of_birth;
.... another parameters ....
#JsonbCreator
public Cliente(#JsonbProperty("surname") String surname, #JsonbProperty("name") String name, #JsonbProperty("city_of_birth") String city_of_birth) throws InputValidationException {
paramValidation(surname, name, city_of_birth, ......... );
this.surname= surname;
this.name= name;
this.city_of_birth= city_of_birth;
.... another parameters ....
}
private void paramValidation(String surname, String name, String city_of_birth) throws InputValidationException{
if( surname == null || surname.isBlank() ){
throw new InputValidationException("surname", Response.Status.METHOD_NOT_ALLOWED);
}
.... other parameter controls ....
}
}
API class
#Path("homeBanking/client/signup")
public class Registration {
private DaoClient daoC = new DaoClient();
#POST
#Produces(MediaType.APPLICATION_JSON)
public Response createClient(Client client) throws InputValidationException {
daoC.insert(client);
return Response.ok().build();
}
}
I think in your context the solution is creating an Exception Mapper to convert the exception message into a JSON object, following this structure: https://docs.jboss.org/resteasy/docs/3.0.6.Final/userguide/html/ExceptionHandling.html
Using the Spring Framework, you can use the ControllerAdvice to create your own error messages. See this article: https://www.baeldung.com/exception-handling-for-rest-with-spring
I hope I've helped!

Gson deserializes as null a ciphered string [duplicate]

This question already has an answer here:
Spring POST receives object with null values
(1 answer)
Closed 3 years ago.
I have an Android app contacting a REST API developed with Spring. The app serializes well an object but the Spring application parses every field as null when they aren't null. What can be wrong? what shall I do?
This is the REST API method signature: cambioPassword(#RequestHeader("Authorization") String header, PasswordChange userData)
Note: both the app and the API uses Gson (I'm not using Jackson as default in the Spring application)
I've tried every kind of constructor and I've changed the visibility of the Java class fields
public class PasswordChange {
private String name;
private String currentPassword; // Ciphered field
private String newPassword; // Ciphered field
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCurrentPassword() {
return currentPassword;
}
public void setCurrentPassword(String currentPassword) {
this.currentPassword= currentPassword;
}
public String getNewPassword() {
return newPassword;
}
public void setNewPassword(String newPassword) {
this.newPassword = newPassword;
}
}
The server should be able to deserialize the PasswordChange class and the fields should not be null as they aren't in the original sent JSON.
Could it be that you are missing the #RequestBody annotation, I expect it to look like:
#PostMapping("/cambio")
cambioPassword(#RequestHeader("Authorization") String header, #RequestBody PasswordChange userData){
...
}
See https://www.baeldung.com/spring-request-response-body

using one POJO class for different xml responses

When I call rest service I get different xml responses, with different xml root element. I would like to know, are there any opportunities to unmarshal these xmls to one pojo class.
For example, I have a class RecordingCreated.
#XmlRootElement(name = "recordingCreated")
public class RecordingCreated {
private String nodeID;
private String cameraID;
private String recPath;
private String recordingStatus;
public String getNodeID() {
return nodeID;
}
#XmlElement
public void setNodeID(String nodeID) {
this.nodeID = nodeID;
}
public String getCameraID() {
return cameraID;
}
#XmlElement
public void setCameraID(String cameraID) {
this.cameraID = cameraID;
}
public String getRecPath() {
return recPath;
}
#XmlElement
public void setRecPath(String recPath) {
this.recPath = recPath;
}
public String getRecordingStatus() {
return recordingStatus;
}
#XmlElement
public void setRecordingStatus(String recordingStatus) {
this.recordingStatus = recordingStatus;
}
}
After calling rest service I can get xml response in the form of
<recordingCreated>
<nodeID>"111</nodeID>
<cameraID>222</cameraID>\
<recordingID>333</recordingID>\
<recPath>rec</recPath>
<recordingStatus>recorded</recordingStatus>
</recordingCreated>
And in the form of
<error>
<code>444</code>
<description>broker: access denied</description>
</error>
When I got first xml resposne, JAXB unmarshal good
JAXBContext jaxbContext = JAXBContext.newInstance(RecordingCreated.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
RecordingCreated recordingCreated = (RecordingCreated) jaxbUnmarshaller.unmarshal(inputStream);
But when I got second response, of course, I got an error, like this
javax.xml.bind.UnmarshalException: unexpected element (uri:"",
local:"error"). Expected elements are <{}recordingCreated>]]
Question: Is there any opportunity having one class unmarshal two various xml responses with different root elements?
Try creating two different sub classes for your two different responses with their corresponding roots.
You can have the current class as posted as the parent for both of them and depending on the response you would get, call the required class.

Returning error list in jersey rest service

In our project we are using rest service(Jersey). In one of the requirement I would like to return a list of missing mandatory parameters back to the client.
Right now I am using exception mapper which can return a single error message,
public class MandatoryParameterMissingException extends RuntimeException {
private static final long serialVersionUID = 1L;
public MandatoryParameterMissingException(String message) {
super(message);
}
public class MandatoryParamMissingExceptionMapper implements ExceptionMapper<MandatoryParameterMissingException> {
#Override
public Response toResponse(MandatoryParameterMissingException ex) {
ErrorMessage errorMessage = new ErrorMessage(ex.getMessage(), 404, "Document source:todo");
return Response.status(Status.NOT_FOUND)
.entity(errorMessage)
.build();
}
private String errorMessage;
private int errorCode;
private String documentation;
public ErrorMessage() {
}
public ErrorMessage(String errorMessage, int errorCode, String documentation) {
super();
this.errorMessage = errorMessage;
this.errorCode = errorCode;
this.documentation = documentation;
}
..getter setters
If I find any missing mandatory params, right now I am doing something like,
if (emailID == null) {
throw new MandatoryParameterMissingException("Email id is missing");
}
Could some one please suggest What is the best way to enhance this to take a list of error messages and pass it back to the client?
For this issue i created a class called ValidationException. A ValidationException contains a list of ValidationError.
There are different kind of ValidationError, for example OutOfRangeError, MandatoryParameterError and whatever you need. A ValidationError always contains specific attributes (all what the client needs to create a meaningful messagetext for the user) => A MandatoryParameterError just the name of the field, an OutOfRangeError the name of the field and the allowed range.
On serverside there are validators (in a common package, so the client could do the validation itself)... the validators are creating ValidationErrors during the validation of your data. If there are validation errors, a ValidationException is thrown. That's it. I can give you some codesnippets...

Categories

Resources