I want to use the object mapper class in java to pick certain parts of an api request object to use in another request.
Request: {"access_instrument":{"id":"12345","additional_attributes":[1123],"instrument_lifecycle_reasons":[4423],"associated_instruments":[123],"links":[]},"types":[],"states":[],"metadata":[]}
I currently have:
ObjectMapper obMapper = new ObjectMapper();
obMapper.registerModule(new JavaTimeModule());
String requestStr1 = obMapper.writeValueAsString(searchCriteria.getAccessInstrument().getId());
String requestStr2 = obMapper.writeValueAsString(searchCriteria.getAccessInstrument().getInstrumentLifecycleReasons());
String requestStr3 = obMapper.writeValueAsString(searchCriteria.getAccessInstrument().getAssociatedInstruments());
Entity<String> requestEntity = Entity.entity(requestStr1+requestStr2+requestStr3, MediaType.APPLICATION_JSON_TYPE);
However I feel this will run into issues with the api validations due to formatting, and adding spacing manually, doesn't seem efficient. Is there a way I can pick apart the data I want from the request body to then send it in the new request?
Note: the requestEntity variable is the request payload that is used in the api call
Related
By inconsistent I mean that variable types can differ depending on the API response. So a named variable could be an Object, a List of Objects, or bizarrely even a String. I do not and cannot control the third-party API I'm consuming.
I'm using restTemplate.exchange(String url, HttpMethod method, HttpEntity<?> requestEntity, Class<T> responseType, Object... uriVariables), and the top-level responseType is consistent. It's in the child (and descendant) objects where the types may differ.
Am I stuck with pivoting to consuming the API response as a String, and do manual parsing? Or is there a way to handle the fact that the variable types might map differently (similar to how GSON supports custom serialisation / deserialisation).
Managed to find a way through this. I did have to read the API response as a String and take it from there. General steps:
restTemplate.exchange into String response body
Setup an ObjectMapper
Configure that to accept single values as arrays, and
empty strings as null objects
Read into the POJO of your choice
Now, this won't be ideal for everyone - in a perfect world you shouldn't have to relax the JSON parsing rules at all. This is all because I'm handling a very inconsistent API.
Rough code example is as-follows (as our internal stack is pretty complex, so I've had to drag bits out from classes here and there):
String exampleEndpoint = Constants.EXAMPLE_ENDPOINT;
ResponseEntity<String> responseEntity = restTemplate.exchange(uri.toString(), HttpMethod.GET, null, String.class);
String stringResponse = responseEntity.getBody();
ExamplePOJO examplePojo = null;
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
mapper.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true);
try {
examplePojo = mapper.readValue(stringResponse, ExamplePOJO.class);
} catch (JsonProcessingException | NullPointerException ne) {
// JsonProcessingException is from readValue, NPE is to catch the string response
// being null in the event you don't want to let it bubble up further
logger.error(ne.getLocalizedMessage());
}
I'd like to unit test my REST endpoint. I'm very new to this, but I was able to write the following code:
HttpPost request = new HttpPost("http://localhost:8080/myrest");
ObjectMapper mapper = new ObjectMapper();
String empJson = mapper.writeValueAsString(clientDto);
StringEntity input = new StringEntity(empJson);
input.setContentType("application/json");
request.setEntity(input);
org.apache.http.HttpResponse httpResponse =
HttpClientBuilder.create().build().execute(request);
clientDto is an instance of a simple POJO with a field of type LocalDateTime. The thing is that my deserializer always gets that date as the following string { (one char only). How do I fix this? If you think that unit testing can be done in a better way, please let me know. I've used Apache dependency but this is not a must.
Using RestAssured library it is very easy to test REST API. Please have a look at this code. One of its pros is that it is self-explanatory.
CreditClass dto = new CreditClass();
dto.setCreditGranted(false);
given()
.contentType(MediaType.APPLICATION_JSON)
.body(dto)
.when().post("localhost:8080/rest-api").then()
.statusCode(200)
.body("creditGranted", equalTo(true));
What if a XML webservice can respond with different xml structures? Eg an <OkResponse> and an <ErrorResponse>, having completely different fields?
ResponseEntity<Response> rsp = restTemplate
.postForEntity(url, new HttpEntity<>(xml, HEADERS), OkResponse.class);
Before sending the request, I don't know which type of response will come back. If I'm using OkResponse.class, I will get a ClassCastException if an ErrorResponse is returned.
How could I handle this?
The autogenerated beans are as follows:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlSeeAlso({
OkResponse.class,
ErrorResponse.class
})
public class AbstractResponse {
}
Use String.class
ResponseEntity<String> rsp = restTemplate
.postForEntity(url, new HttpEntity<>(xml, HEADERS), String.class);
String responseBody = (String)rsp.getBody();
Object response=mapper.readValue(responseBody, Class.forName(responseClass))
Once response body is obtained. make use of service class that you want to map and convert it using jackson mapper .Made use of reflection since the entity passed can be different/dynamic
RestTemplate uses Jackson for JSON serialization, and it supports inherited types though the #JsonTypeInfo annotation. But it requires that all responses have a common 'type' property. If there is no common property that all responses share, then I think you need to use the String approach, and use String.contains() to find a unique property to determine which response type it is.
I have a server that exposes data with the spring-data-rest project and now I am writing services to consume those data and I started with a generic service that will suit all the common needs, one of which is getting the Page object.
I configured my RestTemplate to use the Jackson2HalModule as suggested here.
I've tried a lot of combinations and I was only able to use consume it properly in a non-generic way like this:
PagedResources<Resource<Company>> response2 = restTemplate.exchange(getUrl(), HttpMethod.GET, HttpEntity.EMPTY, new ParameterizedTypeReference<PagedResources<Resource<Company>>>(){}).getBody();
But trying the same code with T didn't work (Resource links were deserialized but content of Resource object was null)
PagedResources<Resource<T>> response3 = restTemplate.exchange(getUrl(), HttpMethod.GET, HttpEntity.EMPTY, new ParameterizedTypeReference<PagedResources<Resource<T>>>(){}).getBody();
Generically I am only able to deserialize the Company data using the following code:
PagedResources<T> response1 = restTemplate.exchange(getUrl(), HttpMethod.GET, HttpEntity.EMPTY, PagedResources.class).getBody();
But this one doesn't deserialize the Resource object so the Company&Links data of what should be the Resource object are stored in a LinkedHashMap instead.
I also tried using the object mapper on the LinkedHashMap with data but I was unsuccessful. It's been a long day so I might be too close to see the correct way of doing this. I'll appreciate any help with this. Thank you.
The question: Is there a way of getting proper generics working in this case?
I'm writing a JSON representation of an object to a Redis instance (via Jesque) but am unclear whether putting a JsonNode object is the right approach. The gist of examples/APIs (e.g. this one for ObjectMapper) is that I should use that if writing to a file, but I'm really looking for an Object I can send to Redis.
Here is what I have, where the JsonNode is represented below by the object payload. This works just fine but was a struggle to figure out so I assume I'm missing the happy path.
final String queueName = "myQueue";
final net.greghaines.jesque.client.Client client = getClient();
final net.greghaines.jesque.Job job = new Job(jobClassName, payload);
client.enqueue(queueName, job);
client.end();
Currently payload is a JsonNode object generated by
final ObjectMapper objectMapper = new ObjectMapper();
final Object jsonNode = objectMapper.valueToTree(this);
Is there a more preferred approach?
An alternative to storing the JsonNode representation of your object is to simply store a String representation:
new ObjectMapper().writeValueAsString(yourObject);
Then, when you retrieve the object, you can always deserialize the String representation to a JsonNode if you need to:
JsonNode actualObj = mapper.readTree(jsonString);
Or to a simple type-safe entity object:
YourEntity entity = mapper.readValue(jsonAsString, YourEntity.class);
All without storing library specific information in Redis.
Hope that helps.
You could use Redisson it has built-in Redis based scheduler and works with Json, Kryo, msgpack and many other codecs. Provides most easier api for Redis power.