Grails get child domain objects - json

I have two domain classes one is parent and other one is child and i have a hasMany relationship between them. Parent class has many childs and child class belongs to parent class.
And here is coding example.
class Parent{
String name
static hasMany = [childs:Child]
static constraints = {
}
}
class Child{
String name
static belongsTo = [parent:Parent]
static constraints={}
}
Problem is as soon as I get the parent object the child objects associated with parent class were also fetched. But when I convert the object to JSON I don't see the child object completely I can only able to see the ID's of child objects. I want to see all columns of child object instead of only Id.
Converted JSON response:
[{"class":"project.Parent","id":1,
"name":"name1","childs":[{"class":"Child","id":1},{"class":"Review","id":2}]}]
But I want the response which contains name of child object too, as follows
[{"class":"project.Parent","id":1,"name":"name1",
"childs":[{"class":"Child","id":1,"name":"childname1"},
{"class":"Review","id":2,"name":"childname2"}
]
}]
Any help greatly appreciated.
Thanks in advance.

The issue is with the use of default JSON converter. Here are your options:
1. Default - all fields, shallow associations
a. render blah as JSON
2. Global deep converter - change all JSON converters to use deep association traversal
a. grails.converters.json.default.deep = true
3. Named config marshaller using provided or custom converters
a. JSON.createNamedConfig('deep'){
it.registerObjectMarshaller( new DeepDomainClassMarshaller(...) )
}
b. JSON.use('deep'){
render blah as JSON
}
4. Custom Class specific closure marshaller
a. JSON.registerObjectMarshaller(MyClass){ return map of properties}
b. render myClassInstance as JSON
5. Custom controller based closure to generate a map of properties
a. convert(object){
return map of properties
}
b. render convert(blah) as JSON
You are currently using Option 1, which is default.
The simplest you can do is use Option 2 to set global deep converter, but be aware this effects ALL domain classes in your app. Which means that if you have a large tree of associations culminating in a top level object and you try to convert a list of those top level objects the deep converter will execute all of the queries to fetch all of the associated objects and their associated objects in turn. - You could load an entire database in one shot :) Be careful.

The latest grails automatically deep converts but you are probably a victim of lazy loading.
The children are not loaded at access and hence the JSON converter cannot convert them to JSON.
The workaround is to put this
static mapping = { childs lazy: false }

user dbrin is correct, but there's one more option. You could also use the Grails GSON Plugin:
https://github.com/robfletcher/grails-gson#readme
The Plugin adds some more features when dealing with json data.

The suggested solution is working, however I had some trouble referencing "grailsApplication". It turns out, that you can ingest it like any other service. I put the following code into the
BootStrap.groovy
file. Also, the class DeepDomainClassMarshaller handles quite well bidirectional circular references, but beware that the JSON Payload is not to big after all deep deferencation.
package aisnhwr
import grails.converters.JSON
import grails.core.GrailsApplication
import org.grails.web.converters.marshaller.json.DeepDomainClassMarshaller
class BootStrap {
GrailsApplication grailsApplication
def init = { servletContext ->
JSON.createNamedConfig('deep'){
it.registerObjectMarshaller( new DeepDomainClassMarshaller(false, grailsApplication) )
}
}
def destroy = {
}
}

Related

Unity JSONUtility to JSON list of base classes

I have a BaseClass and bunch of derived classes.
I also have List<BaseClass> that contains objects from those derived classes.
When I do JSONUtility.ToJson(List<BaseClass>) I get only properties of BaseClass and not derived classes.
And well... I guess it is logical, but can't I force it to use derived class if there's a one or JSONUtility isn't capable of it? So I need to write custom logic for that?
Thanks!
Very probably JSONUtility.ToJson(List<BaseClass>) gets the elements you need with reflection, so the object returned is based on the incoming type.
I would try to obtain the jsons one by one and combine them in the logic, pre casting each of the types. Not tested nor debugged, just an starting point idea to move on:
string jsons;
foreach (var baseClass in baseClassList) {
Type specificType = baseClass.GetType();
string jsonString = JsonUtility.ToJson((specificType)baseClass)
jsons = "[" + string.Join(",", jsonstring) + "]";
}
I faced the same issue, to be honest JsonUtility is not good option for working with List.
My recommendations:
Use array instead of list with this helper class
or Newtonsoft Json Unity Package
I also needed JSON serialization, to call a REST json API, and I suggest to avoid JSONUtility.
It doesn't handle lists or dictionaries, as you saw.
Also it cannot serialize properties defined with { get; set; }, only fields, which is not blocking but not very convenient.
I agree with the recommendation above, just use Newtonsoft. It can serialize anything, and you will also benefit of the Serialization Settings (you can for example setup the contract resolver to convert all property names to snake_case...). See https://www.newtonsoft.com/json/help/html/SerializationSettings.htm

Deserialize just one or two attributes from a Json in Spring Boot

So in this case, I want to consume a third party API to compare capitals with countries, I don't need any other attribute from the Json but those 2, however the API I'm using has a lot of extra attributes on it.
What is the easiest way to deserialize the Json into a class with just those 2 attributes I want?
I tried this but of course it didn't work:
Country country = restTemplate.getForObject( "https://restcountries.eu/rest/v2/capital/"+learning.getCapital(), Country.class);
I understand that this doesn't work because it's trying to map the Json attributes into the class which of course lacks the remaining attributes (It just has two string attributes called Name and Capital).
Annotate the class with #JsonIgnoreProperties:
#JsonIgnoreProperties(ignoreUnknown = true)
public class Country {
You could ignore unkown properties on object mapper for this rest template:
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
if you want this feature globally you can set in your application.properties
spring.jackson.deserialization.FAIL_ON_UNKNOWN_PROPERTIES=false

How to modify spring/jackson JSON deserialisation

I'm trying to figure out how to adjust the way spring/jackson convert a JSON string (stored in a file) into various POJOs. For example, if I have this JSON:
{
"rates":{
"EURUSD":5.4321,
"USDHKD":1.2345
}
}
I actually want to get an instance of my 'Rates' class. Inside that I want a List containing each individual rate.
In my spring config file I created this entry:
#Bean
public ObjectMapper jsonObjectMapper() {
return new MappingJackson2HttpMessageConverter().getObjectMapper();
}
And in my service class I did this:
#Autowired
ObjectMapper jsonObjectMapper;
public Rates currentRates() {
Resource resource = this.ctx.getResource("classpath:stub/data/rates/Rates-01.json");
return this.jsonObjectMapper.readValue(resource.getURL(), Rates.class);
}
The problem is that I am trying to figure out how to take the Map containing the currencies as a single key, break those currencies in two and then create a RateEntry object containing the two currencies and the rate, before populating a list in the Rates class.
I've been looking at Spring's Conversion Service with the idea to define a converter that maps the Map to a list. i.e. this signature: Converter<Map<String, BigDecimal>, List<Rate>>. However this is based on the assumption that the JSON is first converted to standard types before the conversion service is called. An assumption I now think is incorrect.
So I'm now trying to figure out if I need to register some sort of custom ObjectMapper to handle reading directly from the JSON String data. But that sounds like over kill as I only want to adjust part of the object graph, and let the default converters handle the rest.
Any pointers appreciated. Thanks.
Ok, Jackson tries to stay away from structural transformations (since it's a quick-sand pit with unlimited number of general permutations). But it might be possible to use some existing features to do what you want.
First: to use Object key to indicate type, you will probably want to enable polymorphic type handling with "as object wrapper" inclusion.
So add something like:
#JsonTypeInfo(as=Include.WRAPPER_OBJECT)
for your Rates class declaration.
As to converting values into list; this might work by defining "any-setter" (see http://www.cowtowncoder.com/blog/archives/2011/07/entry_458.html), something like:
#JsonAnySetter
public void set(String key, Double value) // or "Object value")
{
list.add(new Rate(key, value));
}
I hope this helps.

Saving and loading with Json

Until now I was using serializable for saving and loading data, but now I have switched to JSON. And as soon as I have started there is a problem. Json will not save me any class. I was trying to save standalone Variables.class. This class contains various static data - player type string, bonus type strings, scores. Then I did create private class in class, then class in method, but nothing. Output od System.out.println(json) is always just {}.
For example this was my last attempt to make things work:
public static void saveAVD() {
Variables v = new Variables();
String json = new Json().toJson(v);
System.out.println(json);
file.writeString(json.prettyPrint(json), false);
}
Note: File variable is located in local bin folder. Inside that file are also just two empty bracelets ({})
Any advice?
(Credit to noone, who answered this in a comment).
JSON will, by default, not serialize static fields. The quickest way to get the behavior you want would probably be to convert the Variables class into a singleton.

one Jackson deserializer for multiple types (config by annotation)

I'm trying to change the (de)serialization of a list in one of my classes.
the objects in the list shall be serialised as int (their jpa id) and deserialised accordingly. serialization is simple.
for the deserialization i have a class that can translate the id into the object if id and class are known.
How do i get the necessary class from jackson? all default jackson serialisers have a constructor like this: protected StdDeserialiser(Class<?> vc) so the information is present somewhere.
is there a way to access it during deserialisation?
or before the deserialiser is constructed by jackson?
or inside the HandlerInstantiator?
I only want to overwrite the default deseriliser for certain references so i can't just write a provider or a custom module.
I made it work from inside the deserializer with the help of the ContextDeserializer interface as this supplies the deserializer with the target property.
public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property) throws JsonMappingException {
Class<?> vc = null;
if (property.getType().isCollectionLikeType()) {
vc = property.getType().getContentType().getRawClass();
} else {
vc = property.getType().getRawClass();
}
return new ResourcePathDeserializer(vc, converter);
}
This solution is not perfect as I only get the raw class of the return type or the generic (which might be a parent class or an interface) but that is enough for my requirements.
It would be better if I could access the "real" class that was resolved by Jackson, but for me this works.
First of all, there is nothing fancy about writing a Module: it is just a way for plugging things in, like custom (de)serializers. So no need to avoid that. And you will most like need to write a module to do what you want.
In general it is not a good idea to try to create "universal" serializers or deserializers, and it will probably run into problem. But it depends on what exactly you are trying to do.
Type information will either be:
Implicit from context: you are writing a (de)serializer for type T, and register it for it, so that's your type
Passed by Jackson when (de)serializer is being constructed, via Module interface: modules are asked if they happen to have a (de)serializer for type T. SimpleModule will only use basic Class-to-impl mapping (that's where "simple" comes from); but full custom Module has access to incoming type.
But I don't know if above will work for your use case. Type information must be available from static type (declared content type for the list).