Как автоматически анализировать JSON в приложении Spring Boot с помощью Jackson

#java #json #spring #jpa #jackson

#java #json #spring #jpa #джексон

Вопрос:

У меня есть файл json с объектом json в качестве значения свойства внутри:

 {
 "name": "name",
 "json": {...}
}
  

Мне нужно автоматически получить его в RestController и использовать его как объект в JPA Hibernate.

Моя сущность:

ОБНОВИТЬ -> более определенный объект

 @Entity
@Table(name = "collections")
public class Collection {
    @Id
    private String name;

    @Column(name = "cache_limit")
    private int limit;

    @Column(name = "cache_algorithm")
    private String algorithm;

    @Transient
    private JsonNode schema;

    @JsonIgnore
    @Column(name ="json_schema")
    private String jsonSchema;

    public Collection() {
    }

    public String getJsonSchema() {
        return schema.toString();
    }

    public void setJsonSchema(String jsonSchema) {
        ObjectMapper mapper = new ObjectMapper();
        try {
            schema = mapper.readTree(jsonSchema);
        } catch (IOException e) {
            throw new RuntimeException("Parsing error -> String to JsonNode");
        }
    }

   ..setters and getters for name limit algorithm schema..
}
  

Когда я использую, entityManager.persist(Collection) у меня есть json_schema столбец как NULL

Как я могу это решить? Возможно, проблема в setJsonSchema()

Обновить:

 public String getJsonSchema() {
        return jsonSchema;
    }

    public void setJsonSchema(JsonNode schema) {
        this.jsonSchema = schema.toString();
    }
  

Такие методы получения / установки не решают проблему

Комментарии:

1. Что вы подразумеваете под «поле json будет пустым».? Ваш контроллер выглядит так, Cat getCat(int name){ return cats.getCatByName(name);} и он возвращает JSON объект с name и json свойство пусто?

Ответ №1:

Вы могли бы определить JsonNode json свойство как @Transient , чтобы JPA не пытался сохранить его в базе данных. Однако jackson должен уметь переводить его обратно и вперед в Json.

Затем вы можете закодировать getter / setter для JPA, чтобы переводить из JsonNode в строку назад и вперед. Вы определяете средство получения, getJsonString которое переводится JsonNode json в String . Его можно сопоставить со столбцом таблицы, например ‘json_string’, затем вы определяете сеттер, в котором вы получаете String из JPA, и анализируете его в JsonNode, который будет доступен для jackson.

Не забудьте добавить @JsonIgnore в getJsonString , чтобы Jackson не пытался перевести в json как jsonString.

 @Entity
@Table(name = "cats")
public class Cat {

  private Long id;

  private String name;

  @Transient
  private JsonNode json;

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  public Long getId() {
    return id;
  }

  @Column(name ="name")
  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public void setId(Long id) {
    this.id = id;
  }

  // Getter and setter for name

  @Transient
  public JsonNode getJson() {
    return json;
  }

  public void setJson(JsonNode json) {
    this.json = json;
  }


  @Column(name ="jsonString")
  public String getJsonString() {
    return this.json.toString();
  }

  public void setJsonString(String jsonString) {
    // parse from String to JsonNode object
    ObjectMapper mapper = new ObjectMapper();
    try {
      this.json = mapper.readTree(jsonString);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}
  

Комментарии:

1. Это немного странно, но json.asText() не работает. json.toString() работает

2. Когда я использую JPA, этот столбец @JsonIgnore равен нулю

3. Можете ли вы выполнить отладку и посмотреть, каково значение json в get / setJsonString?

4. get/setJsonString работают корректно. После использования EntityManager.persist (cat) у меня в базе данных NULL

5. Я могу удалить @Column(name =»json_string») — результат был бы тем же

Ответ №2:

Как объясняется в этой статье, вам не нужно создавать пользовательский тип гибернации вручную, поскольку вы можете просто получить его через Maven Central, используя следующую зависимость:

 <dependency>
    <groupId>com.vladmihalcea</groupId>
    <artifactId>hibernate-types-52</artifactId>
    <version>${hibernate-types.version}</version> 
</dependency> 
  

Для получения дополнительной информации ознакомьтесь с проектом с открытым исходным кодом Hibernate Types.

Затем вы можете просто объявить новый тип вашего класса.

 @TypeDef(
    name = "jsonb-node", 
    typeClass = JsonNodeBinaryType.class
)
  

И сопоставление сущностей будет выглядеть следующим образом:

 @Type(type = "json-node")
@Column(columnDefinition = "json")
private JsonNode json;
  

Ответ №3:

Создайте ответ, не вводя логику в средство установки / получения объектов, без сторонних зависимостей:

 ObjectNode node = JsonNodeFactory.instance.objectNode();
node.put("name", cat.getName());
node.set("json", new ObjectMapper().readTree(cat.getJson()));
return Response.ok(node).build();