🏷 Enterprise (Jakarta EE)
16 patterns
Topic: Enterprise (Jakarta EE)
All Java patterns related to Enterprise (Jakarta EE) — java.evolved
Enterprise
EJB Timer vs Jakarta Scheduler
Old
@Stateless
public class ReportGenerator {
@Resource
TimerService timerService;
@PostConstruct
public void init() {
timerService.createCalendarTimer(
new ScheduleExpression()
.hour("2").minute("0"));
}
@Timeout
public void generateReport(Timer timer) {
// runs every day at 02:00
buildDailyReport();
}
}
Modern
@ApplicationScoped
public class ReportGenerator {
@Resource
ManagedScheduledExecutorService scheduler;
@PostConstruct
public void init() {
scheduler.scheduleAtFixedRate(
this::generateReport,
0, 24, TimeUnit.HOURS);
}
public void generateReport() {
buildDailyReport();
}
}
hover to see modern →
JDK 11+
learn more →
Enterprise
EJB versus CDI
Old
@Stateless
public class OrderEJB {
@EJB
private InventoryEJB inventory;
public void placeOrder(Order order) {
// container-managed transaction
inventory.reserve(order.getItem());
}
}
Modern
@ApplicationScoped
public class OrderService {
@Inject
private InventoryService inventory;
@Transactional
public void placeOrder(Order order) {
inventory.reserve(order.getItem());
}
}
hover to see modern →
JDK 11+
learn more →
Enterprise
JDBC ResultSet Mapping vs JPA Criteria API
Old
String sql = "SELECT * FROM users"
+ " WHERE status = ? AND age > ?";
try (Connection con = ds.getConnection();
PreparedStatement ps =
con.prepareStatement(sql)) {
ps.setString(1, status);
ps.setInt(2, minAge);
ResultSet rs = ps.executeQuery();
List<User> users = new ArrayList<>();
while (rs.next()) {
User u = new User();
u.setId(rs.getLong("id"));
u.setName(rs.getString("name"));
u.setAge(rs.getInt("age"));
users.add(u);
}
}
Modern
@PersistenceContext
EntityManager em;
public List<User> findActiveAboveAge(
String status, int minAge) {
var cb = em.getCriteriaBuilder();
var cq =
cb.createQuery(User.class);
var root = cq.from(User.class);
cq.select(root).where(
cb.equal(root.get("status"), status),
cb.greaterThan(root.get("age"), minAge));
return em.createQuery(cq).getResultList();
}
hover to see modern →
JDK 11+
learn more →
Enterprise
JDBC versus jOOQ
Old
String sql = "SELECT id, name, email FROM users "
+ "WHERE department = ? AND salary > ?";
try (Connection con = ds.getConnection();
PreparedStatement ps =
con.prepareStatement(sql)) {
ps.setString(1, department);
ps.setBigDecimal(2, minSalary);
ResultSet rs = ps.executeQuery();
List<User> result = new ArrayList<>();
while (rs.next()) {
result.add(new User(
rs.getLong("id"),
rs.getString("name"),
rs.getString("email")));
}
return result;
}
Modern
DSLContext dsl = DSL.using(ds, SQLDialect.POSTGRES);
return dsl
.select(USERS.ID, USERS.NAME, USERS.EMAIL)
.from(USERS)
.where(USERS.DEPARTMENT.eq(department)
.and(USERS.SALARY.gt(minSalary)))
.fetchInto(User.class);
hover to see modern →
JDK 11+
learn more →
Enterprise
JDBC versus JPA
Old
String sql = "SELECT * FROM users WHERE id = ?";
try (Connection con = dataSource.getConnection();
PreparedStatement ps =
con.prepareStatement(sql)) {
ps.setLong(1, id);
ResultSet rs = ps.executeQuery();
if (rs.next()) {
User u = new User();
u.setId(rs.getLong("id"));
u.setName(rs.getString("name"));
}
}
Modern
@PersistenceContext
EntityManager em;
public User findUser(Long id) {
return em.find(User.class, id);
}
public List<User> findByName(String name) {
return em.createQuery(
"SELECT u FROM User u WHERE u.name = :name",
User.class)
.setParameter("name", name)
.getResultList();
}
hover to see modern →
JDK 11+
learn more →
Enterprise
JNDI Lookup vs CDI Injection
Old
public class OrderService {
private DataSource ds;
public void init() throws NamingException {
InitialContext ctx = new InitialContext();
ds = (DataSource) ctx.lookup(
"java:comp/env/jdbc/OrderDB");
}
public List<Order> findAll()
throws SQLException {
try (Connection con = ds.getConnection()) {
// query orders
}
}
}
Modern
@ApplicationScoped
public class OrderService {
@Inject
@Resource(name = "jdbc/OrderDB")
DataSource ds;
public List<Order> findAll()
throws SQLException {
try (Connection con = ds.getConnection()) {
// query orders
}
}
}
hover to see modern →
JDK 11+
learn more →
Enterprise
JPA versus Jakarta Data
Old
@PersistenceContext
EntityManager em;
public User findById(Long id) {
return em.find(User.class, id);
}
public List<User> findByName(String name) {
return em.createQuery(
"SELECT u FROM User u WHERE u.name = :name",
User.class)
.setParameter("name", name)
.getResultList();
}
public void save(User user) {
em.persist(user);
}
Modern
@Repository
public interface Users extends CrudRepository<User, Long> {
List<User> findByName(String name);
}
hover to see modern →
JDK 21+
learn more →
Enterprise
JSF Managed Bean vs CDI Named Bean
Old
@ManagedBean
@SessionScoped
public class UserBean implements Serializable {
@ManagedProperty("#{userService}")
private UserService userService;
private String name;
public String getName() { return name; }
public void setName(String name) {
this.name = name;
}
public void setUserService(UserService svc) {
this.userService = svc;
}
}
Modern
@Named
@SessionScoped
public class UserBean implements Serializable {
@Inject
private UserService userService;
private String name;
public String getName() { return name; }
public void setName(String name) {
this.name = name;
}
}
hover to see modern →
JDK 11+
learn more →
Enterprise
Manual JPA Transaction vs Declarative @Transactional
Old
@PersistenceContext
EntityManager em;
public void transferFunds(Long from, Long to,
BigDecimal amount) {
EntityTransaction tx = em.getTransaction();
tx.begin();
try {
Account src = em.find(Account.class, from);
Account dst = em.find(Account.class, to);
src.debit(amount);
dst.credit(amount);
tx.commit();
} catch (Exception e) {
tx.rollback();
throw e;
}
}
Modern
@ApplicationScoped
public class AccountService {
@PersistenceContext
EntityManager em;
@Transactional
public void transferFunds(Long from, Long to,
BigDecimal amount) {
var src = em.find(Account.class, from);
var dst = em.find(Account.class, to);
src.debit(amount);
dst.credit(amount);
}
}
hover to see modern →
JDK 11+
learn more →
Enterprise
Message-Driven Bean vs Reactive Messaging
Old
@MessageDriven(activationConfig = {
@ActivationConfigProperty(
propertyName = "destinationType",
propertyValue = "jakarta.jms.Queue"),
@ActivationConfigProperty(
propertyName = "destination",
propertyValue = "java:/jms/OrderQueue")
})
public class OrderMDB implements MessageListener {
@Override
public void onMessage(Message message) {
TextMessage txt = (TextMessage) message;
processOrder(txt.getText());
}
}
Modern
@ApplicationScoped
public class OrderProcessor {
@Incoming("orders")
public void process(Order order) {
// automatically deserialized from
// the "orders" channel
fulfillOrder(order);
}
}
hover to see modern →
JDK 11+
learn more →
Enterprise
Servlet versus JAX-RS
Old
@WebServlet("/users")
public class UserServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req,
HttpServletResponse res)
throws ServletException, IOException {
String id = req.getParameter("id");
res.setContentType("application/json");
res.getWriter().write("{\"id\":\"" + id + "\"}");
}
}
Modern
@Path("/users")
public class UserResource {
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response getUser(
@QueryParam("id") String id) {
return Response.ok(new User(id)).build();
}
}
hover to see modern →
JDK 11+
learn more →
Enterprise
Singleton EJB vs CDI @ApplicationScoped
Old
@Singleton
@Startup
@ConcurrencyManagement(
ConcurrencyManagementType.CONTAINER)
public class ConfigCache {
private Map<String, String> cache;
@PostConstruct
public void load() {
cache = loadFromDatabase();
}
@Lock(LockType.READ)
public String get(String key) {
return cache.get(key);
}
@Lock(LockType.WRITE)
public void refresh() {
cache = loadFromDatabase();
}
}
Modern
@ApplicationScoped
public class ConfigCache {
private volatile Map<String, String> cache;
@PostConstruct
public void load() {
cache = loadFromDatabase();
}
public String get(String key) {
return cache.get(key);
}
public void refresh() {
cache = loadFromDatabase();
}
}
hover to see modern →
JDK 11+
learn more →
Enterprise
SOAP Web Services vs Jakarta REST
Old
@WebService
public class UserWebService {
@WebMethod
public UserResponse getUser(
@WebParam(name = "id") String id) {
User user = findUser(id);
UserResponse res = new UserResponse();
res.setId(user.getId());
res.setName(user.getName());
return res;
}
}
Modern
@Path("/users")
@Produces(MediaType.APPLICATION_JSON)
public class UserResource {
@Inject
UserService userService;
@GET
@Path("/{id}")
public User getUser(@PathParam("id") String id) {
return userService.findById(id);
}
}
hover to see modern →
JDK 11+
learn more →
Enterprise
Spring Framework 7 API Versioning
Old
// Version 1 controller
@RestController
@RequestMapping("/api/v1/products")
public class ProductControllerV1 {
@GetMapping("/{id}")
public ProductDtoV1 getProduct(
@PathVariable Long id) {
return service.getV1(id);
}
}
// Version 2 — duplicated structure
@RestController
@RequestMapping("/api/v2/products")
public class ProductControllerV2 {
@GetMapping("/{id}")
public ProductDtoV2 getProduct(
@PathVariable Long id) {
return service.getV2(id);
}
}
Modern
// Configure versioning once
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void configureApiVersioning(
ApiVersionConfigurer config) {
config.useRequestHeader("X-API-Version");
}
}
// Single controller, version per method
@RestController
@RequestMapping("/api/products")
public class ProductController {
@GetMapping(value = "/{id}", version = "1")
public ProductDtoV1 getV1(@PathVariable Long id) {
return service.getV1(id);
}
@GetMapping(value = "/{id}", version = "2")
public ProductDtoV2 getV2(@PathVariable Long id) {
return service.getV2(id);
}
}
hover to see modern →
JDK 17+
learn more →
Enterprise
Spring Null Safety with JSpecify
Old
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
public class UserService {
@Nullable
public User findById(@NonNull String id) {
return repository.findById(id).orElse(null);
}
@NonNull
public List<User> findAll() {
return repository.findAll();
}
@NonNull
public User save(@NonNull User user) {
return repository.save(user);
}
}
Modern
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
@NullMarked
public class UserService {
public @Nullable User findById(String id) {
return repository.findById(id).orElse(null);
}
public List<User> findAll() {
return repository.findAll();
}
public User save(User user) {
return repository.save(user);
}
}
hover to see modern →
JDK 17+
learn more →
Enterprise
Spring XML Bean Config vs Annotation-Driven
Old
<!-- applicationContext.xml -->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="userRepository"
class="com.example.UserRepository">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="userService"
class="com.example.UserService">
<property name="repository" ref="userRepository"/>
</bean>
</beans>
Modern
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
@Repository
public class UserRepository {
private final JdbcTemplate jdbc;
public UserRepository(JdbcTemplate jdbc) {
this.jdbc = jdbc;
}
}
@Service
public class UserService {
private final UserRepository repository;
public UserService(UserRepository repository) {
this.repository = repository;
}
}
hover to see modern →
JDK 17+
learn more →