I have an entity that owns another entity:
//psuedocode
public class ClassA{
private String name;
@OneToOne
private ClassB classb;
}
public class ClassB{
private String thing1;
private String thing2;
private String thing3;
}
When I retrieve ClassA objects, I don't want to see ClassB.thing3, but I do want to see thing1 and thing 2:
{
"name":"classa",
"classb":{
"thing1":"hi",
"thing2":"there"
}
}
But if I query for ClassB I want to see everything:
{"thing1":"hi",
"thing2":"there",
"thing3":"joseph"}
So I can't just put an ignore annotation over thing3, because then I'll ignore it on the second fetch. I tried a Converter<ClassB>
, but that forces me to implement toString()
and fromString()
for the JSON, which dies on converting the JSON object to Java-side (the converter expects a String, but gets the object instead).
I want to avoid building/parsing the JSON object myself if possible to let my json provider do the work, if possible. I'm on Johnzon.
This is possible, you need to use @NamedEntityGraph,
This should help, http://www.thoughts-on-java.org/jpa-21-entity-graph-part-1-named-entity/
Something like this should be possible by querying using SELECT NEW, but you're going to need some new Classes for that ... and won't be passing your entities directly to JSON.
new Classes: (pseudocode)
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;
Then you can pass ResultA instead of ClassA to JSON.
PS: As mentioned in the comment above, I don't think NamedEntityGraphs are the way to go here
I would always fetch all the data from the database and let the filtering to be done by the JSON provider if you want to serialize it anyway. If you use Jackson you can simply add views to your fields:
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 {
}
}
Later when you serialize your object you just need to use your view:
String result = mapper
.writerWithView(Views.AlwaysInclude.class)
.writeValueAsString(new ClassA());
When you want to serialize only ClassB then you shouldn't use views.
String result = mapper.writeValueAsString(new ClassB());
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With