Apache DeltaSpike
repository·master·Indexed 41 days ago
https://github.com/apache/deltaspikeA suite of portable CDI (Contexts and Dependency Injection) Extensions that provide additional functionality such as configuration, messaging, and JPA repository patterns to applications running in a CDI-compliant environment. It is container-agnostic and supports various CDI specifications including JSR-299, JSR-346, JSR-365, and Jakarta CDI-3.0+. Key modules include Core, Data, JSF Integration, and a Java SE Plugin for bootstrapping containers like JBoss Weld or Apache OpenWebBeans.
What's inside DeltaSpike
- DeltaSpike Data is a module designed to provide data access abstractions. For detailed documentation, including specific API usage, configuration, and integration guides, please refer to the official DeltaSpike website.
Overview of Apache DeltaSpike Modules
masterApache DeltaSpike is composed of a mandatory Core module and several optional modules that provide enterprise functionality to CDI-based applications. To use DeltaSpike, you must include the Core module, and then add only the specific modules required for your application's needs (e.g., JPA for transactions, JSF for web integration, or Security for method-level interceptors).Overview of the DeltaSpike Data Module examples
masterThe Data Module examples demonstrate how to integrate JPA and repository patterns within a DeltaSpike application. Specifically, these examples cover:
- JPA Integration: How to use Java Persistence API (JPA) within the DeltaSpike ecosystem.
- Repository Pattern: How to utilize the DeltaSpike Data module to implement repositories for data access.
- Transaction Management: How the
@Transactionalannotation functions, including its ability to automatically save entities within a transactional context.
What is Apache DeltaSpike?
masterApache DeltaSpike is a suite of portable CDI (Contexts and Dependency Injection) Extensions designed to simplify application development when working with CDI and Java EE.
Important Distinction: Apache DeltaSpike is not a CDI container itself; it is a set of extensions that run inside a CDI container (such as JBoss Weld or Apache OpenWebBeans).
What is Apache DeltaSpike?
masterApache DeltaSpike is a collection of portable CDI (Contexts and Dependency Injection) extensions. It provides a core module and several optional modules that add enterprise functionality to Java projects. Because they are 'portable' extensions, they can be used with any spec-compliant CDI implementation, such as JBoss Weld or Apache OpenWebBeans.
Key capabilities include:
- Enhanced Security: Type-safe control over method invocations via annotations.
- Transaction Management: Support for transactions in non-EJB beans (including JTA and resource-local transactions).
- New CDI Scopes: Adds scopes like
TransactionScoped,WindowScoped,ViewScoped,ViewAccess, andGrouped conversation scope. - Java SE Support: Provides boot and shutdown control for CDI containers in Java SE environments.
- JSF Improvements: Multi-window handling, type-safe view configurations, and JSF event broadcasting to CDI.
- Productivity Tools: JMX integration for CDI beans, type-safe i18n messages, and a Data module for entity framework/JDBC support.
Overview of the DeltaSpike Data Module
masterThe Data module implements the Repository pattern to simplify the repository layer in Java applications. It reduces boilerplate code by allowing developers to define interfaces that automatically handle query logic.
Key capabilities include:
- Method Name Translation: Automatically generating queries from method names (e.g.,
findByAgeBetween). - JPQL Queries: Executing custom JPQL strings via annotations.
- Named Queries: Executing pre-defined JPA named queries.
- Automatic Implementation: The CDI extension provides the implementation at runtime, so clients only need to depend on the interface.
@Repository public interface PersonRepository extends EntityRepository<Person, Long> { List<Person> findByAgeBetweenAndGender(int minAge, int maxAge, Gender gender); @Query("select p from Person p where p.ssn = ?1") Person findBySSN(String ssn); @Query(named=Person.BY_FULL_NAME) Person findByFullName(String firstName, String lastName); }- Method Name Translation: Automatically generating queries from method names (e.g.,
Key Features of Apache DeltaSpike
masterDeltaSpike provides several modules and integrations to enhance CDI-based applications:
- Core Module: Provides component configuration, type-safe messaging, internationalization (i18n), and exception handling.
- Bean Lookup Utilities: Simplifies programmatic bean lookup.
- Java SE Plugin: Allows bootstrapping CDI containers (like JBoss Weld or Apache OpenWebBeans) in standalone Java SE environments.
- JSF Integration: Includes support for JSF, including backporting JSF 2.2 features for Java EE 6.
- JPA & Transaction Support: Provides integration for JPA and transaction management.
- Data Module: Implements an easy-to-use repository pattern on top of JPA.
- Scheduler Integration: Provides scheduling capabilities.
- Testing Support: Enables low-level unit testing of CDI-enabled projects.
How the Proxy Module works
masterThe Proxy Module provides a CDI-based wrapper for creating dynamic proxies. Unlike standard libraries like Javassist, DeltaSpike proxies are designed to execute CDI interceptors.
Key Features:
- Interceptor Support: Proxies can trigger CDI interceptors defined on the target object.
- Dynamic Registration: Through
DeltaSpikeProxyContextualLifecycle, you can dynamically register a proxy as a CDI bean using the DeltaSpikeBeanBuilder.
Important Limitation: Currently, CDI Interceptors applied via
@Interceptors,@Intercepted, or@Decoratorare not supported by these proxies.Configure Multi-Window Handling modes
masterDeltaSpike JSF module supports several modes for handling multiple browser windows/tabs to enable window-specific scopes:
- CLIENTWINDOW: Uses an intermediate
windowhandler.htmlpage to managewindowId. It covers most edge cases but may cause 'flickering'. - LAZY: Appends
windowIdto URLs. It avoids a loading screen but can lead to unintentional scope destruction if two tabs share awindowIdduring a lazy check. - NONE: Disables window detection. Scopes like
@WindowScopedor@ViewAccessScopedwill not work. - DELEGATED: Delegates handling to the JSF 2.2
ClientWindowAPI. - CUSTOM: Allows providing a custom
org.apache.deltaspike.jsf.spi.scope.window.ClientWindowimplementation.
To switch the mode, provide a
@Specializesimplementation ofJsfModuleConfigand overridegetDefaultWindowMode().@Specializes public class MyJsfModuleConfig extends JsfModuleConfig { @Override public ClientWindowConfig.ClientWindowRenderMode getDefaultWindowMode() { return ClientWindowConfig.ClientWindowRenderMode.LAZY; } }- CLIENTWINDOW: Uses an intermediate
How simple interceptor-style authorization works
masterThe Simple Interceptor-style API allows you to secure methods using a custom binding annotation. This approach loosely couples the secured method to a predicate method (the authorizer) using
@SecurityBindingType.Workflow:
- Create a binding annotation: Define an annotation annotated with
@SecurityBindingType. - Create an authorizer: Create a CDI bean with a method annotated with
@Securesand your custom binding annotation. This method returns abooleanindicating if access is granted. - Apply to methods/classes: Annotate your business methods or classes with the binding annotation.
Advanced Features:
- Parameter Binding: Use
@SecurityParameterBindingon a custom annotation to inject specific method arguments into your authorizer method. - Return Value Binding: Use
@SecuredReturnto perform authorization checks after the method has executed, based on its return value.
// 1. Create binding @SecurityBindingType public @interface UserLoggedIn {} // 2. Create authorizer @ApplicationScoped public class LoggedInAuthorizer { @Secures @UserLoggedIn public boolean doSecuredCheck(InvocationContext ctx, Identity identity) { return identity.isLoggedIn(); } } // 3. Secure method @UserLoggedIn public void doSomething() { ... } // Using Parameter Binding @SecurityParameterBinding public @interface CurrentThing {} @Secures @UserLoggedIn public boolean doSecuredCheck(..., @CurrentThing Thing thing) { return thing.hasMember(identity); }- Create a binding annotation: Define an annotation annotated with
Use Method Expressions for Query Generation
masterDeltaSpike Data can translate method names into JPQL queries. The method name must follow a specific pattern:
(Prefix)(Property)(Comparator).Supported Prefixes
findBy...(orfindOptionalBy,findAnyBy,findAll,findFirst,findTop)removeBy...(ordeleteBy)countBy...(returnsintorlong)
Supported Comparators
Name Args Description Equal1 Property equals value (default) EqualIgnoreCase1 Case-insensitive equality Like1 Uses %wildcard in argumentLikeIgnoreCase1 Case-insensitive like GreaterThan1 >LessThan1 <Between2 Between two values IsNull0 Property is null In1 Property in a Collection Containing1 Automatically wraps argument in %StartingWith1 Automatically adds %to endEndingWith1 Automatically adds %to startAdvanced Features
- Ordering: Use
OrderBy[Property][Asc|Desc](e.g.,findByLastNameOrderByAgeAsc). - Limits: Use
findFirst[N]orfindTop[N](e.g.,findTop20OrderByLastNameDesc). - Nested Properties: Use an underscore
_to traverse nested properties (e.g.,findByCompany_companyName). - Custom Prefixes: Change the prefix via
@Repository(methodPrefix = "...").
@Repository public interface PersonRepository extends EntityRepository<Person, Long> { // Complex query via name List<Person> findByNameLikeAndAgeBetweenAndGender(String name, int minAge, int maxAge, Gender gender); // Ordering and Limits List<Person> findTop2ByLastNameOrderByAgeAscLastNameDesc(String lastName); // Nested properties List<Person> findByCompany_companyName(String companyName); }How to define a Repository
masterA repository can be an abstract class or an interface marked with the
@Repositoryannotation. You must specify the entity it relates to using theforEntityattribute.Using Interfaces
Interfaces are the most common way to define repositories. You can extend base types like
EntityRepositoryto gain common CRUD operations.Using Abstract Classes
Use abstract classes if you need to implement custom logic using the
typedQuerymethod provided byAbstractEntityRepository.Note: Annotations on interfaces do not inherit. If you create a base interface with annotations, concrete implementations must re-apply them.
// Interface approach @Repository(forEntity = Person.class) public interface PersonRepository extends EntityRepository<Person, Long> { Person findBySsn(String ssn); } // Abstract class approach @Repository public abstract class PersonRepository extends AbstractEntityRepository<Person, Long> { public List<Person> findBySSN(String ssn) { return typedQuery("select p from Person p where p.ssn = ?1") .setParameter(1, ssn) .getResultList(); } }