Работа с двунаправленным 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, как я хотел!