Apache DeltaSpike

repository·master·Indexed 41 days ago

https://github.com/apache/deltaspike

A 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.

Tokens
46.6K
Snippets
126
Records
173
Agent score
99%

What's inside DeltaSpike

  1. Overview of Apache DeltaSpike Modules

    master
    Apache 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).
  2. Overview of the DeltaSpike Data Module examples

    master

    The Data Module examples demonstrate how to integrate JPA and repository patterns within a DeltaSpike application. Specifically, these examples cover:

    1. JPA Integration: How to use Java Persistence API (JPA) within the DeltaSpike ecosystem.
    2. Repository Pattern: How to utilize the DeltaSpike Data module to implement repositories for data access.
    3. Transaction Management: How the @Transactional annotation functions, including its ability to automatically save entities within a transactional context.
  3. What is Apache DeltaSpike?

    master

    Apache 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).

  4. What is Apache DeltaSpike?

    master

    Apache 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, and Grouped 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.
  5. Overview of the DeltaSpike Data Module

    master

    The 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);
    }
  6. Key Features of Apache DeltaSpike

    master

    DeltaSpike 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.
  7. How the Proxy Module works

    master

    The 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 DeltaSpike BeanBuilder.

    Important Limitation: Currently, CDI Interceptors applied via @Interceptors, @Intercepted, or @Decorator are not supported by these proxies.

  8. Configure Multi-Window Handling modes

    master

    DeltaSpike JSF module supports several modes for handling multiple browser windows/tabs to enable window-specific scopes:

    • CLIENTWINDOW: Uses an intermediate windowhandler.html page to manage windowId. It covers most edge cases but may cause 'flickering'.
    • LAZY: Appends windowId to URLs. It avoids a loading screen but can lead to unintentional scope destruction if two tabs share a windowId during a lazy check.
    • NONE: Disables window detection. Scopes like @WindowScoped or @ViewAccessScoped will not work.
    • DELEGATED: Delegates handling to the JSF 2.2 ClientWindow API.
    • CUSTOM: Allows providing a custom org.apache.deltaspike.jsf.spi.scope.window.ClientWindow implementation.

    To switch the mode, provide a @Specializes implementation of JsfModuleConfig and override getDefaultWindowMode().

    @Specializes
    public class MyJsfModuleConfig extends JsfModuleConfig
    {
        @Override
        public ClientWindowConfig.ClientWindowRenderMode getDefaultWindowMode()
        {
            return ClientWindowConfig.ClientWindowRenderMode.LAZY;
        }
    }
  9. How simple interceptor-style authorization works

    master

    The 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:

    1. Create a binding annotation: Define an annotation annotated with @SecurityBindingType.
    2. Create an authorizer: Create a CDI bean with a method annotated with @Secures and your custom binding annotation. This method returns a boolean indicating if access is granted.
    3. Apply to methods/classes: Annotate your business methods or classes with the binding annotation.

    Advanced Features:

    • Parameter Binding: Use @SecurityParameterBinding on a custom annotation to inject specific method arguments into your authorizer method.
    • Return Value Binding: Use @SecuredReturn to 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);
    }
  10. Use Method Expressions for Query Generation

    master

    DeltaSpike Data can translate method names into JPQL queries. The method name must follow a specific pattern: (Prefix)(Property)(Comparator).

    Supported Prefixes

    • findBy... (or findOptionalBy, findAnyBy, findAll, findFirst, findTop)
    • removeBy... (or deleteBy)
    • countBy... (returns int or long)

    Supported Comparators

    NameArgsDescription
    Equal1Property equals value (default)
    EqualIgnoreCase1Case-insensitive equality
    Like1Uses % wildcard in argument
    LikeIgnoreCase1Case-insensitive like
    GreaterThan1>
    LessThan1<
    Between2Between two values
    IsNull0Property is null
    In1Property in a Collection
    Containing1Automatically wraps argument in %
    StartingWith1Automatically adds % to end
    EndingWith1Automatically adds % to start

    Advanced Features

    • Ordering: Use OrderBy[Property][Asc|Desc] (e.g., findByLastNameOrderByAgeAsc).
    • Limits: Use findFirst[N] or findTop[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);
    }
  11. How to define a Repository

    master

    A repository can be an abstract class or an interface marked with the @Repository annotation. You must specify the entity it relates to using the forEntity attribute.

    Using Interfaces

    Interfaces are the most common way to define repositories. You can extend base types like EntityRepository to gain common CRUD operations.

    Using Abstract Classes

    Use abstract classes if you need to implement custom logic using the typedQuery method provided by AbstractEntityRepository.

    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();
        }
    }