简体   繁体   中英

Cannot inject dependencies when executing Hibernate Interceptor - Wildfly/CDI

I'm implementing an EmptyInterceptor from Hibernate to audit the DB changes.

The problem is that all dependencies injected (@Inject) are null , inside the Interceptor and inside any other class that gets instantiated with new() operator when inside the interceptor execution.

I saw another question with the same problem, but using Spring framework that has a workaround by making the interceptor a bean and then the CDI can injects all dependencies to it.

I want to use my DAO's and entity manager to persist these new audit entities, is there a way to make WELD/CDI inject my dependencies inside the Interceptor?

Using Wildfly 17, CDI 2.0

HistoricoInterceptor

@Interceptor
@Historico
public class HistoricoInterceptor extends EmptyInterceptor {
private static final long serialVersionUID = 6271759158996755175L;

@Inject
@Any
private Instance<HistoricoInterceptadorI> historicoInterceptadorI;

@Inject
private RequestQueryParamExtractor requestQueryParamExtractor;

@Override
public boolean onSave(Object entity, Serializable id, Object[] state, String[] 
propertyNames,
        Type[] types) {}

beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
    http://xmlns.jcp.org/xml/ns/javaee 
    http://xmlns.jcp.org/xml/ns/javaee/beans_2_0.xsd"
version="2.0" bean-discovery-mode="all">
<interceptors <class>br.com.procempa.tesouro.pessoaapi.util.interceptor.HistoricoInterceptor</class>
    </interceptors>

RequestQueryParamExtractor

@RequestScoped
public class RequestQueryParamExtractor {
private static final String LOTACAO_PARAM = "lotacaoId";
private static final String LOGIN_PARAM = "nomeLogin";

@Inject
private HttpServletRequest httpServletRequest;

public Optional<String> getLotacaoId() {
    String lotacaoId = httpServletRequest.getParameter(LOTACAO_PARAM);
    
    return Optional.ofNullable(lotacaoId);
}

public Optional<String> getNomeLogin() {
    String nomeLogin = httpServletRequest.getParameter(LOGIN_PARAM);
    
    return Optional.ofNullable(nomeLogin);
}
}

persistence.xml

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0"
xmlns="http://java.sun.com/xml/ns/persistence" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
    http://java.sun.com/xml/ns/persistence
    http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="primary">
    <jta-data-source>java:jboss/datasources/pessoaDSHom</jta-data-source>
    <properties>
        <!-- Properties for Hibernate -->
        <property name="hibernate.dialect" 
value="org.hibernate.dialect.Oracle10gDialect" />
        <property name="hibernate.hbm2ddl.auto" value="validate" />
        <property name="hibernate.SQL" value="DEBUG"/>
        <property name="hibernate.show_sql" value="false" />
        <property name="hibernate.default_schema" value="poasiat" />
        <property name="hibernate.jpa.compliance.global_id_generators" 
value="false"/>
        <property name="hibernate.session_factory.interceptor" 
value="br.com.procempa.tesouro.pessoaapi.util.interceptor.HistoricoInterceptor"/>
    </properties>
</persistence-unit>
</persistence>

The interceptor is a Hibernate interceptor, not a CDI one. This is not wrong, just note that the name "interceptor" is overloaded in this context (CDI uses interceptors with different FQCN as well).

Now, from CDI perspective, Hibernate interceptor is a non-contextual object and as such will not be handled by CDI. That means, among other things, no injection.

You could workaround this by performing a dynamic resolution to get hold of your beans:

// invoke this from within a method where you want to use that bean
Instance<Object> instance = CDI.current().getBeanManager().createInstance();
RequestQueryParamExtractor rqpe = instance.select(RequestQueryParamExtractor.class).get();

This OFC presumes that the class you are resolving is a known bean.

Last but not least, if you resolve any @Dependent scoped beans in this manner, you are responsible for their destruction as well. Once done working with them, you should dispose of them by calling Instance.destroy(beanInstance) . There is no need to perform this for normal-scoped beans (such as the instance of RequestQueryParamExtractor that your code shows). This is to prevent memory leaks because you are performing dynamic resolution in a non-contextual object whose life span is no controlled by CDI. Therefore, resolved dependent instances might linger there.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM