JSON to POJO with custom annotations

Gaʀʀʏ picture Gaʀʀʏ · Jan 23, 2018 · Viewed 6.9k times · Source

I'm trying to include Spring Boot annotations in my generated Java code from JSON like these:

@Entity
public class Person {
...
}

and

@Repository
public interface PersonRepository extends CrudRepository<Person, Long> 
{
}

I'm converting from JSON to POJO with this tutorial. What can I add to my json files to make the generated Java classes include annotations @Entity and @Repository? I have yet to find a tutorial or explanation as to how to provide custom annotations.

jsonschema2pojo looks like it could work using a custom annotator when generating classes, but I am wondering if there is anything built-in to Jackson that easily allows custom annotations?

Answer

Gaʀʀʏ picture Gaʀʀʏ · Jan 23, 2018

jsonschema2pojo's customAnnotator allowed me to add custom annotations to generated java files. The annoyance with it is that your annotator class must be in a separate project and must be included within the plugin. Here's why.

Add the dependency to your pom.xml

<dependency>
    <groupId>org.jsonschema2pojo</groupId>
    <artifactId>jsonschema2pojo-core</artifactId>
    <version>0.4.0</version>
</dependency>

Add the plugin to the pom.xml plugins

<plugin>
    <groupId>org.jsonschema2pojo</groupId>
    <artifactId>jsonschema2pojo-maven-plugin</artifactId>
    <version>0.5.1</version>
    <dependencies>
        <!-- NOTE: Your annotator MUST come from a dependency -->
        <dependency>
            <groupId>ANNOTATOR_GROUP_ID</groupId>
            <artifactId>ANNOTATOR_ARTIFACT</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
            <scope>compile</scope>
            <version>1.5.2.RELEASE</version>
        </dependency>
       <!-- NOTE: Any annotation used must have its dependency here!!! -->
    </dependencies>
    <configuration>
        <sourceDirectory>${basedir}/src/main/resources/schema</sourceDirectory>
        <targetPackage>com.test.gen</targetPackage>
        <useCommonsLang3>true</useCommonsLang3>
        <customAnnotator>com.fully.qualified.path.YourAnnotator</customAnnotator>
    </configuration>
    <executions>
        <execution>
            <goals>
                <goal>generate</goal>
            </goals>
        </execution>
    </executions>
</plugin>

Create your custom annotator class in a separate project.

package com.deere.gtin_k.pdeaas.work_manager.application;

import com.fasterxml.jackson.databind.JsonNode;
import com.sun.codemodel.JDefinedClass;
import com.sun.codemodel.JFieldVar;
import org.jsonschema2pojo.AbstractAnnotator;

import javax.persistence.Entity;

public class HibernateAnnotator extends AbstractAnnotator {

    @Override
    public void propertyField(JFieldVar field, JDefinedClass clazz, String propertyName, JsonNode propertyNode) {
        super.propertyField(field, clazz, propertyName, propertyNode);

        // Note: does not have to be the propertyName, could be the field or propertyNode that is verified.
        if (propertyName.equals("entity")) {
            clazz.annotate(Entity.class);
        }
    }
}

Lastly, the json file:

{
  "title": "Person",
  "type": "object",
  "properties": {
    "entity": true,
    "name": {
      "type": "string"
    }
  }
}

And the final result:

package com.test.gen;

import java.util.HashMap;
import java.util.Map;
import javax.persistence.Entity;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;


/**
 * Person
 * <p>
 * 
 * 
 */
@JsonInclude(JsonInclude.Include.NON_NULL)
@Entity
@JsonPropertyOrder({
    "entity",
    "name"
})
public class Person {

    @JsonProperty("entity")
    private Object entity;
    ...
}

I wish there was a simpler way to do this.