adam bien's blog

Creating DTOs Without Mapping with JPA and Java EE 📎

The Ping class is a JPA entity and JSON-B DTO at the same time:


@Entity
@NamedQuery(name = "all", query = "SELECT p FROM Ping p")
public class Ping {

    @Id
    @GeneratedValue
    public long id;

    public String message;
    public int age;

}

...the Ping class can be directly read from a DB:

@Stateless
public class PingStore {

    @PersistenceContext
    EntityManager em;

    public List<Ping> all() {
        return this.em.createNamedQuery("all", Ping.class).getResultList();
    }
}        
        
...and exposed via JAX-RS:

@Path("ping")
public class PingResource {

    @Inject
    PingStore store;

    @GET
    public List<Ping> all() {
        return this.store.all();
    }
}    

curl -i http://localhost:8080/flight/resources/ping/ returns:

[{"age":0,"id":1,"message":"Enjoy Java EE 8!"},{"age":0,"id":2,"message":"Enjoy Java EE 8!"}]    

A dedicated DTO:

public class PingSlice {

    public long timestamp;
    public String flightName;

    public PingSlice(String flightName) {
        this.flightName = flightName;
        this.timestamp = System.currentTimeMillis();
    }

}

can be directly mapped by the EntityManager:

public List<PingSlice> allSlices() {
        return this.em.createQuery("SELECT new com.airhacks.ping.entity.PingSlice(p.message) from Ping p", PingSlice.class).
                getResultList();
    }


exposed via JAX-RS again:

@GET
@Path("slices")
public List<PingSlice> allSlices() {
    return this.store.allSlices();
}

and returned as JSON (curl -i http://localhost:8080/flight/resources/ping/slices):

[{"flightName":"Enjoy Java EE 8!","timestamp":1542797875539},{"flightName":"Enjoy Java EE 8!","timestamp":1542797875539}]    

Also primitive types like String, can be fetched with JPA:

public List<String> allStrings() {
        return this.em.createQuery("SELECT p.message from Ping p", String.class).
                getResultList();
    }    

...exposed via JAX-RS:

@GET
@Path("strings")
public List<String> allStrings() {
    return this.store.allStrings();
}

and returned as JSON (curl -i http://localhost:8080/flight/resources/ping/strings)

["Enjoy Java EE 8!","Enjoy Java EE 8!"]

With Java EE JPA Entities can be used as DTOs first. A different "view" to the JPA entities can be implemented on-demand and without explicit mapping layers or mappers.

See you at Java EE Microservices. Is Munich's airport too far? Learn from home: javaeemicro.services.