Работа с двунаправленным JACKSON

Во -первых, извините за мой плохой английский;

Во-вторых, у меня есть следующий код:

@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")    

public class UserAccount implements Serializable  {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private List<Venda> vendas;

    }

И следующее:

public class Venda implements Serializable  {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private UserAccount cliente;

    }

Итак, все в порядке и получим json из сериализации таким образом (когда я запрашиваю учетную запись пользователя):

[
  {
    "id": 1,    
    "vendas": [
      {
        "id": 1,        
        "cliente": 1,        
      }
    ]
  }
]

И когда я прошу Венду:

[
  {
    "id": 1,    
    "cliente": {
      "id": 1,      
      "vendas": [
        {
          "id": 1,        
          "cliente": 1         
        }
      ]
    }
  }
]

Проблема в том, что в первом случае мне не нужна информация о клиенте о "vendas", но во втором мне нужна информация о клиенте, однако я не хочу его "vendas", потому что я уже получил это раньше;

Я уже споткнулся @JsonIgnore и у меня не работал, что мне делать?

PS: я работаю с GSON, чтобы получить.Class от JSON, и я получаю ужасное исключение, потому что иногда клиент - это объект, а иногда - целое число, так что если у вас, ребята, есть другое решение, которое заставляет клиентов и венды не менять свои типа, я бы тоже хотел знать.:(

2 ответа

Решение

Я смог решить эту проблему с помощью функции Джексона. Функция Mixin - это класс, в котором вы можете указать аннотации json (для класса, полей и методов получения / установки), и они применяются к сериализуемому bean / pojo. По сути, миксин позволяет добавлять аннотации во время выполнения и без изменения исходного файла bean / pojo. Вы используете функцию модуля Джексона для применения Mixin во время выполнения.

Поэтому я создал один миксин, который динамически добавляет @JsonIgnore аннотации к методу вендского метода получения UserAccount класс и еще один миксин, который добавляет @JsonIgnore аннотации к клиентскому методу получения Venda учебный класс.

Вот модифицированный UserAccount учебный класс:

@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class UserAccount implements Serializable
{
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private List<Venda> vendas = new ArrayList<>();

    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }
    public List<Venda> getVendas() { return vendas; }
    public void        setVendas(List<Venda> vendas) { this.vendas = vendas; }
    public void        addVenda(Venda v) { 
        this.vendas.add(v);
        v.setCliente(this);
    }

    /**
     * a Jackson module that is also a Jackson mixin 
     * it adds @JsonIgnore annotation to getVendas() method of UserAccount class
     */
    public static class FilterVendas extends SimpleModule {
        @Override
        public void setupModule(SetupContext context) {
            context.setMixInAnnotations(UserAccount.class, FilterVendas.class);
        }
        // implementation of method is irrelevant. 
        // all we want is the annotation and method's signature 
        @JsonIgnore
        public List<Venda> getVendas() { return null; }  
    }

Вот модифицированный Venda учебный класс:

public class Venda implements Serializable
{
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private UserAccount cliente;

    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }
    public UserAccount getCliente() { return cliente; }
    public void        setCliente(UserAccount cliente) { this.cliente = cliente; }

    /**
     * a Jackson module that is also a Jackson mixin 
     * it adds @JsonIgnore annotation to getCliente() method of Venda class
     */
    public static class FilterCliente extends SimpleModule {
        @Override
        public void setupModule(SetupContext context) {
            context.setMixInAnnotations(Venda.class, FilterCliente.class);
        }
        // implementation of method is irrelevant. 
        // all we want is the annotation and method's signature 
        @JsonIgnore
        public UserAccount getCliente() { return null; }
    }
}

и метод тестирования с конфигурацией сопоставителя объектов времени выполнения:

public static void main(String... args) {
    Venda v = new Venda();
    UserAccount ua = new UserAccount();
    v.setId(1L);
    ua.setId(1L);
    ua.addVenda(v);
    try {
        ObjectMapper mapper = new ObjectMapper();
        System.out.println("UserAccount: (unfiltered)");
        System.out.println(mapper.writeValueAsString(ua));

        mapper = new ObjectMapper();
        // register module at run time to apply filter
        mapper.registerModule(new Venda.FilterCliente());
        System.out.println("UserAccount: (filtered)");
        System.out.println(mapper.writeValueAsString(ua));

        mapper = new ObjectMapper();
        System.out.println("Venda: (unfiltered)");
        System.out.println(mapper.writeValueAsString(v));

        mapper = new ObjectMapper();
        // register module at run time to apply filter
        mapper.registerModule(new UserAccount.FilterVendas());
        System.out.println("Venda: (filtered)");
        System.out.println(mapper.writeValueAsString(ua));
    } catch (Exception e) {
        e.printStackTrace();
    }
}

выход:

UserAccount: (unfiltered)
{"id":1,"vendas":[{"id":1,"cliente":1}]}
UserAccount: (filtered)
{"id":1,"vendas":[{"id":1}]}
Venda: (unfiltered)
{"id":1,"cliente":{"id":1,"vendas":[{"id":1,"cliente":1}]}}
Venda: (filtered)
{"id":1}

Спасибо, ребята, я получил решение таким образом:

public class CustomClienteSerializer extends JsonSerializer<UserAccount> {

@Override
public void serialize(UserAccount cliente, JsonGenerator generator, SerializerProvider provider)
        throws IOException, JsonProcessingException {

    cliente.setVendas(null);
    generator.writeObject(cliente);

}

}

и добавив это в мой класс Venda:

@JsonSerialize(using = CustomClienteSerializer.class)   
@ManyToOne(fetch = FetchType.EAGER)
private UserAccount cliente;

Итак... Я получил JSON, как я хотел!

Другие вопросы по тегам