Think in enterprise java

Building Enterprise Java applications, the Spring way

I think it is fair to say that Java EE has gained pretty bad reputation among Java developers. Despite the fact that it has certainly improved on all fronts over the years, even changed home to Eclipse Foundation to become Jakarta EE, its bitter taste is still quite strong. On the other side we have Spring Framework (or to reflect the reality better, a full-fledged Spring Platform): brilliant, lightweight, fast, innovative and hyper-productive Java EE replacement. So why to bother with Java EE?

We are going to answer this question by showing how easy it is to build modern Java applications using most of Java EE specs. And the key ingredient to succeed here is Eclipse Microprofile: enterprise Java in the age of microservices.

The application we are going to build is RESTful web API to manage people, as simple as that. The standard way to build RESTful web services in Java is by using JAX-RS 2.1 (JSR-370). Consequently, CDI 2.0 (JSR-365) is going to take care of dependency injection whereas JPA 2.0 (JSR-317) is going to cover the data access layer. And certainly, Bean Validation 2.0 (JSR-380) is helping us to deal with input verification.

Читайте также:  Data text html charset utf 8 base64 decode

The only non-Java EE specification we would be relying on is OpenAPI v3.0 which helps to provide the usable description of our RESTful web APIs. With that, let us get started with the PersonEntity domain model (omitting getters and setters as not very relevant details):

@Entity @Table(name = «people») public class PersonEntity

It just has the absolute minimum set of properties. The JPA repository is pretty straightforward and implements typical set of CRUD methods.

@ApplicationScoped @EntityManagerConfig(qualifier = PeopleDb.class) public class PeopleJpaRepository implements PeopleRepository < @Inject @PeopleDb private EntityManager em; @Override @Transactional(readOnly = true) public OptionalfindByEmail(String email) < final CriteriaBuilder cb = em.getCriteriaBuilder(); final CriteriaQueryquery = cb.createQuery(PersonEntity.class); final Root root = query.from(PersonEntity.class); query.where(cb.equal(root.get(PersonEntity_.email), email)); try < final PersonEntity entity = em.createQuery(query).getSingleResult(); return Optional.of(entity); >catch (final NoResultException ex) < return Optional.empty(); >> @Override @Transactional public PersonEntity saveOrUpdate(String email, String firstName, String lastName) < final PersonEntity entity = new PersonEntity(email, firstName, lastName); em.persist(entity); return entity; >@Override @Transactional(readOnly = true) public Collection findAll() < final CriteriaBuilder cb = em.getCriteriaBuilder(); final CriteriaQueryquery = cb.createQuery(PersonEntity.class); query.from(PersonEntity.class); return em.createQuery(query).getResultList(); > @Override @Transactional public Optional deleteByEmail(String email) < return findByEmail(email) .map(entity ->< em.remove(entity); return entity; >); > >

The transaction management (namely, the @Transactional annotation) needs some explanation. In the typical Java EE application, the container runtime is responsible for managing the transactions. Since we don’t want to onboard the application container but stay lean, we could have used EntityManager to start / commit / rollback transactions. It would certainly work out but pollute the code with the boilerplate. Arguably, the better option is to use Apache DeltaSpike CDI extensions for declarative transaction management (this is where @Transactional and @EntityManagerConfig annotations are coming from). The snippet below illustrates how it is being integrated.

@ApplicationScoped public class PersistenceConfig < @PersistenceUnit(unitName = "peopledb") private EntityManagerFactory entityManagerFactory; @Produces @PeopleDb @TransactionScoped public EntityManager create() < return this.entityManagerFactory.createEntityManager(); >public void dispose(@Disposes @PeopleDb EntityManager entityManager) < if (entityManager.isOpen()) < entityManager.close(); >> >

Awesome, the hardest part is already behind! The Person data transfer object and the service layer are coming next.

Читайте также:  Java double object to string

Honestly, for the sake of keeping the example application as small as possible we could skip the service layer altogether and go to the repository directly. But this is, in general, not a very good practice so let us introduce PeopleServiceImpl anyway.

@ApplicationScoped public class PeopleServiceImpl implements PeopleService < @Inject private PeopleRepository repository; @Override public OptionalfindByEmail(String email) < return repository .findByEmail(email) .map(this::toPerson); >@Override public Person add(Person person) < return toPerson(repository.saveOrUpdate(person.getEmail(), person.getFirstName(), person.getLastName())); >@Override public Collection getAll() < return repository .findAll() .stream() .map(this::toPerson) .collect(Collectors.toList()); >@Override public Optional remove(String email) < return repository .deleteByEmail(email) .map(this::toPerson); >private Person toPerson(PersonEntity entity) < return new Person(entity.getEmail(), entity.getFirstName(), entity.getLastName()); >>

The only part left is the definition of the JAX-RS application and resources.

@Dependent @ApplicationPath(«api») @OpenAPIDefinition( info = @Info( title = «People Management Web APIs», version = «1.0.0», license = @License( name = «Apache License», url = «https://www.apache.org/licenses/LICENSE-2.0» ) ) ) public class PeopleApplication extends Application

Not much to say, as simple as it could possibly be. The JAX-RS resource implementation is a bit more interesting though (the OpenAPI annotations are taking most of the place).

@ApplicationScoped @Path( "/people" ) @Tag(name = "people") public class PeopleResource < @Inject private PeopleService service; @Produces(MediaType.APPLICATION_JSON) @GET @Operation( description = "List all people", responses = < @ApiResponse( content = @Content(array = @ArraySchema(schema = @Schema(implementation = Person.class))), responseCode = "200" ) >) public Collection getPeople() < return service.getAll(); >@Produces(MediaType.APPLICATION_JSON) @Path("/") @GET @Operation( description = "Find person by e-mail", responses = < @ApiResponse( content = @Content(schema = @Schema(implementation = Person.class)), responseCode = "200" ), @ApiResponse( responseCode = "404", description = "Person with such e-mail doesn't exists" ) >) public Person findPerson(@Parameter(description = "E-Mail address to lookup for", required = true) @PathParam("email") final String email) < return service .findByEmail(email) .orElseThrow(() ->new NotFoundException("Person with such e-mail doesn't exists")); > @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) @POST @Operation( description = "Create new person", requestBody = @RequestBody( content = @Content(schema = @Schema(implementation = Person.class)), ), responses = < @ApiResponse( content = @Content(schema = @Schema(implementation = Person.class)), headers = @Header(name = "Location"), responseCode = "201" ), @ApiResponse( responseCode = "409", description = "Person with such e-mail already exists" ) >) public Response addPerson(@Context final UriInfo uriInfo, @Parameter(description = "Person", required = true) @Valid Person payload) < final Person person = service.add(payload); return Response .created(uriInfo.getRequestUriBuilder().path(person.getEmail()).build()) .entity(person) .build(); >@Path("/") @DELETE @Operation( description = "Delete existing person", responses = < @ApiResponse( responseCode = "204", description = "Person has been deleted" ), @ApiResponse( responseCode = "404", description = "Person with such e-mail doesn't exists" ) >) public Response deletePerson(@Parameter(description = "E-Mail address to lookup for", required = true ) @PathParam("email") final String email) < return service .remove(email) .map(r ->Response.noContent().build()) .orElseThrow(() -> new NotFoundException("Person with such e-mail doesn't exists")); > >

And with that, we are done! But how could we assemble and wire all these pieces together? Here is the time for Microprofile to enter the stage. There are many implementations to chose from, the one we are going to use in this post is Project Hammock. The only thing we have to do is to specify the CDI 2.0, JAX-RS 2.1 and JPA 2.0 implementations we would like to use, which translates to Weld, Apache CXF, and OpenJPA respectively (expressed through the Project Hammock dependencies). Let us take a look on the Apache Maven pom.xml file.

 1.8.1 2.1   org.apache.deltaspike.modules deltaspike-jpa-module-api $ compile  org.apache.deltaspike.modules deltaspike-jpa-module-impl $ runtime  ws.ament.hammock dist-microprofile $ ws.ament.hammock jpa-openjpa $ ws.ament.hammock util-beanvalidation $ ws.ament.hammock util-flyway $ ws.ament.hammock swagger $ 

Without further ado, let us build and run the application right away (if you are curious what relational datastore the application is using, it is H2 with the database configured in-memory).

> mvn clean package > java -jar target/eclipse-microprofile-hammock-0.0.1-SNAPSHOT-capsule.jar

The best way to ensure that our people management RESTful web APIs are fully functional is to send a couple of requests to it:

> curl -X POST http://localhost:10900/api/people -H «Content-Type: application\json» \ -d » HTTP/1.1 201 Created Location: http://localhost:10900/api/people/a@b.com Content-Type: application/json

What about making sure the Bean Validation is working fine? To trigger that, let us send the partially prepared request.

> curl --X POST http://localhost:10900/api/people -H "Content-Type: application\json" \ -d '' HTTP/1.1 400 Bad Request Content-Length: 0

Java applications

So far so good but fairly speaking we have not talked about testing our application at all. How hard it would be to come up with the integration test for, let say, the scenario of adding a person? It turns out that the frameworks around testing Java EE applications have improved a lot. In particular, it is exceptionally easy to accomplish with Arquillian test framework (along with beloved JUnit and REST Assured). One real example is worth thousand words.

@RunWith(Arquillian.class) @EnableRandomWebServerPort public class PeopleApiTest < @ArquillianResource private URI uri; @Deployment public static JavaArchive createArchive() < return ShrinkWrap .create(JavaArchive.class) .addClasses(PeopleResource.class, PeopleApplication.class) .addClasses(PeopleServiceImpl.class, PeopleJpaRepository.class, PersistenceConfig.class) .addPackages(true, "org.apache.deltaspike"); >@Test public void shouldAddNewPerson() throws Exception < final Person person = new Person("a@b.com", "John", "Smith"); given() .contentType(ContentType.JSON) .body(person) .post(uri + "/api/people") .then() .assertThat() .statusCode(201) .body("email", equalTo("a@b.com")) .body("firstName", equalTo("John")) .body("lastName", equalTo("Smith")); >>

Amazing, isn’t it? It is actually a lot of fun to develop modern Java EE applications, someone may say, the Spring way! And in fact, the parallels with Spring are not coincidental since it was inspiring, is inspiring and undoubtedly is going to continue inspire a lot of innovations in the Java EE ecosystem.

How the future is looking like? I think, by all means bright, both for Jakarta EE and Eclipse Microprofile. The latter just approached the version 2.0 with tons of new specifications included, oriented to address the needs of the microservice architectures. It is awesome to witness these transformations happening.

The complete source of the project is available on Github.

Источник

Bruce Eckel’s Free Electronic Books

These are electronic books in HTML on C++ and Java, along with the source code. The HTML books are fully indexed, use Frames for easy navigation through the chapters, and have color syntax highlighting on all the source-code listings. Each HTML download contains an entire book and source code in a single zipped file.

Click here for public and on-site seminars based on the books below.

Note: Many of these documents require the installation of the fonts Georgia, Verdana and Andale Mono (code font) for proper viewing. These can be found here.

Thinking in C++, 2 nd edition, Volume 2 Revision 19 — August 23, 2003

Book in HTML + source-code tree and makefiles. Revision history at start of book.

Thinking in Enterprise Java Revision 1.1 — May 6, 2003

NOTE: book only, no source code. Described in Thinking in Java, 3 rd edition. Very early release; book is still in formative stages. Revision history at start of book.

Thinking in Patterns Revision 0.9 — May 20, 2003

Thinking in Java, 3rd Edition Revision 4.0 — November 20, 2002: Final Version to Printer
Download includes HTML book and source code

Thinking in C++, 2 nd edition, Volume 1 Revision 13 — Sept 27, 2001

Thinking in Java, 2 nd edition Revision 12 — June 12 2001
Word Version (May have more recent corrections than HTML version; see redline/strikeouts)

Thinking in Java, 1 st edition

Last Modified Sat Feb 5 2000

Источник

Think in enterprise java

Thinking in Enterprise Java

This is the book that has been spawned from some of the more advanced chapters formerly in Thinking in Java. This book isn’t a second volume of Thinking in Java, but rather focused coverage of the more advanced topic of enterprise programming. It is currently available (in some form) as a free download from www.BruceEckel.com. Because it is a separate book, it can expand to fit the necessary topics. The goal, like Thinking in Java, is to produce a very understandable introduction to the basics of the enterprise programming technologies so that the reader is prepared for more advanced coverage of those topics.

The list of topics will include, but is not limited to:

  • Introduction to Enterprise Programming
  • Network Programming with Sockets and Channels
  • Remote Method Invocation (RMI)
  • Connecting to Databases
  • Naming and directory services
  • Servlets
  • Java Server Pages
  • Tags, JSP Fragments and Expression Language
  • Automating the creation of user interfaces
  • Enterprise Java Beans
  • XML
  • Web Services
  • Automated Testing

You can find the current state of Thinking in Enterprise Java at www.BruceEckel.com.

Источник

Оцените статью