Search code examples
jakarta-eejerseyjax-rsmoxyjsonb-api

Instead of @JsonbIgnore, is it possible to require explicit inclusion of an object's fields on jax-rs (jersey+moxy) JSON serialization?


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).

(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?


Solution

  • 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