0

我已经构建了一个 EJB 来管理我的数据库访问。我正在围绕它构建一个使用 Struts 2 的网络应用程序。

我遇到的问题是,当我部署耳朵时,EntityManager 没有注入到我的服务类中(并且最终为 null 并导致 NullPointerExceptions)。

奇怪的是,它适用于 JBoss 7.1.1,但不适用于 WebSphere 7。

您会注意到 Struts 不注入 EJB,所以我有一些拦截器代码可以做到这一点。我目前的工作理论是,WS7 容器由于某些未知原因而无法注入 EntityManager。我的下一步是尝试下一个 Spring,但如果可能的话,我真的很想让它工作。

我花了几天时间搜索和尝试各种事情,但没有任何运气。我想我会试一试。让我知道我是否可以提供更多信息。

<?xml version="1.0" encoding="UTF-8"?>
<persistence    xmlns="http://java.sun.com/xml/ns/persistence"
                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.0"
                xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
    <persistence-unit name="JPATestPU" transaction-type="JTA">
        <description>JPATest Persistence Unit</description>
        <jta-data-source>jdbc/Test-DS</jta-data-source>
        <class>org.jaredstevens.jpatest.db.entities.User</class>
        <properties>
            <property name="hibernate.hbm2ddl.auto" value="update"/>
        </properties>
    </persistence-unit>
</persistence>
package org.jaredstevens.jpatest.db.entities;

import java.io.Serializable;
import javax.persistence.*;

@Entity
@Table
public class User implements Serializable {
    private static final long serialVersionUID = -2643583108587251245L;

    private long id;
    private String name;
    private String email;

    @Id
    @GeneratedValue(strategy = GenerationType.TABLE)
    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    @Column(nullable=false)
    public String getName() {
        return this.name;
    }

    public void setName( String name ) {
        this.name = name;
    }

    @Column(nullable=false)
    public String getEmail() {
        return this.email;
    }

    @Column(nullable=false)
    public void setEmail( String email ) {
        this.email= email;
    }
}
package org.jaredstevens.jpatest.db.services;
import java.util.List;

import javax.ejb.Remote;
import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceContextType;
import javax.persistence.Query;

import org.jaredstevens.jpatest.db.entities.User;
import org.jaredstevens.jpatest.db.interfaces.IUserService;

@Stateless(name="UserService",mappedName="UserService")
@Remote
public class UserService implements IUserService {
    @PersistenceContext(unitName="JPATestPU",type=PersistenceContextType.TRANSACTION)
    private EntityManager em;

    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public User getUserById(long userId) {
        User retVal = null;
        if(userId > 0) {
            retVal = (User)this.getEm().find(User.class, userId);
        }
        return retVal;
    }

    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public List<User> getUsers() {
        List<User> retVal = null;
        String sql;
        sql = "SELECT u FROM User u ORDER BY u.id ASC";
        Query q = this.getEm().createQuery(sql);
        retVal = (List<User>)q.getResultList();
        return retVal;
    }

    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public void save(User user) {
        this.getEm().persist(user);
    }

    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public boolean remove(long userId) {
        boolean retVal = false;
        if(userId > 0) {
            User user = null;
            user = (User)this.getEm().find(User.class, userId);
            if(user != null) this.getEm().remove(user);
            if(this.getEm().find(User.class, userId) == null) retVal = true;
        }
        return retVal;
    }

    public EntityManager getEm() {
        return em;
    }

    public void setEm(EntityManager em) {
        this.em = em;
    }
}
package org.jaredstevens.jpatest.actions.user;

import javax.ejb.EJB;
import org.jaredstevens.jpatest.db.entities.User;
import org.jaredstevens.jpatest.db.interfaces.IUserService;

import com.opensymphony.xwork2.ActionSupport;

public class UserAction extends ActionSupport {
    @EJB(mappedName="UserService")
    private IUserService userService;

    private static final long serialVersionUID = 1L;
    private String userId;
    private String name;
    private String email;

    private User user;

    public String getUserById() {
        String retVal = ActionSupport.SUCCESS;
        this.setUser(userService.getUserById(Long.parseLong(this.userId)));
        return retVal;
    }

    public String save() {
        String retVal = ActionSupport.SUCCESS;
        User user = new User();
        if(this.getUserId() != null && Long.parseLong(this.getUserId()) > 0) user.setId(Long.parseLong(this.getUserId()));
        user.setName(this.getName());
        user.setEmail(this.getEmail());
        userService.save(user);
        this.setUser(user);
        return retVal;
    }

    public String getUserId() {
        return this.userId;
    }

    public void setUserId(String userId) {
        this.userId = userId;
    }

    public String getName() {
        return this.name;
    }

    public void setName( String name ) {
        this.name = name;
    }

    public String getEmail() {
        return this.email;
    }

    public void setEmail( String email ) {
        this.email = email;
    }

    public User getUser() {
        return this.user;
    }

    public void setUser(User user) {
        this.user = user;
    }
}
package org.jaredstevens.jpatest.utils;

import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.Interceptor;

public class EJBAnnotationProcessorInterceptor implements Interceptor {
    private static final long serialVersionUID = 1L;

    public void destroy() {
    }

    public void init() {
    }

    public String intercept(ActionInvocation ai) throws Exception {
        EJBAnnotationProcessor.process(ai.getAction());
        return ai.invoke();
    }
}
package org.jaredstevens.jpatest.utils; 

import java.lang.reflect.Field;

import javax.ejb.EJB;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

public class EJBAnnotationProcessor {
    public static void process(Object instance)throws Exception{
        Field[] fields = instance.getClass().getDeclaredFields();
        if(fields != null && fields.length > 0){
            EJB ejb;
            for(Field field : fields){
                ejb = field.getAnnotation(EJB.class);
                if(ejb != null){
                    field.setAccessible(true);
                    field.set(instance, EJBAnnotationProcessor.getEJB(ejb.mappedName()));
                }
            }
        }
    }

    private static Object getEJB(String mappedName) {
        Object retVal = null;
        String path = "";
        Context cxt = null;
        String[] paths = {"cell/nodes/virgoNode01/servers/server1/","java:module/"};
        for( int i=0; i < paths.length; ++i )
        {
            try {
                path = paths[i]+mappedName;
                cxt = new InitialContext();
                retVal = cxt.lookup(path);
                if(retVal != null) break;
            } catch (NamingException e) {
                retVal = null;
            }
        }
        return retVal;
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
    "http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>
    <constant name="struts.devMode" value="true" />

    <package name="basicstruts2" namespace="/diagnostics" extends="struts-default">
        <interceptors>
            <interceptor name="ejbAnnotationProcessor"
                class="org.jaredstevens.jpatest.utils.EJBAnnotationProcessorInterceptor"/>
            <interceptor-stack name="baseStack">
            <interceptor-ref name="defaultStack"/>
            <interceptor-ref name="ejbAnnotationProcessor"/>
            </interceptor-stack>
        </interceptors>
        <default-interceptor-ref name="baseStack"/>
    </package>

    <package name="restAPI" namespace="/conduit" extends="json-default">
        <interceptors>
            <interceptor name="ejbAnnotationProcessor"
                class="org.jaredstevens.jpatest.utils.EJBAnnotationProcessorInterceptor" />
            <interceptor-stack name="baseStack">
                <interceptor-ref name="defaultStack" />
                <interceptor-ref name="ejbAnnotationProcessor" />
            </interceptor-stack>
        </interceptors>
        <default-interceptor-ref name="baseStack" />

        <action name="UserAction.getUserById"
            class="org.jaredstevens.jpatest.actions.user.UserAction" method="getUserById">
            <result type="json">
                <param name="ignoreHierarchy">false</param>
                <param name="includeProperties">
                    ^user\.id,
                    ^user\.name,
                    ^user\.email
                </param>
            </result>
            <result name="error" type="json" />
        </action>

        <action name="UserAction.save"
            class="org.jaredstevens.jpatest.actions.user.UserAction" method="save">
            <result type="json">
                <param name="ignoreHierarchy">false</param>
                <param name="includeProperties">
                    ^user\.id,
                    ^user\.name,
                    ^user\.email
                </param>
            </result>
            <result name="error" type="json" />
        </action>
    </package>
</struts>

堆栈跟踪

java.lang.NullPointerException
    org.jaredstevens.jpatest.actions.user.UserAction.save(UserAction.java:38)
    sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:60)
    sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:37)
    java.lang.reflect.Method.invoke(Method.java:611)
    com.opensymphony.xwork2.DefaultActionInvocation.invokeAction(DefaultActionInvocation.java:453)
    com.opensymphony.xwork2.DefaultActionInvocation.invokeActionOnly(DefaultActionInvocation.java:292)
    com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:255)
    org.jaredstevens.jpatest.utils.EJBAnnotationProcessorInterceptor.intercept(EJBAnnotationProcessorInterceptor.java:21)
    com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
    org.apache.struts2.interceptor.debugging.DebuggingInterceptor.intercept(DebuggingInterceptor.java:256)
    com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
    com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor.doIntercept(DefaultWorkflowInterceptor.java:176)
    com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
    com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
    com.opensymphony.xwork2.validator.ValidationInterceptor.doIntercept(ValidationInterceptor.java:265)
    org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor.doIntercept(AnnotationValidationInterceptor.java:68)
    com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
    com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
    com.opensymphony.xwork2.interceptor.ConversionErrorInterceptor.intercept(ConversionErrorInterceptor.java:138)
    com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
    com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:211)
    com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
    com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
    com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:211)
    com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
    com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
    com.opensymphony.xwork2.interceptor.StaticParametersInterceptor.intercept(StaticParametersInterceptor.java:190)
    com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
    org.apache.struts2.interceptor.MultiselectInterceptor.intercept(MultiselectInterceptor.java:75)
    com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
    org.apache.struts2.interceptor.CheckboxInterceptor.intercept(CheckboxInterceptor.java:90)
    com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
    org.apache.struts2.interceptor.FileUploadInterceptor.intercept(FileUploadInterceptor.java:243)
    com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
    com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor.intercept(ModelDrivenInterceptor.java:100)
    com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
    com.opensymphony.xwork2.interceptor.ScopedModelDrivenInterceptor.intercept(ScopedModelDrivenInterceptor.java:141)
    com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
    com.opensymphony.xwork2.interceptor.ChainingInterceptor.intercept(ChainingInterceptor.java:145)
    com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
    com.opensymphony.xwork2.interceptor.PrepareInterceptor.doIntercept(PrepareInterceptor.java:171)
    com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
    com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
    com.opensymphony.xwork2.interceptor.I18nInterceptor.intercept(I18nInterceptor.java:176)
    com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
    org.apache.struts2.interceptor.ServletConfigInterceptor.intercept(ServletConfigInterceptor.java:164)
    com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
    com.opensymphony.xwork2.interceptor.AliasInterceptor.intercept(AliasInterceptor.java:192)
    com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
    com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor.intercept(ExceptionMappingInterceptor.java:187)
    com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
    org.apache.struts2.impl.StrutsActionProxy.execute(StrutsActionProxy.java:54)
    org.apache.struts2.dispatcher.Dispatcher.serviceAction(Dispatcher.java:511)
    org.apache.struts2.dispatcher.ng.ExecuteOperations.executeAction(ExecuteOperations.java:77)
    org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter.doFilter(StrutsPrepareAndExecuteFilter.java:91)
    com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:188)
    com.ibm.ws.webcontainer.filter.WebAppFilterChain.doFilter(WebAppFilterChain.java:116)
    com.ibm.ws.webcontainer.filter.WebAppFilterChain._doFilter(WebAppFilterChain.java:77)
    com.ibm.ws.webcontainer.filter.WebAppFilterManager.doFilter(WebAppFilterManager.java:908)
    com.ibm.ws.webcontainer.filter.WebAppFilterManager.invokeFilters(WebAppFilterManager.java:997)
    com.ibm.ws.webcontainer.extension.DefaultExtensionProcessor.invokeFilters(DefaultExtensionProcessor.java:1062)
    com.ibm.ws.webcontainer.extension.DefaultExtensionProcessor.handleRequest(DefaultExtensionProcessor.java:982)
    com.ibm.ws.webcontainer.webapp.WebApp.handleRequest(WebApp.java:3935)
    com.ibm.ws.webcontainer.webapp.WebGroup.handleRequest(WebGroup.java:276)
    com.ibm.ws.webcontainer.WebContainer.handleRequest(WebContainer.java:931)
    com.ibm.ws.webcontainer.WSWebContainer.handleRequest(WSWebContainer.java:1583)
    com.ibm.ws.webcontainer.channel.WCChannelLink.ready(WCChannelLink.java:186)
    com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.handleDiscrimination(HttpInboundLink.java:452)
    com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.handleNewRequest(HttpInboundLink.java:511)
    com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.processRequest(HttpInboundLink.java:305)
    com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.ready(HttpInboundLink.java:276)
    com.ibm.ws.tcp.channel.impl.NewConnectionInitialReadCallback.sendToDiscriminators(NewConnectionInitialReadCallback.java:214)
    com.ibm.ws.tcp.channel.impl.NewConnectionInitialReadCallback.complete(NewConnectionInitialReadCallback.java:113)
    com.ibm.ws.tcp.channel.impl.AioReadCompletionListener.futureCompleted(AioReadCompletionListener.java:165)
    com.ibm.io.async.AbstractAsyncFuture.invokeCallback(AbstractAsyncFuture.java:217)
    com.ibm.io.async.AsyncChannelFuture.fireCompletionActions(AsyncChannelFuture.java:161)
    com.ibm.io.async.AsyncFuture.completed(AsyncFuture.java:138)
    com.ibm.io.async.ResultHandler.complete(ResultHandler.java:204)
    com.ibm.io.async.ResultHandler.runEventProcessingLoop(ResultHandler.java:775)
    com.ibm.io.async.ResultHandler$2.run(ResultHandler.java:905)
    com.ibm.ws.util.ThreadPool$Worker.run(ThreadPool.java:1604)
4

2 回答 2

2

这里真正的问题是 EJB 没有注入。我的拦截器代码无法在 JNDI 中成功查找 EJB,并将我对它的本地引用设置为 null。一旦解决了这个问题,EntityManager 就会被注入,一切都会再次变得愉快。

对此的解决方案有两个:

  1. 我的拦截器类中的 JNDI 查找失败,因为我硬编码的路径对于我所在的服务器是错误的。
  2. WS7 配置需要应用程序的 EJB 设置中的别名,以便我的拦截器类可以找到正确的 EJB。

要修复#1 - 我修改了我的代码。我需要一个更好的解决方案,尽管这与服务器无关。

要修复#2:

  1. 登录控制台。(http://servername:9080/admin)
  2. 应用程序->应用程序类型->Websphere 企业应用程序。
  3. 单击您的应用程序名称(在我的例子中是 JPATestEAR)。
  4. 右侧有链接。单击“EJB JNDI 名称”(它应该列出所有 EJB)。
  5. 在右侧,有单选按钮和表单域,您可以在其中为每个 EJB 输入别名。我使用了“所有接口的 JNDI 名称”,并在“UserService”字段中输入了我的 EJB 名称。
  6. 单击“保存”,然后再次保存设置。

感谢@bkail 让我走上正轨。

于 2012-11-03T20:28:40.073 回答
0

如果您的应用程序被打包为 WAR,这可能解释了为什么它不能在 WS7 上运行。

正如 bkail 指出的那样,这可能是包装问题。

从 EE6 开始,您可以将本地 EJB bean 捆绑为您的 war 应用程序的一部分,但在 EE6 之前,您需要将其部署为 ear 并将 ejb 打包在 ejb-jar 中。

您可以尝试使用 Websphere 8+,它应该可以工作或将您的应用程序重新打包为带有 ejb-jar 模块和 war 模块的 ear。

于 2012-11-03T16:57:35.503 回答