Following "_links" from an Object the return Json object is empty. I suppose this is because of the lack of automatic lazy fetching in SDN.
Is there an easy way to tell SDR to fetch objects before returning them?
Example:
.../questions/1131 returns the following JSON:
{
//...
"_links" : {
"self" : {
"href" : "http://localhost:8080/api/questions/1131"
},
"askedBy" : {
"href" : "http://localhost:8080/api/questions/1131/askedBy"
}
//...
}
}
Clicking on .../questions/1131/askedBy should return a User, but it returns a User object, where all the properties are null, except the links, which are correct.
How can I tell SDR to fetch these embedded objects before converting them to JSON?
It feels a bit hackish, but I have found a working solution.
#Bean
#Transactional
public ResourceProcessor<Resource> fetchProcessor() {
return new ResourceProcessor<Resource>() {
#Autowired
Neo4jTemplate template;
#Override
public Resource process(Resource resource) {
final Object content = resource.getContent();
if (content != null) {
template.fetch(content);
}
return resource;
}
};
}
Also, I think it is a bit overkill, as it calls template.fetch() even if the object is already populated.
A better idea, anyone?
Related
I am creating a client for the following format of JSON -
{
"results": [
{
"Product": "K265113",
"Language": "EN",
"LongText": "FIXTURE,INTERIOR,WALL"
}
]
}
The JSON always contains "results" field which is an array of a single element (it will always be a single element in this array). I just need LongText field from the JSON and nothing else. I am using Spring RESTTemplate.
I know that it works if I create two DTOs like -
public class ParentDTO
{
private List<ChildDTO> results;
public List<ChildDTO> getResults()
{
return results;
}
public void setResults(List<ChildDTO> results)
{
this.results = results;
}
}
public class ChildDTO
{
private String longText;
public String getLongText()
{
return longText;
}
#JsonProperty("LongText")
public void setLongText(String longText)
{
this.longText = longText;
}
}
But is there any way to read longText by creating a single DTO as the parent DTO is not having any useful field as I know there will always but just one element in the results array.
The reason you need only single DTO could be that you want only single class to perform this task. You can achieve that using ChildDTO as inner class which will make it more readable and maintainable.
The other way is to not parse the spring template response into DTOs instead use JSONNode class of Jackson databind API.
JsonNode root = objectMapper.readTree(response.getBody());
You can find more information at
https://fasterxml.github.io/jackson-databind/javadoc/2.8/com/fasterxml/jackson/databind/JsonNode.html
You can traverse down the tree and could retrieve the value of the attribute directly without any DTOs.
I using postman and spring boot. In spring boot i using code look like :
public PersistableCategory createCategory(#RequestBody PersistableCategory persistableCategory, MerchantStore store, HttpServletRequest httpRequest) {
MerchantStore merchantStore = (MerchantStore) httpRequest.getAttribute("MERCHANT_STORE");
return categoryService.saveCategories(store,persistableCategory);
}
get attribute from httpservletrequest. But i can't know where i set attribute with name MERCHANT_STORE in postman. I set in body look like
{
"attributes": {
"MERCHANT_STORE": {
"code":"1"
}
},
but it not working. How to set attribute in postman and using HttpServletRequest get it.
if you have more APIs, and need to response like the request (more than one depth attribute)
{
"attributes": {
"MERCHANT_STORE": {
"code":"1",
"code2":{
"element1":"1",
"element2":"2"
}}}
2.First, make a class for response.
public class responseData {
private merchant_store;
// getter, setter, the other elements..
}
i think that's better to make to make class for setting results.
public class result{
private View json; // this object from spring servlet lib.
// and make methods to parse http header(yep, in postman) and to return datas.
}
Let's make response in controller.
public PersistableCategory createCategory(){
MerchantStore merchantStore = (MerchantStore);
httpRequest.getAttribute("MERCHANT_STORE");
Object purpose = categoryService.saveCategories(store,persistableCategory);
Object responseData = new responseData();
responseData.set(purpose);
result.set(responseData, successYn);
return result;
}
Well, successYn is just String in my
Because i wanted to know whether it finished to access DB and set Datas.
if you want you can set other types.
This time I'm really confused and stuck...
I'm working on a spring-boot (1.5.3) application exposing a REST API with HAL style using spring-hateoas library. Some of the endpoints already work correctly and return HAL-links. Currently I'm trying to change another endpoint to also return the response with HAL, but the result is serialized in the "collection+json" style.
What I found so far:
There are 3 ObjectMapper instances in the spring context:
objectMapper
_halObjectMapper
halObjectMapper
I converted the response with all three of these and found that the first two produce "collection+json" output ("links" with "rel") and the third one produces the expected HAL style ("_links" without "rel").
Why are there three and how can I inspect and control which of these objectMappers get used for rendering the response? How is it possible that my other endpoints return the expected format?
Here's my simplified code, in case it's of any interest:
#RestController
public class SearchController{
#RequestMapping(value = "/search", produces = { "application/hal+json" }, method = RequestMethod.GET)
public ResponseEntity<SearchResponse> search(...){
SearchResponse searchResponse = ...; // search & build response
return new ResponseEntity<>(searchResponse, HttpStatus.OK);
}
}
public class SearchResponse {
#JsonProperty("_meta")
private PageSortInfo meta;
#JsonUnwrapped
private Resources<Resource<SearchResultItem>> resultlist;
...// getters & setters
}
The response is supposed to look like this:
{
"_meta" : {
...
},
"_embedded" : {
"searchResultItemList" : [ {
...,
"_links" : {
"self" : {
"href" : "..."
}
}
},
...
]
},
"_links" : {
"self" : {
"href" : "http://localhost:8882/api/search"
}
}
}
Well, after another day of digging through google search results, sprint-boot code and a lot of trial & error I finally found the answer, which is of course trivial:
Spring will choose the MessageConverter used to convert the response object to the appropriate format by matching the registered converters to the type of the object (in my case SearchResponse) and the response type ("application/hal+json" for me). The halJacksonHttpMessageConverter will only be chosen if the response object is of type ResourceSupport. SO all I had to do is make my SearchResponse extend ResourceSupport and I got the expected response format.
public class SearchResponse extends ResourceSupport {...}
Here's where I'm at. I've an MVC controller method that accepts JSON content. Because I need to validate it using JSON Schema, my controller maps the request body as a Jackson JsonNode.
Upon successful validation, I need to persist the data in Spring Couchbase repository. Consider the following snippet:
public class Foo
{
#Id
private String _id;
#Version
private Long _rev;
#Field
private JsonNode nodeData;
// .. Other data and members.
}
//
// Repository
//
#Repository
public interface FooRepository extends CrudRepository<Foo, String> {
}
When I store these elements into the Couch repository, what I'd like to see is something like this:
{
"_class": "Foo",
"field1": "field 1 data",
"nodeData" : {
"Some" : "additional data",
"from" : "JsonNode"
}
}
instead, what I see in the repository is something like this:
{
"_class": "Foo",
"field1": "field 1 data",
"nodeData" : {
"_children": {
"Some": {
"_value": "additional data",
"_class": "com.fasterxml.jackson.databind.node.TextNode"
},
"From": {
"_value": "jsonNode",
"_class": "com.fasterxml.jackson.databind.node.TextNode"
},
"_nodeFactory": {
"_cfgBigDecimalExact": false
}
}
}
Each stored property of the JsonNode is decorated with class information, and other meta-data, which is not desirable.
My question - is there a preferred way to get the CrudRepository to behave in the manner that I wish?
It doesn't work that way because serialization and de-serialization conventions are already established. You can override these conventions with custom serialization & de-serialization in Jackson-- but that might go beyond the "crude" approach you are looking for.
I see you want a one shoe fits all approach to data modeling.
Might i recommend storing a Map
#Field
private Map<String, String> data;
This map is private so its perfect.
You can then have two methods
one method puts to the map like so
ObjectMapper mapper = new ObjectMapper()
public void setFeild(String name, Object value) {
ObjectNode node new ObjectNode(JsonNodeFactory.instance);
node.put("clazz", value.getClass().getName());
if (value instance of String) {
node.put("value", value)
} else {
node.put("value", mapper.writeValueAsString(data));
}
data.put(name, node.toString());
}
the other gets from the map like so
public Object getField(String name) {
if (data.contains(name)) {
JsonNode node = mapper.readValue(data.get(name), JsonNode.class);
Class clazz = Class.forName(node.get("class").textValue());
if (clazz.equals(String.class) {
return node.get("value").textValue();
} else {
return (Object) mapper.readValue(node.get("value"), clazz);
}
}
}
You should update this implementation to handle Date, Integer, Boolean, Double ... etc the same way i am handling String-- POJOs are what you serialize/de-serialize to/from json.
I hope this makes sense.
Using Jackson data binding, what's the neatest way to skip a bad chunk of data, without rejecting the whole parse?
Take these classes (I'm using public fields just to keep the code short):
public class ClassWhichCouldFailConstruction {
public ClassWhichCouldFailConstruction(String s) {
if(s.charAt(0) > 'L') {
throw new BadParameterException();
}
// else init code here.
}
}
public class User {
public String name;
public ClassWhichCouldFailConstruction failable;
}
public class AppInfo {
public List<User> users;
}
... and this code to parse it:
AppInfo appinfo = (List<User>) objectMapper.readValues(jsonStream, AppInfo.class);
... and this JSON:
{ "users": [
{ "name": "John", "failable": "Example" },
{ "name": "Jane", "failable": "No good" }
]
}
By default ClassWhichCouldFailConstruction("No good") will throw an exception which will bubble up to the caller of objectMapper.readValues().
How can I make it return a AppInfo object containing a users list that is one item long (the valid item)?
And can I run a routine to deal with (e.g. to log) the skipped entry?
I know I can achieve this with a custom deserializer:
public class User {
public String name;
#JsonDeserialize (using = MyCustomDeserializer.class)
public ClassWhichCouldFailConstruction failable;
}
... in which MyCustomDeserializer consumes the content in incremental mode. I'm looking for an option which takes advantage of data binding. Consider that ClassWhichCouldFailConstruction might be something a whole lot more complicated, so writing a custom parser would be laborious.
Use Bean Validation API instead of throwing exception from constructor -- aspects of JSON parsing and data-binding (that Jackson does) can be separated from validation logic. This is where Bean Validator helps: you can declaratively define rules and constraints.