Как вы отправляете обратно подмножество объекта JPA, принадлежащего другому объекту?

У меня есть объект, которому принадлежит другой объект:

//psuedocode    
public class ClassA{
   private String name;

   @OneToOne
   private ClassB classb;
}

public class ClassB{
   private String thing1;
   private String thing2;
   private String thing3;
}

Когда я извлекаю объекты ClassA, я не хочу видеть ClassB.thing3, но я хочу видеть вещь1 и вещь 2:

{
"name":"classa",
"classb":{
         "thing1":"hi",
         "thing2":"there"
        }
}

Но если я запрашиваю для ClassB, я хочу видеть все:

{"thing1":"hi",
 "thing2":"there",
 "thing3":"joseph"}

Поэтому я не могу просто поместить аннотацию ignore поверх thing3, потому что тогда я проигнорирую ее во второй выборке. Я попробовал Converter<ClassB>, но это заставило меня реализовать toString() и fromString() для JSON, который умирает при преобразовании объекта JSON на Java-сторону (конвертер ожидает String, но вместо этого получает объект).

Я хочу избежать сборки/разбора объекта JSON самостоятельно, если это возможно, чтобы мой поставщик json выполнял работу, если это было возможно. Я нахожусь на Джонсоне.

Ответ 2

Что-то вроде этого должно быть возможным путем запроса с помощью SELECT NEW, но вам понадобятся новые классы для этого... и не будут передавать ваши сущности непосредственно в JSON.

новые классы: (Псевдокод)

class ResultB {
   String thing1;
   String thing2;

   public ResultB(ClassB classB) {
       this.thing1 = classB.thing1;
       this.thing2 = classB.thing2; 
   } 
}

class ResultA {
   String name;
   ResultB resultB;

   public ResultA(ClassA classA) {
      this.name=classA.name;
      this.resultB=new ResultB(classA);
   }
}

Query:

select new ResultA(a) from ClassA a fetch join a.classB;

Затем вы можете передать ResultA вместо ClassA в JSON.

PS: Как уже упоминалось в комментарии выше, я не думаю, что NamedEntityGraphs - это путь сюда

Ответ 3

Я бы всегда извлекал все данные из базы данных и позволял фильтрацию выполнять поставщик JSON, если вы все равно его сериализуете. Если вы используете Джексон, вы можете просто добавить представления в свои поля:

public class ClassA {

   @JsonView(Views.AlwaysInclude.class)
   private String name;

   @JsonView(Views.AlwaysInclude.class)
   @OneToOne
   private ClassB classb;
}

public class ClassB {
   @JsonView(Views.AlwaysInclude.class)
   private String thing1;

   @JsonView(Views.AlwaysInclude.class)
   private String thing2;

   private String thing3;
}

public class Views {
    public static class AlwaysInclude {
    }
}

Позже, когда вы сериализуете свой объект, вам просто нужно использовать ваше представление:

String result = mapper
  .writerWithView(Views.AlwaysInclude.class)
  .writeValueAsString(new ClassA());

Если вы хотите сериализовать только ClassB, вы не должны использовать представления.

String result = mapper.writeValueAsString(new ClassB());