
The author of the picture - Sabine Hurdler / Fotolia.com
Hi, Habr!
')
Once upon a time, in the hot summer of 2013, you and exactly you convinced us to start working on the wonderful book “
Learning Java EE 7 ” by Anthony Gonsalves, who withstood 6 draws and became a real bestseller. Now we seriously expect to begin work on a book on Java EE 8 from the competent and likeable expert
Sebastian Dashner before the end of the year.

November 7, Mr. Dashner published an article with his own reflections on the prospects and advantages of Java EE 8. Under the cat, you can read the translation of this article from German
What should you focus on when designing projects for large enterprises? What exactly is the "lightness" of the Java EE platform? How does Java EE support business concepts and subject-oriented design? How did this platform evolve? In which direction continues to evolve? This article briefly discusses the new features and the integration of Java into container environments.
Development: focus on enterprise projectsA key component of any Enterprise-programs - these are the functions that give a turnover of funds. The added value is acquired during the implementation of cases, the provision of business logic, to a lesser extent depends on how exactly the technical implementation is performed, or what technology is chosen for this. Thus, Enterprise-projects should be sharpened primarily for the implementation of practical scenarios.
The developer often sees this situation differently. He is interested in implementation details, quality, and also the beauty of technical solutions. The program is designed, discussed with colleagues, the code is processed and structured. Yes, all these are important aspects of software development - in any case, first of all we are interested in fulfilling customer requirements, and only then we have to spend time and effort on refining the code.
When an enterprise-engineer learns to see these problems from the point of view of the customer (giving money) and from the point of view of a project manager who has a budget laid out - much will become clearer.
Java Enterprise - first business logic!Therefore, we pay special attention to the implementation of business logic (domain logic). Only when logic is ready will narrower technical issues be addressed. Java Enterprise favors this approach. Subject areas - its essence - are first implemented in pure Java. Since we work in the enterprise sector, end-to-end functionalities, such as communication and data persistence, are very relevant to us. On modern Java EE, they are fully implemented declaratively, with almost minimal costs. In principle, on the Java EE platform, the principle of “configuration agreements” is in place, supporting this approach to programming.
Java specifications are added to our business logic (pure Java classes) with a few annotations. Then the business logic is easily verified using unit tests. Since almost all functionality is declared in annotations on modern Java EE, classes can be instantiated directly in tests — including without an enterprise container.
Java EE and domain-specific design (DDD)We implement the entry point of a specific case, the so-called facade, as an annotated Java class. In the terminology of subject-oriented design, it is customary to say that such a class represents a certain service. The following example shows a service implemented as an EJB:
@Stateless public class CarManufacturer { @Inject CarFactory carFactory; @PersistenceContext EntityManager entityManager; public Car manufactureCar(Specification spec) { Car car = carFactory.createCar(spec); entityManager.persist(car); return car; } }
The
CarFactory
class creates new
Car
entities according to the specifications. EntityManager manages the persistence of these entities in the database.
Thus, a concept known in the domain-oriented design as the “repository” pattern is presented. The EntityManager type offers a completely clear API. An additional facade, also referred to as DAO (data access object) used in the J2EE world, is no longer needed here.
When presenting business processes at the program level, they must first be implemented directly in the form of a facade, as a
CarManufacturer
in this case. If the methods and processes become too complicated, the functionality moves to the level of delegates, such as
CarFactory
in this case. Unit tests provide the right behavior — facades are instantiated in these tests, and delegates, respectively, are simulated as mock objects.
Domain classes, for example,
Car
, are at the same time POJO ("plain old Java object"), which can be supplied with annotations illustrating technically expedient functionality, for example, persistence:
@Entity @Table(name = "cars") public class Car { @Id @GeneratedValue private long id; @OneToOne(optional = false, cascade = CascadeType.ALL) private Engine engine; @OneToMany(cascade = CascadeType.ALL) private Set<Seat> seats = new HashSet<>();
In the subject-oriented design,
entities are understood as specific objects related to the subject area; these are the “root” objects of our application. JPA provides mapping of entities to the level of persistence with almost no additional costs - this is done using annotations. The annotation designation
@Entity
also fits harmoniously into the world of DDD. JPA requires
@Entity
be identified by
@Id
.
JPA also supports a concept called aggregate. So, continuing our example, in the car there are several seats. In our subject area, each seat can be identified. Save operations cascade from the root Car object to all its related Seat instances. Thus, we can request from the database for an existing identifier the whole machine, including all its constituent elements.
DDD factories that encapsulate the creation of relatively complex objects in methods or classes are implemented in the Java EE world, either in pure Java, where the methods are part of the subject area entities, or using CDI. As for CDI, their producer method (producer method) deserves special mention - it is very compact and useful. The following example first shows the factory, part of the “car” entity:
public class Car { ... public LogBook createDriverLog() {
In fact, it is advisable to pack factories primarily in cases where a certain entity must possess numerous properties in order to create specific objects. The following example shows
CarFactory
to create a derived
CarFactory
using CDI:
public class CarFactoryProducer { @Produces public CarFactory exposeCarFactory() { CarFactory factory = new BMWCarFactory();
As in the first example, an instance of
BMWCarFactory
can be implemented using the
CarFactory
type.
These examples show how lightweight the development approach is practiced in modern Java EE, without incurring significant technical costs. The focus is on business logic, which adapts to the technical requirements of the Enterprise application without any special costs.
Communication in Java EE: JAX-RS, JMS, WebSocket, and JSONServer endpoints with JAX-RS, JMS or WebSocket are other examples that illustrate how thin declarative APIs make life easier for a developer. In most application situations, the “configuration agreement” principle in Java EE is sufficient. In other cases, the behavior can be expanded programmatically.
JSON binding with JSON-B is another innovation introduced in Java EE 8. As with JAXB for XML, JSON-B allows you to declare Java classes declaratively to JSON and back. In Java EE 8, JSON-B seamlessly integrates with JAX-RS; JAX-RS Runtime delegates JSON mapping of reference types to JSON-B. Thus, classes of those types that are used in JAX-RS resources can define annotations. Without any additional configuration costs, these annotations are taken into account in HTTP requests and responses. The following example shows the
User
class, which is serializable with JSON-B:
public class User { @JsonbTransient private long id; @JsonbProperty("username") private String name; ... }
A JAX-RS resource representing the HTTP endpoint in this application case specifies the type
"User"
for the request or response body:
@Path("users") @Produces(MediaType.APPLICATION_JSON) public class UsersResource { @Inject UserStore userStore; @GET public List<User> getUsers() { return userStore.getUsers(); } }
JSON-B serialization picks up everything automatically: JSON-objects of the list of users transmitted via HTTP contain the
username
property and the
id
missing.
The declarative approach and interaction with the Java EE API is especially good for enterprise development, since in this area you always need to focus only on the most essential.
Java EE and applications with zero dependencies: working with Docker and KubernetesThe fact that the programmer needs to work as productively as possible is also reflected in the build and deployment model level. In Java EE applications, application is traditionally separated from implementation. Classes import only API - the implementation is provided by the Enterprise container. This approach allows you to minimize the time of assembly, delivery and deployment. At all stages of the continuous delivery pipeline, only the contents of the application are compiled, assembled and delivered - but not the implementation of the framework. The latter occurs already during the execution.
That is why Java EE is most profitably disclosed in the world of containers and orchestration, that is, in conjunction with Docker and Kubernetes. When the file system uses copy-on-write and separate caches at the levels of individual container images, the infrastructure performs only the most necessary operations. At each iteration, only the compiled classes of our application are delivered, but not the technological part. This approach is provided by so-called “zero-dependency applications” packaged in a WAR archive. At the same time, the application contains dependencies only with the scope
provided
.
The following example shows a Docker file containing the base GlassFish 5 image and a Java EE application. Potential dependencies of the application are not delivered to the deployable version, but appear only at earlier stages in the Docker file.
FROM oracle/glassfish:5.0
# provided-
COPY ...jar $GLASSFISH_HOME/glassfish/domains/domain1/lib/ext/
COPY target/cars.war $GLASSFISH_HOME/glassfish/domains/domain1/autodeploy
The resulting Docker image at startup automatically executes our application.
Thanks to applications with zero dependencies, as well as these elements from the Docker file, the concept of “copy-on-write” is implemented, which significantly speeds up the entire continuous delivery pipeline. If neither the runtime environment nor the dependencies that exist between several assemblies (as is usually the case), then only the classes of our application in the
cars.war
archive are packed and forwarded.
As a rule, Enterprise projects often had to deal at least in part with the complexities, versions and configurations of application servers. There are many applications on the servers, which complicates the deployment, configuration and new installation operations, and in some cases also requires coordination. Such a problem is solved with the help of containers like Docker. Because the container contains everything that is needed to run and configure an application — including runtime and configuration — the choice of technology does not depend on other applications. Upgrading versions, for example, switching from Java EE 7 to Java EE 8 is not so cumbersome and risky. Therefore, the deployed version does not have to deliver the entire stack and megabytes of dependencies - all of this is included in the composition of the corresponding basic images.
Java EE 8 and onwardsSo, in Java EE 8, there are new features, among which the most noticeable is the new JSON-B standard, which greatly simplifies enterprise development. In the past, frameworks for displaying JSON, for example, Jackson, were responsible for resolving version conflicts between third-party dependencies and, in particular, their transitive dependencies and application server libraries. To resolve conflicts took time and resources. With Java EE 8, you can do without all these extra costs.
In addition to JSON-B, another new standard was introduced - the Security API, which provides security, and some older APIs were updated: CDI, JSON-P, Bean Validation, JPA, Servlet, and JSF. In addition, I would like to highlight such innovations as Server-Sent events, reactive clients in JAX-RS, new JSON-P 1.1 features. and Bean Validation 2.0, as well as numerous improvements in the integration of various standards. The direction in which Java EE APIs have developed in recent months and years is very optimistic from the developers' point of view, and after the Java EE platform is transferred to the Eclipse Foundation (meet Eclipse Enterprise for Java (EE4J)), further development of Java EE should go into a more open mode and probably speed up.
TotalModern Java EE allows the programmer to focus on the most important application aspects and minimize technical costs. Because ready-to-deploy versions are as compact as possible, Java EE now integrates optimally with container environments — for example, Docker, Kubernetes, or OpenShift.