I'm using Spring 5.3.20 to build a REST/JSON API, which is based on automatic mapping of Java POJOs to JSON objects. For instance:
@RestController
@RequestMapping ( path = "/{ds}/dataset-info", method = { RequestMethod.GET, RequestMethod.POST } )
@CrossOrigin
public class DatasetInfoService
{
@RequestMapping ( path = "" )
public DatasetInfo datasetInfo ()
{
// TODO: mockup data that need to be replaced with a real fetch from config
return new DatasetInfo () {
{
this.setTitle ( "AraTiny Dataset" );
this.setOrganization ( "Rothamsted Research" );
this.setSpecies ( List.of (
new SpecieInfo ( "3702", "Thale cress", "Arabidopsis Thaliana" ),
new SpecieInfo ( "4565", "Bread Wheat", "Triticum aestivum" ),
new SpecieInfo ( "4577", "Maize", "Zea mays" )
));
}
};
}
...
}
This returns what expected, something like:
{
"title": "AraTiny Dataset",
"organization": "Rothamsted Research",
"species": [
{
"taxId": "3702",
"commonName": "Thale cress",
"scientificName": "Arabidopsis Thaliana"
},
...
}
Now, my question is: I'd like to add something like "@type": "DatasetInfo"
at the root level of every JSON object, and I'd like to do it automatically. The value could be taken from the class name, so, in principle, it is automatable.
Is there a simple way to do it in Spring? Like, setting a flag? Or setting a decorator for a JSON serialiser?
The intuitive solution would be defining getType()
for each POJO class (or, as suggested in a comment, in a root class), but I don't think that's the most seamless one, some kind of annotation (eg, @JsonType
) would already be better, and it would be great if some helper like that already exists, so I don't need to implement one on my own.
CodePudding user response:
I am sure there is a question about this somewhere, but i can't find it. You are looking for this annotation - JsonTypeInfo.
Annotation used for configuring details of if and how type information is used with JSON serialization and deserialization, to preserve information about actual class of Object instances. This is necessarily for polymorphic types, and may also be needed to link abstract declared types and matching concrete implementation.
Example usage
package temp;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "@whatever_property_you_desire")
public class DatasetInfo {
private String name;
//getters and setters
}
property
specifies the name of the property, use = JsonTypeInfo.Id.CLASS
specifies that the fully qualified name will be used as type identifier.
Test
public class Temp {
public static void main(String[] args) throws Exception {
DatasetInfo info = new DatasetInfo();
info.setName("test");
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(info);
System.out.println(json);
}
}
DatasetInfo will be serialized as:
{
"@whatever_property_you_desire": "temp.DatasetInfo",
"name": "test"
}
Edit: Since you seem to want the property to be named @type
and to use simple class name, you can simplify to
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME)
Id.NAME
serializes type info as simple class name, and default property name for it is @type
.
CodePudding user response:
Did you look at annotating your classes with @JsonTypeInfo
? You could even make this available as a marker interface:
@JsonTypeInfo(use=JsonTypeInfo.Id.MINIMAL_CLASS, property="type")
public interface JsonTyped {
}
Then your response classes can implement this marker interface in case you want them to include the basic class name.
public class DataSetInto implements JsonTyped {
...
}