I have a JPA entity implementing an interface and I want to expose via jax-rs endpoint only the fields that are defined by that interface. Something that looks like:
public interface ConnectedAppExternal {
String getId();
String getName();
}
@Entity(name="connected_application")
public class ConnectedApp implements ConnectedAppExternal {
@Id
@Column(name="id")
private id;
@Column(name="name")
private String name;
@Column(name="internal_status")
private String internalStatus;
...
@Override
public String getId(){
return this.id;
}
@Override
public String getName(){
return this.name;
}
public String getInternalStatus(){
return this.internalStatus;
}
public void setId(String id){
this.id = id;
}
public void setName(String name){
this.name = name;
}
public void setInternalStatus(String internalStatus){
this.internalStatus= internalStatus;
}
...
}
@Path("/applications")
public class ConnectedAppResource {
@Inject
ConnectedAppService appService;
...
@GET("applications/{id}")
@Produces("application/json")
public ConnectedAppExternal getConnectedApplication(@PathParam("id") String id){
return appService.getAppById(id);
}
...
}
Even if I make my jax-rs resource @GET
method return a ConnectedAppExternal
response, Moxy will serialize the whole JPA entity with all its properties, so I end up either having to add @JsonbIgnore
to every new internal entity field I do not want to expose; or defining a DTO containing the exposed interface fields only, which means a lot of mapping and alignment overhead (more code => more bugs / accidental leaks).
ConnectedAppExternal
interface defined properties? (Maybe a Moxy marshaller/unmarshaller config setting I missed while researching the docs on https://www.eclipse.org/eclipselink/documentation/3.0/moxy/json.htm#sthref204 and following the serializer flow?)(I am pretty sure there is not, since I have seen the serializer code, but just asking for an alternative that works like this anyway;)
...or maybe at least avoid requiring an explicit @JsonbIgnore
/@JsonbTransient
exclusion of non-exposed fields due to Moxy serializing every field with a getter/setter by default, and instead require an explicit @JsonbProperty
inclusion for a field to be JSON serialized / exposed?
As an approach you may declare JPA projection queries with required data and return Map<String, Object> type from your resource. Somthing like this:
@NamedQueries({
@NamedQuery(name="ConnectedApp.findByName",
query="SELECT c.id, c.internalStatus FROM ConnectedApp c WHERE c.name = :name")
})
See: https://dzone.com/articles/projection-queries-a-way-to-optimize-data-traffic or https://www.objectdb.com/java/jpa/query/named
Another approach would be to serialize only required properties with Jsonb, Somewhat like this:
@GET
@Path("applications/{id}")
@Produces(MediaType.APPLICATION_JSON)
public String getApp(@PathParam("id") String id) {
JsonbConfig config = new JsonbConfig().withPropertyVisibilityStrategy(
new PropertyVisibilityStrategy(){
@Override
public boolean isVisible(Field field) {
return List.of("id", "name").indexOf(field.getName()) != -1;
}
@Override
public boolean isVisible(Method method) {
return false;
}
});
Jsonb jsonb = JsonbBuilder.newBuilder().withConfig(config).build();
return jsonb.toJson(appService.getAppById(id));
}
please find example here: https://adambien.blog/roller/abien/entry/private_fields_serialization_with_json