Skip to content

A simple plugin for converting POJO to JSON in IntelliJ IDEA

License

Notifications You must be signed in to change notification settings

organics2016/pojo2json

Repository files navigation

POJO to JSON

A simple plugin for converting POJO to JSON in IntelliJ IDEA

  • Support any type you can think of in Java.
  • Support Java17 and last
  • Support Java14 Records JEP-359
  • Partial support Jackson and Fastjson annotations.
  • Support conversion
    • Inner Class
    • Global Variable
    • Local Variable
    • Constructor Parameter
    • Method Parameter

Support JVM platform languages

  • Java - full support
  • Kotlin - full support

Usage

  • Note that the position of the cursor can affect the result!

  • Open class file > Move cursor to Class/Variable/Parameter > Right click > Copy JSON > JSON result will copy to clipboard Image text

  • Open class file > Move cursor to Class/Variable/Parameter > Alt + Insert > Copy JSON > JSON result will copy to clipboard Image text

  • Project view select a class file > Right click > Copy JSON > JSON result will copy to clipboard Image text

  • Project view select multiple files > Right click > Copy JSON > JSON result will generate to files in the Scratches folder Image text

Installation

  • Install in IDEA:

    • Preferences(Settings) > Plugins > Marketplace > Search"POJO to JSON" > Install
  • Manual Install:

    • plugin -> Preferences(Settings) > Plugins > ⚙️ > Install plugin from disk... -> Select the plugin package and install(No need to unzip)

Q&A

  • Why always report errors when use it?

    This class reference level exceeds maximum limit or has nested references!
    

    When the program throws this warning there are only two possibilities.

    1. This class or parent class has nested references

      eg:

      public class A {
          private B b;
      
          public class B {
              private A a;
          }
      }
      {
       "b":{
        "a":{
         "b":{
           "a":{
              ......
            }
          }
         }
       }
      }
      

      or

      public class A {
          private A a;
      }
      {
       "a":{
        "a":{
         "a":{
           "a":{
              ......
            }
          }
         }
       }
      }
      
    2. This class reference level > 200

      eg:

      public class A {
          private B _0;
      
          public class B {
              private C _1;
      
              public class C {
                  private D _2;
      
                  public class D {
                      // _3 ..... _201..
                  }
              }
          }
      }
      {
        "_0": {
          "_1": {
            "_2": {
              "......_201":{}
            }
          }
        }
      }
      

      Perhaps both will happen for entity but this entity are not suitable for JSON.
      So you can try to serialize your POJO using Jackson to see what happens.
      If no exception, you can submit a bug to this repository issues with your target class :)

  • But how to solve this problem?

    You can try the following methods.

Support Annotations and Javadoc

  • @JsonProperty and @JSONField

    import com.alibaba.fastjson.annotation.JSONField;
    import com.fasterxml.jackson.annotation.JsonProperty;
    
    public class User {
    
        @JsonProperty("name")
        private String username;
    
        @JSONField(name = "pass")
        private String password;
    }

    paste result:

    {
      "name": "",
      "pass": ""
    }
  • @JsonIgnore or Javadoc tags JsonIgnore

    import com.fasterxml.jackson.annotation.JsonIgnore;
    
    public class User {
    
        @JsonIgnore
        private String username;
        private String password;
    }

    or when there is no jackson library

    public class JsonIgnoreDocTestPOJO {
    
        /**
         * @JsonIgnore
         */
        private String username;
        private String password;
    }

    paste result:

    {
      "password": ""
    }
  • @JsonIgnoreProperties or Javadoc tags JsonIgnoreProperties

    import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
    
    import java.util.List;
    
    public class User {
    
        private String username;
        @JsonIgnoreProperties({"users", "aaa", "bbb"})
        private List<Role> roles;
    
        public class Role {
    
            private String roleName;
            private List<User> users;
        }
    }

    or when there is no jackson library

    import java.util.List;
    
    public class User {
    
        private String username;
        /**
         * @JsonIgnoreProperties users, aaa, bbb
         */
        private List<Role> roles;
    
        public class Role {
    
            private String roleName;
            private List<User> users;
        }
    }

    paste result:

    {
      "username": "",
      "roles": [
        {
          "roleName": ""
        }
      ]
    }

    You may encounter this problem during use.

    This class reference level exceeds maximum limit or has nested references!
    

    The above method can solve the nested reference problem well.

  • @JsonIgnoreType

    import com.fasterxml.jackson.annotation.JsonIgnoreType;
    
    import java.util.List;
    
    public class User {
    
        private String username;
        private List<Role> roles;
    
        @JsonIgnoreType
        public class Role {
            private String roleName;
            private List<User> users;
        }
    }

    paste result:

    {
      "username": "",
      "roles": []
    }

Configure SpEL expression

What can SpEL expression do?

  • Configure meaningful test values.

  • Field-level control of convert results.

  • Customize any type you want to convert.

  • IntelliJ IDEA > File > Settings > Tools > POJO to JSON Image text

Configuration

Default Configuration

  • This is a default configuration. Normally no modification.

    com.fasterxml.jackson.databind.JsonNode=#{#object.getValue()}
    com.fasterxml.jackson.databind.node.ArrayNode=#{#array.getValue()}
    com.fasterxml.jackson.databind.node.ObjectNode=#{#object.getValue()}
    java.lang.Boolean=#{#boolean.getValue()}
    java.lang.CharSequence=#{#field.getName() + '_' + #shortuuid.getValue()}
    java.lang.Character=#{'c'}
    java.lang.Double=#{#decimal.getValue()}
    java.lang.Float=#{#decimal.getValue()}
    java.lang.Number=#{#integer.getValue()}
    java.math.BigDecimal=#{#decimal.getValue()}
    java.time.LocalDate=#{#datetime.getValue('yyyy-MM-dd')}
    java.time.LocalDateTime=#{#datetime.getValue('yyyy-MM-dd HH:mm:ss')}
    java.time.LocalTime=#{#datetime.getValue('HH:mm:ss')}
    java.time.YearMonth=#{#datetime.getValue('yyyy-MM')}
    java.time.ZonedDateTime=#{#datetime.getValue()}
    java.time.temporal.Temporal=#{#temporal.getValue()}
    java.util.AbstractMap=#{#object.getValue()}
    java.util.Date=#{#datetime.getValue('yyyy-MM-dd HH:mm:ss')}
    java.util.Map=#{#object.getValue()}
    java.util.UUID=#{#uuid.getValue()}

Random Value Configuration

  • If you want to ask where the previous option Copy JSON and Random Values went? Use the following configuration to achieve the previous effect.

    com.fasterxml.jackson.databind.JsonNode=#{#object.getValue()}
    com.fasterxml.jackson.databind.node.ArrayNode=#{#array.getValue()}
    com.fasterxml.jackson.databind.node.ObjectNode=#{#object.getValue()}
    java.lang.Boolean=#{#boolean.getRandomValue()}
    java.lang.CharSequence=#{#field.getName() + '_' + #shortuuid.getValue()}
    java.lang.Character=#{'c'}
    java.lang.Double=#{#decimal.getRandomValue()}
    java.lang.Float=#{#decimal.getRandomValue()}
    java.lang.Number=#{#integer.getRandomValue()}
    java.math.BigDecimal=#{#decimal.getRandomValue()}
    java.time.LocalDate=#{#datetime.getRandomValue('yyyy-MM-dd')}
    java.time.LocalDateTime=#{#datetime.getRandomValue('yyyy-MM-dd HH:mm:ss')}
    java.time.LocalTime=#{#datetime.getRandomValue('HH:mm:ss')}
    java.time.YearMonth=#{#datetime.getRandomValue('yyyy-MM')}
    java.time.ZonedDateTime=#{#datetime.getRandomValue()}
    java.time.temporal.Temporal=#{#temporal.getRandomValue()}
    java.util.AbstractMap=#{#object.getValue()}
    java.util.Date=#{#datetime.getRandomValue('yyyy-MM-dd HH:mm:ss')}
    java.util.Map=#{#object.getValue()}
    java.util.UUID=#{#uuid.getValue()}

Global JSON Keys Format Configuration

Expression Result Eg
Camel Case(Default) #{#field.getName()} or #{#field.getCamelCaseName()} testName
Snake Case #{#field.getSnakeCaseName()} test_name
Kebab Case #{#field.getKebabCaseName()} test-name
Pascal Case #{#field.getPascalCaseName()} TestName
Snake Case Upper #{#field.getSnakeCaseUpperName()} TEST_NAME

Configuration Details

  • Full compliance with SpEL expression standards.

  • Expressions need to be used only when operations or references are required. The expression must start with #{ and end with }

    # result {"test":"ABCD"}
    com.example.TestClass=ABCD
    # result {"test":"ABCD_4_732f65b6b9cf"}
    com.example.TestClass=ABCD#{"_" + 2+2 + "_" + #shortuuid.getValue()}
  • The plugin has some built-in shortcut references.Note that not all references support getRandomValue()

Ref Expression Result Eg Support getRandomValue()
#boolean #{#boolean.getValue()} false
#array #{#array.getValue()} [] N
#object #{#object.getValue()} {} N
#decimal #{#decimal.getValue()} 0.00
#integer #{#integer.getValue()} 0
#localdatetime #{#localdatetime.getValue()} 2023-09-14 15:04:52
#localdate #{#localdate.getValue()} 2023-09-14
#localtime #{#localtime.getValue()} 15:04:52
#yearmonth #{#yearmonth.getValue()} 2023-09
#temporal #{#temporal.getValue()} 1694675092600
#zoneddatetime #{#zoneddatetime.getValue()} 2023-09-14T15:04:52.601+08:00
#uuid #{#uuid.getValue()} 679e70fa-d24b-4726-ab87-2de620333f20 N
#shortuuid #{#shortuuid.getValue()} 732f65b6b9cf N
#datetime #{#datetime.getValue()} 2023-09-14T15:04:52.601+08:00
  • Custom Date Format

    java.time.YearMonth=#{#datetime.getValue('yyyy-MM')}

    or need random values

    java.time.YearMonth=#{#datetime.getRandomValue('yyyy-MM')}
  • Custom Number types

    # Get a random number between 0 and 100, retaining 2 decimal places.
    java.math.BigDecimal=#{#decimal.getRandomValue(0,100,2)}
    # Get a random number between 0 and 100, retaining 2 decimal places.
    java.math.BigDecimal=#{#decimal.getRandomValue(2)}
  • Custom String type

    java.lang.CharSequence=#{#field.getName() + '_' + #shortuuid.getValue()}

    or

    java.lang.String=#{#field.getName() + '_' + #shortuuid.getValue()}

    The #field reference is quite special and can be simply understood as each field in the Class.It actually points to a PsiVariable instance.

  • You will find that this configuration has an extends relationship.So you can define the expression of the parent class, and the sub-class will also benefit.

    com.example.ParentClass=#{#field.getName() + '_' + #shortuuid.getValue()}
    class SubClass extends ParentClass {
    }
    
    public class Test {
        private SubClass subClass;
    }

    json result:

    {
      "subClass": "subClass_4c672dc197e3"
    }
  • Some special cases, SpEL expressions cannot be adapted.

    • You cannot create custom classes outside of Java Base package because plugins cannot reflect instances of custom classes.

      You can

      java.lang.Number=#{new java.math.BigDecimal(6)}

      You can't

      java.lang.Number=#{new com.example.BigDecimal(6)}
    • The test found that the first situation will cause problems in Kotlin.

      Eg

      java.lang.Number=#{#integer.getRandomValue}

      But recommended this

      java.lang.Number=#{#integer.getRandomValue()}
    • When incorrect configuration causes the plugin to fail to run properly, you can clear the configuration and save it, and the plugin will initialize the default configuration.

Contributors

Ideas and partial realization from linsage