【问题标题】:Inject a bean into EJB, which has been implemented in a different module - WAR将 bean 注入 EJB 中,该 bean 已在不同的模块 - WAR 中实现
【发布时间】:2017-06-10 22:35:27
【问题描述】:

我有以下结构:

EAR
|
| - EJB
| - WAR (servlet)
| - JAR (api)

JAR 包含几个接口和限定符。这些接口和限定符将用于其他模块 - WAR 和 EJB。

WAR 将 JAR 作为依赖项,并且类实现特定的接口。该类使用限定符进行注释。两者 - 接口和限定符都来自 JAR。

EJB 将 JAR 作为依赖项,我希望它能够注入 WAR 已实现的 bean。

但它不起作用。因错误而崩溃:

引起:org.jboss.weld.exceptions.WeldException:WELD-001602: 无法为 @com.api.QualifierWithParams()

同样,@com.api.QualifierWithParams() 来自已导入的 JAR。

我认为运行时不知道模块之间的 cdi bean?

现在我这样做的全部原因是因为 EJB 可以是 @Singleton,无论有多少 Servlet 实例都可以访问它。像缓存一样使用它。我想我可以复制一些代码,但不能。有什么办法吗?

编辑 - 我花了一些时间来精简代码,但这里是:

/*
EJB:

In maven this will have in its pom.xml's dependencies a dependency element for the JAR below.

*/

@Local
public interface EJBInterface {
    public String someBusinessMethod (String s);
}

@Singleton(name="EBJImplementation")
@javax.ejb.Startup
@Local(EJBInterface.class)
public class EBJImplementation implements EJBInterface{

    @javax.inject.Inject @com.api.QualifierWithParams(type=SomeType.PRIMARY, someQualifierParameter=15) InjectableBeanInterface b;

    @Override
    public String someBusinessMethod (String s){
        return s + " with param value of: " + Integer.parseInt(b.getParam());
    }

    /*
    @PostConstruct
    private void setUp(){

    }
    */
}

////////////////////////////////////////////

JAR:

package com.api;
public interface InjectableBeanInterface {

    public int getParam();
}

package com.api;
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
public @interface QualifierWithParams {
    SomeType type() default SomeType.PRIMARY; //just an enum to help  reduce annotation explosion

    @Nonbinding int someQualifierParameter() default 0;
}


////////////////////////////////////////////

/*
WAR:

Like the EJB, it will include JAR file as a dependency

*/

public class BeanImpl implements com.api.InjectableBeanInterface{

    private int someQualifierParameter;

    public BeanImpl (int p){
        someQualifierParameter = p;
    }

    @Override
    public int getParam(){return someQualifierParameter == null ? -1 : someQualifierParameter;}
}


public class InjectableBeanFactory {

    @Produces
    @com.api.QualifierWithParams(type=SomeType.PRIMARY)
    public com.api.InjectableBeanInterface productionFact(InjectionPoint ip){
        //get the parameter from the qualifier and create new instance
        Annotated a = ip.getAnnotated();
        com.api.QualifierWithParams qualifierParams = a.getAnnotation(com.api.QualifierWithParams.class);

        int tempParam = qualifierParams.someQualifierParameter();
        return new BeanImpl(tempParam);
    }
}

//Servlet. Configuration is done in the web.xml . This is the entry point of the application.
public class Main extends HttpServlet{

    private @EJB EJBInterface b;

    @Override
    protected void doGet(HttpServletRequest rq, HttpServletResponse rs) throws ServletException, IOException {

        Logger.getLogger("main-logger").log(Level.INFO, b.someBusinessMethod("called from servlet"));

        //...
    }
}

堆栈跟踪:

Failed to start service jboss.deployment.unit."test.ear".WeldStartService: org.jboss.msc.service.StartException in service jboss.deployment.unit."test".WeldStartService: Failed to start service
        at org.jboss.msc.service.ServiceControllerImpl$StartTask.run(ServiceControllerImpl.java:1904)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
        at java.lang.Thread.run(Thread.java:748)
Caused by: org.jboss.weld.exceptions.WeldException: WELD-001602: Cannot create qualifier instance model for @com.api.QualifierWithParams(type=PRIMARY, someQualifierParameter=15)
        at com.api.QualifierWithParams.type(QualifierWithParams.java:0)
  StackTrace:
        at org.jboss.weld.resolution.QualifierInstance.createValues(QualifierInstance.java:139)
        at org.jboss.weld.resolution.QualifierInstance.of(QualifierInstance.java:96)
        at org.jboss.weld.resolution.ResolvableBuilder.addQualifier(ResolvableBuilder.java:147)
        at org.jboss.weld.resolution.ResolvableBuilder.addQualifiers(ResolvableBuilder.java:197)
        at org.jboss.weld.resolution.ResolvableBuilder.<init>(ResolvableBuilder.java:83)
        at org.jboss.weld.manager.BeanManagerImpl.getBeans(BeanManagerImpl.java:567)
        at org.jboss.weld.bootstrap.Validator.validateInjectionPointForDeploymentProblems(Validator.java:357)
        at org.jboss.weld.bootstrap.Validator.validateInjectionPoint(Validator.java:281)
        at org.jboss.weld.bootstrap.Validator.validateGeneralBean(Validator.java:134)
        at org.jboss.weld.bootstrap.Validator.validateRIBean(Validator.java:155)
        at org.jboss.weld.bootstrap.Validator.validateBean(Validator.java:518)
        at org.jboss.weld.bootstrap.ConcurrentValidator$1.doWork(ConcurrentValidator.java:68)
        at org.jboss.weld.bootstrap.ConcurrentValidator$1.doWork(ConcurrentValidator.java:66)
        at org.jboss.weld.executor.IterativeWorkerTaskFactory$1.call(IterativeWorkerTaskFactory.java:63)
        at org.jboss.weld.executor.IterativeWorkerTaskFactory$1.call(IterativeWorkerTaskFactory.java:56)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
        at java.lang.Thread.run(Thread.java:748)
        at org.jboss.threads.JBossThread.run(JBossThread.java:320)
Caused by: java.lang.IllegalArgumentException: object is not an instance of declaring class
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.jboss.weld.resolution.QualifierInstance.createValues(QualifierInstance.java:137)
        ... 19 more

【问题讨论】:

  • 请显示代码
  • @NkosieMaphumulo OP 用代码编辑。
  • 您引用的异常是否有后续Caused by ...?如果是这样,请添加完整的堆栈跟踪
  • @SteveC 是的,有:“Caused by: java.lang.IllegalArgumentException: object is not an instance of declaring class”。使用堆栈跟踪更新了 OP。基本上它说它找不到对象,因为它是另一个模块中的另一个类?

标签: java jakarta-ee ejb cdi


【解决方案1】:

进一步的测试表明,如果我将它作为实例注入,它将起作用:

@Inject @Any javax.enterprise.inject.Instance<InjectableBeanInterface> d;

但是我必须手动添加限定符:

d.select(new QualifierWithParamsIMPL(SomeType.PRIMARY, 15)).get();

限定符(QualifierWithParams)本身必须手动实现:

public class QualifierWithParamsIMPL extends AnnotationLiteral<QualifierWithParams> implements QualifierWithParams {

    private final SomeType type;
    private final int someQualifierParameter;

    public CMSdbConnectionIMPL(SomeType type, int someQualifierParameter){
        this.type = type;
        this.someQualifierParameter = someQualifierParameter;
    }

    @Override
    public String type() {return type;}
    @Override
    public String someQualifierParameter() {return someQualifierParameter;}
}

但这不适用于 InjectionPoint,因此在 OP 中的代码中:

com.api.QualifierWithParams qualifierParams = a.getAnnotation(com.api.QualifierWithParams.class);

将为空...

所以我想我会寻找其他方法。我可能会用@ApplicationScoped CDI bean 代替@Singleton EJB。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-10-12
    • 2015-02-12
    • 1970-01-01
    • 2015-04-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多