为什么EJB bean方法未被检测到,如果它是封装私有的?

问题描述:

这一个令我困惑。我创建了一个基于在Wildfly 10.1上运行的JavaEE7的最小JAX-RS应用程序。为什么EJB bean方法未被检测到,如果它是封装私有的?

@ApplicationPath("") 
public class JAXRSConfiguration extends Application { 

    @Override 
    public Set<Class<?>> getClasses() { 
     return new HashSet<Class<?>>(Arrays.asList(Resource.class)); 
    } 
} 

资源注入一个单独的虚拟无状态的bean:

@Path("") 
public class Resource { 

    @Inject 
    Manager manager; 

    @GET 
    @Path("/go") 
    public void go() { 
     manager.call(); 
    } 
} 

这是豆:

@Stateless 
public class Manager { 

    @PostConstruct 
    private void init() { 
     System.out.println("POST CONSTRUCT "); 
    } 

    void call() { 
     System.out.println("called "); 
    } 
} 

使用浏览器来执行GET导致以下错误:

org.jboss.resteasy.spi.UnhandledException: org.jboss.weld.exceptions.WeldException: Class org.jboss.weld.util.reflection.Reflections can not access a member of class com.a.b.Manager with modifiers "" 

Can pos t完整的堆栈跟踪,但所有引起的消息都是相同的。

我搜索了这个错误,当注入的bean是而不是 public,但是我的是。我决定尝试删除公众,看看它会抱怨什么,以及......它的工作原理。注入bean,注入任何注入,调用post构造方法,打印所有打印。

这与Does ejb stateless class has to be public?完全相反。这里发生了什么?

更新

Oliv37促使我做一些测试,下面是调查结果:

  • 如果callpackage,则只有当Managerpackage工作。
  • 如果callpublic,它无论如何工作。
  • 如果callfinal,则只有在Managerpackage时才会调用@PostConstruct方法。

现在问题变成了:为什么该方法需要公开以便CDI检测工作以及为什么使其最终导致post构造方法在类为公共时不会被调用?

UPDATE2

完整的堆栈跟踪:

org.jboss.resteasy.spi.UnhandledException: org.jboss.weld.exceptions.WeldException: Class org.jboss.weld.util.reflection.Reflections can not access a member of class com.a.b.Manager with modifiers "" 
    at org.jboss.resteasy.core.ExceptionHandler.handleApplicationException(ExceptionHandler.java:77) 
    at org.jboss.resteasy.core.ExceptionHandler.handleException(ExceptionHandler.java:220) 
    at org.jboss.resteasy.core.SynchronousDispatcher.writeException(SynchronousDispatcher.java:175) 
    at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:418) 
    at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:209) 
    at org.jboss.resteasy.plugins.server.servlet.ServletContainerDispatcher.service(ServletContainerDispatcher.java:221) 
    at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:56) 
    at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:51) 
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:790) 
    at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:85) 
    at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62) 
    at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36) 
    at org.wildfly.extension.undertow.security.SecurityContextAssociationHandler.handleRequest(SecurityContextAssociationHandler.java:78) 
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43) 
    at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:131) 
    at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57) 
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43) 
    at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46) 
    at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64) 
    at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:60) 
    at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:77) 
    at io.undertow.security.handlers.NotificationReceiverHandler.handleRequest(NotificationReceiverHandler.java:50) 
    at io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43) 
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43) 
    at org.wildfly.extension.undertow.security.jacc.JACCContextIdHandler.handleRequest(JACCContextIdHandler.java:61) 
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43) 
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43) 
    at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:292) 
    at io.undertow.servlet.handlers.ServletInitialHandler.access$100(ServletInitialHandler.java:81) 
    at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:138) 
    at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:135) 
    at io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:48) 
    at io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43) 
    at io.undertow.servlet.api.LegacyThreadSetupActionWrapper$1.call(LegacyThreadSetupActionWrapper.java:44) 
    at io.undertow.servlet.api.LegacyThreadSetupActionWrapper$1.call(LegacyThreadSetupActionWrapper.java:44) 
    at io.undertow.servlet.api.LegacyThreadSetupActionWrapper$1.call(LegacyThreadSetupActionWrapper.java:44) 
    at io.undertow.servlet.api.LegacyThreadSetupActionWrapper$1.call(LegacyThreadSetupActionWrapper.java:44) 
    at io.undertow.servlet.api.LegacyThreadSetupActionWrapper$1.call(LegacyThreadSetupActionWrapper.java:44) 
    at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:272) 
    at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:81) 
    at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:104) 
    at io.undertow.server.Connectors.executeRootHandler(Connectors.java:202) 
    at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:805) 
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) 
    at java.lang.Thread.run(Thread.java:748) 
Caused by: org.jboss.weld.exceptions.WeldException: Class org.jboss.weld.util.reflection.Reflections can not access a member of class com.a.b.Manager with modifiers "" 
    at org.jboss.weld.util.reflection.Reflections.invokeAndUnwrap(Reflections.java:437) 
    at org.jboss.weld.bean.proxy.EnterpriseBeanProxyMethodHandler.invoke(EnterpriseBeanProxyMethodHandler.java:128) 
    at org.jboss.weld.bean.proxy.EnterpriseTargetBeanInstance.invoke(EnterpriseTargetBeanInstance.java:56) 
    at org.jboss.weld.bean.proxy.InjectionPointPropagatingEnterpriseTargetBeanInstance.invoke(InjectionPointPropagatingEnterpriseTargetBeanInstance.java:67) 
    at org.jboss.weld.bean.proxy.ProxyMethodHandler.invoke(ProxyMethodHandler.java:100) 
    at com.a.b.Manager$Proxy$_$$_Weld$EnterpriseProxy$.call(Unknown Source) 
    at com.airhacks.boundary.Resource.go(Resource.java:16) 
    at com.airhacks.boundary.Resource$Proxy$_$$_WeldClientProxy.go(Unknown Source) 
    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.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:139) 
    at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java:295) 
    at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:249) 
    at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:236) 
    at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:402) 
    ... 42 more 
Caused by: java.lang.IllegalAccessException: Class org.jboss.weld.util.reflection.Reflections can not access a member of class com.a.b.Manager with modifiers "" 
    at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:102) 
    at java.lang.reflect.AccessibleObject.slowCheckMemberAccess(AccessibleObject.java:296) 
    at java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:288) 
    at java.lang.reflect.Method.invoke(Method.java:491) 
    at org.jboss.weld.util.reflection.Reflections.invokeAndUnwrap(Reflections.java:433) 
    ... 58 more 
+0

关于该类不公开的一个评论,它的工作原理:正如你的链接问题中的一个评论所说:它在你的环境中与你选择的容器一起工作,但不能保证在每个EE容器中工作,因为它是没有被规范定义。 – dunni

+0

@dunni好的,但如果这是规范,为什么它不与公众一起工作?我明白,如果我做的东西不在规范中,它可能工作,可能不会,但如果我在规范中做事情,他们必须工作... – Mark

+1

哼,你是否尝试为方法'调用'添加'public'修饰符在'经理'类里面? –

简短的回答是 - 让你call方法public

较长的一个是这样的 - 这里的问题是你的call方法受封装保护。因此到EJB规范,章会话Bean的无接口视图(从3.1 EJB规范引用):

Only public methods of the bean class (and any super-classes) may be invoked through the no-interface view. Attempted invocations of methods with any other access modifiers via the no-interface view reference must result in a javax.ejb.EJBException .

通过采用非公修改你违反了规范和事实,即在不引发EJBException可要么在WFLY中忽略EJB impl,要么忽略一个特性。不管怎样,你都处于灰色未指定的区域。

现在至于焊接 - 它试图使用反射来访问该方法并调用它,deliberately not making it accessible prior to invocation。这是显而易见的地方,因为您无法绕过它而访问其他方法(使用Method.setAccessible())。

至于你的问题final方法和@PostConstruct没有被调用 - 你打破了另一个EJB规则。这一个是4.9.8 Session Bean’s No-Interface View和破折号一个有说:

Only private methods of the bean class and any superclasses except java.lang.Object may be declared final .

我不能说为什么没有异常,但是这是你头痛的原因。至于为什么这个规则存在 - 正如我在评论中所述,Weld需要创建代理,并且如果该方法不能被覆盖,则不可能在@PostConstruct中编织并拦截它。

希望这回答您的查询。

+0

也创建[WFLY问题](https://issues.jboss.org/browse/WFLY-9425)来检查这种行为 - 事实证明它会抛出正确的异常(调用非公共EJB方法 - 请参阅我在该问题中的评论),但焊接速度更快,并且在IllegalAccess反射问题上失败 - 这可能(应该)在焊接方面得到改进。 – Siliarus

+0

最后一个修饰符会不会调用post构造呢? – Mark

+0

Uf,与我们在这里整理的内容相比,这是完全不同的问题。我想这个问题会出现在Weld创建bean的代理对象 - 但是根据CDI规范,这不适用于最终方法。但是,真的,这个问题应该得到一个单独的“线程”,您可以在其中指定其失败的具体部署方案。在这里,它与所有选项都纠结在一起。 – Siliarus