Search code examples
javajsonspring-rest

Spring REST any way to set the JSON type field automatically?


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.


Solution

  • 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.