IBM WAS 8.5.5.4:在不同 JAR 中具有接口和实现的 POJO 无法成功注入另一个 EJB jar 中的 EJB 3.1 bean
IBM WAS 8.5.5.4 : A POJO with interface and implementation in different JARs cannot be injected successfully inside an EJB 3.1 bean in another EJB jar
我正在开发 Java EE 6 应用程序,它必须在 JBoss WildFly 8.2.0 和 IBM WAS 8.5.5.4 中使用相同的 EAR 包工作。
应用程序结构非常简单。它基本上遵循以下一个:
耳朵
|__ /lib/
|____|__ API.jar
|____|__ IMPL.jar
|
|__ EJB.jar
|__ WebConsole.war
|____|__/库
|_______|__C.jar
在 EJB 模块中,我有一个 @Stateless 会话 bean 试图 @Inject 一个 POJO。
这里的特殊性在于 POJO 实现了一个位于 [API.jar] 中的接口,但实现位于 [IMPL.jar].
此外,POJO 实现用我们自己的 限定符 注释,即 @ServiceProvider. ,它只是定义为:
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD,ElementType.PARAMETER})
public @interface ServiceProvider {
}
EJB 如下所示(仅显示相关代码):
@Stateless
@Local(SecurityServiceLocal.class)
public class SecurityService implements SecurityServiceLocal {
@Inject @ServiceProvider
IServiceProvider serviceProvider;
...
}
POJO 接口(在 API.jar 内)如下所示:
public interface IServiceProvider {
public String sayHello();
}
POJO 实现(在 IMPL.jar 内)如下所示:
@Named
@ServiceProvider
public class ServiceProviderImpl implements IServiceProvider, Serializable {
private static final long serialVersionUID = -1L;
@Override
public String sayHello() {
return "Hello!";
}
[API.jar]、[IMPL.jar]甚至[EJB.jar] 有一个空 [/META-INF/beans.xml] 以启用 CDI。
使用@Produces的Factory在[IMPL.jar]中也可用,如下图:
public class ServiceFactory {
@Produces IServiceProvider getServiceProvider(@ServiceProvider IServiceProvider serviceProvider) {
return serviceProvider;
}
}
最后但同样重要的是,[EJB.jar] 引用了 [API.jar] 和 [IMPL.jar] 在 /META-INF/MANIFEST.MF Class-Path 属性.
现在,当 运行 这个示例应用程序在 WildFly 8.2.0.Final 中时,一切都按预期工作。用 @ServiceProvider 注释的 IServiceProvider 的实现被注入到 EJB 中。
或者换句话说,实现API.jar中接口的IMPL.jar中的POJO被注入到Stateless Session bean中EJB.jar
但是,当在 IBM WebSphere 8.5.5.4 中部署相同的应用程序时,注入失败并在启动期间显示以下消息:
javax.enterprise.inject.UnsatisfiedResolutionException:
Api type [dummy.IServiceProvider] is not found with the qualifiers
Qualifiers: [@dummy.qualifier.ServiceProvider()] for injection into Field Injection Point, field : dummy.IServiceProvider dummy.securityplugin.service.SecurityService.serviceProvider,
Bean Owner : [WSEjbBean [businessLocals=[interface dummy.securityplugin.service.SecurityServiceLocal],
ejbName=SecurityService-975208151,Name:null,WebBeans Type:ENTERPRISE,
API Types: [dummy.securityplugin.service.SecurityServiceLocal,java.lang.Object],
Qualifiers:[javax.enterprise.inject.Any,javax.enterprise.inject.Default]]
InjectionType : [interface dummy.IServiceProvider]
Annotated : [Annotated Field,Base Type : interface dummy.IServiceProvider,
Type Closures : [class java.lang.Object, interface dummy.IServiceProvider],
Annotations : [@dummy.qualifier.ServiceProvider(), @javax.inject.Inject()],
Java Member Name : serviceProvider]
Qualifiers : [[@dummy.qualifier.ServiceProvider()]]
IBM 知识中心有一个 link 提供了对此类异常的一些见解:
然而,据我所知,一切都配置正确(它在 WildFly 8 中运行!!)。
最后,我尝试其他方法:我 MOVE POJO 实现 FROM [IMPL.jar] 到 [EJB.jar] ... 而这次注入 WORKS 正如 中预期的那样WebSphere 8.5.5.4
因此看起来,如果要注入 EJB 的 POJO class 驻留在 SAME ejb 模块中,则完全没有问题。
但是,在我们最终的代码结构中,我们必须具有[API.jar]和[IMPL.jar]分别.
因此,最后一个问题:我做错了什么? IBM WebSphere 8.5.5.4(可能还有其他 8.x 版本)是否存在某种错误?我需要回忆一下,EJB 模块在 Class-Path Manifest 属性中引用了 API 和 IMPL jar。
非常感谢有关此主题的帮助...谢谢 !!!
最终我找到了根本原因。
罪魁祸首是 application.xml
由于我使用 Maven 生成带有 maven-ear-plugin 的 EAR 包,事实证明,如果我们没有明确指定 Java EE 版本为 6,则默认 application.xml 针对旧的 J2EE 1.3 系统。
WildFly 8 似乎忽略了这一点,并且一切正常。
但是,在 WebSphere 8.x 中,如果 application.xml 没有指定 version="6" ,Classpath 设置就完全乱了。
换句话说,maven-ear-plugin 必须包含 6 标签,如下所示:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-ear-plugin</artifactId>
<version>2.7</version>
<configuration>
<version>6</version>
...
要为 application.xml 正确生成正确的版本:
<xml version="1.0" encoding="UTF-8"?>
<application xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/application_6.xsd"
version="6">
我正在开发 Java EE 6 应用程序,它必须在 JBoss WildFly 8.2.0 和 IBM WAS 8.5.5.4 中使用相同的 EAR 包工作。
应用程序结构非常简单。它基本上遵循以下一个:
耳朵
|__ /lib/
|____|__ API.jar
|____|__ IMPL.jar
|
|__ EJB.jar
|__ WebConsole.war
|____|__/库
|_______|__C.jar
在 EJB 模块中,我有一个 @Stateless 会话 bean 试图 @Inject 一个 POJO。
这里的特殊性在于 POJO 实现了一个位于 [API.jar] 中的接口,但实现位于 [IMPL.jar].
此外,POJO 实现用我们自己的 限定符 注释,即 @ServiceProvider. ,它只是定义为:
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD,ElementType.PARAMETER})
public @interface ServiceProvider {
}
EJB 如下所示(仅显示相关代码):
@Stateless
@Local(SecurityServiceLocal.class)
public class SecurityService implements SecurityServiceLocal {
@Inject @ServiceProvider
IServiceProvider serviceProvider;
...
}
POJO 接口(在 API.jar 内)如下所示:
public interface IServiceProvider {
public String sayHello();
}
POJO 实现(在 IMPL.jar 内)如下所示:
@Named
@ServiceProvider
public class ServiceProviderImpl implements IServiceProvider, Serializable {
private static final long serialVersionUID = -1L;
@Override
public String sayHello() {
return "Hello!";
}
[API.jar]、[IMPL.jar]甚至[EJB.jar] 有一个空 [/META-INF/beans.xml] 以启用 CDI。
使用@Produces的Factory在[IMPL.jar]中也可用,如下图:
public class ServiceFactory {
@Produces IServiceProvider getServiceProvider(@ServiceProvider IServiceProvider serviceProvider) {
return serviceProvider;
}
}
最后但同样重要的是,[EJB.jar] 引用了 [API.jar] 和 [IMPL.jar] 在 /META-INF/MANIFEST.MF Class-Path 属性.
现在,当 运行 这个示例应用程序在 WildFly 8.2.0.Final 中时,一切都按预期工作。用 @ServiceProvider 注释的 IServiceProvider 的实现被注入到 EJB 中。
或者换句话说,实现API.jar中接口的IMPL.jar中的POJO被注入到Stateless Session bean中EJB.jar
但是,当在 IBM WebSphere 8.5.5.4 中部署相同的应用程序时,注入失败并在启动期间显示以下消息:
javax.enterprise.inject.UnsatisfiedResolutionException:
Api type [dummy.IServiceProvider] is not found with the qualifiers
Qualifiers: [@dummy.qualifier.ServiceProvider()] for injection into Field Injection Point, field : dummy.IServiceProvider dummy.securityplugin.service.SecurityService.serviceProvider,
Bean Owner : [WSEjbBean [businessLocals=[interface dummy.securityplugin.service.SecurityServiceLocal],
ejbName=SecurityService-975208151,Name:null,WebBeans Type:ENTERPRISE,
API Types: [dummy.securityplugin.service.SecurityServiceLocal,java.lang.Object],
Qualifiers:[javax.enterprise.inject.Any,javax.enterprise.inject.Default]]
InjectionType : [interface dummy.IServiceProvider]
Annotated : [Annotated Field,Base Type : interface dummy.IServiceProvider,
Type Closures : [class java.lang.Object, interface dummy.IServiceProvider],
Annotations : [@dummy.qualifier.ServiceProvider(), @javax.inject.Inject()],
Java Member Name : serviceProvider]
Qualifiers : [[@dummy.qualifier.ServiceProvider()]]
IBM 知识中心有一个 link 提供了对此类异常的一些见解:
然而,据我所知,一切都配置正确(它在 WildFly 8 中运行!!)。
最后,我尝试其他方法:我 MOVE POJO 实现 FROM [IMPL.jar] 到 [EJB.jar] ... 而这次注入 WORKS 正如 中预期的那样WebSphere 8.5.5.4
因此看起来,如果要注入 EJB 的 POJO class 驻留在 SAME ejb 模块中,则完全没有问题。
但是,在我们最终的代码结构中,我们必须具有[API.jar]和[IMPL.jar]分别.
因此,最后一个问题:我做错了什么? IBM WebSphere 8.5.5.4(可能还有其他 8.x 版本)是否存在某种错误?我需要回忆一下,EJB 模块在 Class-Path Manifest 属性中引用了 API 和 IMPL jar。
非常感谢有关此主题的帮助...谢谢 !!!
最终我找到了根本原因。 罪魁祸首是 application.xml
由于我使用 Maven 生成带有 maven-ear-plugin 的 EAR 包,事实证明,如果我们没有明确指定 Java EE 版本为 6,则默认 application.xml 针对旧的 J2EE 1.3 系统。
WildFly 8 似乎忽略了这一点,并且一切正常。 但是,在 WebSphere 8.x 中,如果 application.xml 没有指定 version="6" ,Classpath 设置就完全乱了。
换句话说,maven-ear-plugin 必须包含
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-ear-plugin</artifactId>
<version>2.7</version>
<configuration>
<version>6</version>
...
要为 application.xml 正确生成正确的版本:
<xml version="1.0" encoding="UTF-8"?>
<application xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/application_6.xsd"
version="6">