-2

私はTomcat 6.0.26-6.0.35をJSF 2 Mojarraで数年間使用しており、2.1.2までのさまざまなバージョンを数か月使用しています。次のようなコードを含む、リクエストスコープおよびセッションスコープの Bean がいくつかあります。

private @Resource(name="jdbc/cLabs", mappedName="jdbc/cLabs") DataSource cLabs;

これは、私が使用した Tomcat 6 のすべてのバージョンに正しく挿入されています。私は他のタイプの@Resourceどちらも機能しないため、DataSource resources.Tomcat 7.0.27 に切り替えようとしただけでなく、突然これらの構成要素が機能しなくなりました。リソースは注入されません。他のタイプの@Resourceも動作しないものがあるので、単なるDataSourceリソースではありません。ただし、いずれの場合も、指定されたリソースは存在し、たとえば次の方法で検索できます

new InitialContext().lookup("java:comp/env/jdbc/cLabs");

[context.xml の要素によって定義されます]

もちろん、これは王室の PITA であり、私は 1 年か 2 年ほど前に後者を前者に置き換えました。Tomcat 7を再び機能させるために織り込まなければならない魔法の呪文は他にありますか?

リソースサーブレットに正しく注入されるため、完全に壊れているわけではないことに注意してください。Tomcat と JSF の間の対話。

4

4 に答える 4

3

顔は @Resource フィールドとは別に @PostConstruct メソッドを処理する必要があるため、何かが org.apache.catalina.core.DefaultInstanceManager に注釈を無視させていると思います。@Resource で注釈が付けられたフィールドで機能する回避策を作成しました。

以下を web.xml に追加します。

<context-param>
    <param-name>com.sun.faces.injectionProvider</param-name>
    <param-value>com.example.faces.Tomcat7InjectionProvider</param-value>
</context-param>

クラスをソースに追加します。

package com.example.faces;

import java.lang.reflect.Field;

import javax.annotation.Resource;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.servlet.ServletContext;

import org.apache.catalina.util.Introspection;

import com.sun.faces.spi.InjectionProviderException;
import com.sun.faces.vendor.WebContainerInjectionProvider;

public class Tomcat7InjectionProvider extends WebContainerInjectionProvider {

    public Tomcat7InjectionProvider(ServletContext servletContext) {
    }

    @Override
    public void inject(Object managedBean) throws InjectionProviderException {
        if (managedBean != null) {
            // see org.apache.catalina.core.DefaultInstanceManager
            Field[] fields = Introspection.getDeclaredFields(managedBean.getClass());
            for (Field field : fields) {
                // field may be private
                field.setAccessible(true);
                if (field.isAnnotationPresent(Resource.class)) {
                    Resource annotation = null;
                    try {
                        annotation = field.getAnnotation(Resource.class);
                        Context ctx = new InitialContext();
                        Object resource = ctx.lookup("java:comp/env/" + annotation.name());
                        field.set(managedBean, resource);
                    } catch (Exception e) {
                        throw new InjectionProviderException("cannot find resource " + annotation.name(), e);
                    }
                }
            }
        }
    }
}
于 2014-02-24T03:52:30.063 に答える
2

@JeffEの回答の改良版である、私自身の質問に答えます。基本的な問題は次のとおりです。

  1. ATomcat6InjectionProviderは JSF 2.0 で提供されていましたが、ある時点で削除されました。
  2. WebContainerInjectionProviderJeffE が指摘しているように、デフォルトでは @Resource アノテーションは処理されません。

web.xml次のように、コンテキストエントリなしでこれを克服できます。

  1. というファイルを作成しMETA-INF/services/com.sun.faces.spi.injectionprovider、次の行を追加します。

    com.sun.faces.vendor.Tomcat7InjectionProvider:org.apache.catalina.core.DefaultInstanceManager
    

    この行の意味は、展開に 2 番目のクラスが存在する場合、最初のクラスがインジェクション プロバイダーとして使用されるということです。上記の 2 番目のクラスは、Tomcat 7 の一部です。

  2. 次のクラスをコンパイルします。

このバージョンには、JeffE のバージョンに対する多数の改善が含まれています。具体的には:

  • @Resourceおよび@ResourcesJavadocの必要に応じて、スーパークラスを処理します。
  • クラスレベルでの処理@Resourceと注釈@Resources
  • Javadoc@Resourceの要求に応じて、 で注釈が付けられたメソッドを処理します。@Resource
  • Javadocで要求されているように、s の空または欠落したname属性を@Resource正しく処理します。@Resource
  • Fieldの元のアクセスを復元します
  • Tomcat クラスには依存しません。

パッケージ名を変更する場合は、上記のパッケージ名を調整してください。

package com.sun.faces.vendor;

import com.sun.faces.spi.DiscoverableInjectionProvider;
import com.sun.faces.spi.InjectionProviderException;
import java.lang.reflect.Field;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.Resource;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletContext;

/**
 * @author Jeff E
 * @author Esmond Pitt Improvements named above.
 * 
 * @see javax.annotation.Resource
 *
 * @see <a href="http://stackoverflow.com/a/21978577/207421">This StackOverflow
 * answer, although what org.apache.catalina.util.Introspection may be and where
 * it lives remains a mystery.</a>
 */
public class Tomcat7InjectionProvider
    extends DiscoverableInjectionProvider
{
    private Logger logger = Logger.getLogger(this.getClass().getName());
    private ServletContext  servletContext;

    private WebContainerInjectionProvider   delegate = new WebContainerInjectionProvider();

    public Tomcat7InjectionProvider(ServletContext servletContext)
    {
        logger.config("constructed");
        this.servletContext = servletContext;
    }

    @Override
    public void inject(Object managedBean) throws InjectionProviderException
    {
        logger.log(Level.CONFIG, "managedBean={0}", new Object[]{managedBean.getClass().getName()});
        Class<?> clazz = managedBean.getClass();
        do
        {
            List<Resource>  classResources = new LinkedList<>();
            // Process class-level @Resources and @Resource
            if (clazz.isAnnotationPresent(Resources.class))
            {
                Resources annotation = clazz.getAnnotation(Resources.class);
                for (Resource resource : annotation.value())
                {
                    classResources.add(resource);
                }
            }
            if (clazz.isAnnotationPresent(Resource.class))
            {
                Resource    annotation = clazz.getAnnotation(Resource.class);
                classResources.add(annotation);
            }
            for (Resource annotation : classResources)
            {
                String  name = annotation.name();
                // Make sure the resource exists.
                try
                {
                    Context ctx = new InitialContext();
                    Object resource = ctx.lookup("java:comp/env/" + name);
                }
                catch (NamingException exc)
                {
                    throw new InjectionProviderException("checking class resource " + annotation.name()+" of "+clazz.getName(), exc);
                }
            }
            // Process fields with @Resource
            // see org.apache.catalina.core.DefaultInstanceManager
//            Field[] fields = Introspection.getDeclaredFields(managedBean.getClass());
            Field[] fields = managedBean.getClass().getDeclaredFields();
            for (Field field : fields)
            {
                if (field.isAnnotationPresent(Resource.class))
                {
                    Resource annotation = field.getAnnotation(Resource.class);
                    String name = annotation.name();
                    logger.log(Level.CONFIG, "injecting @Resource(name=\"{2}\") into {0}.{1}", new Object[]
                        {
                            managedBean.getClass().getName(), field.getName(), name
                        });
                    try
                    {
                        Context ctx = new InitialContext();
                        Object resource;
                        if (name != null && name.length() > 0)
                        {
                            resource = ctx.lookup("java:comp/env/" + name);
                        }
                        else
                        {
                            resource = ctx.lookup(clazz.getName() + "/" + field.getName());
                        }
                        // field may be private
                        boolean accessibility = field.isAccessible();
                        try
                        {
                            field.setAccessible(true);
                            field.set(managedBean, resource);
                        }
                        finally
                        {
                            field.setAccessible(accessibility);
                        }
                    }
                    catch (NamingException | IllegalAccessException exc)
                    {
                        throw new InjectionProviderException("injecting resource " + annotation.name()+" into "+clazz.getName()+"."+field.getName(), exc);
                    }
                }
            }
            // Process methods with @Resource
            for (Method method : clazz.getDeclaredMethods())
            {
                if (method.isAnnotationPresent(Resource.class)
                && method.getName().startsWith("set")
                && method.getName().length() > 3
                && method.getReturnType() == void.class
                && method.getParameterTypes().length == 1)
                {
                    // It's a setter with @Resource
                    Resource annotation = method.getAnnotation(Resource.class);
                    String name = annotation.name();
                    logger.log(Level.CONFIG, "injecting @Resource(name=\"{2}\") via {0}.{1}", new Object[]
                        {
                            managedBean.getClass().getName(), method.getName(), name
                        });
                    try
                    {
                        Context ctx = new InitialContext();
                        Object resource;
                        if (name != null && name.length() > 0)
                        {
                            resource = ctx.lookup("java:comp/env/" + name);
                        }
                        else
                        {
                            name = method.getName().substring(3);
                            name = name.substring(0,1).toLowerCase()+name.substring(1);
                            resource = ctx.lookup(clazz.getName() + "/" + name);
                        }
                        // method may be private
                        boolean accessibility = method.isAccessible();
                        try
                        {
                            method.setAccessible(true);
                            method.invoke(managedBean, resource);
                        }
                        finally
                        {
                            method.setAccessible(accessibility);
                        }
                    }
                    catch (NamingException | IllegalAccessException | InvocationTargetException exc)
                    {
                        throw new InjectionProviderException("injecting resource " + annotation.name()+" via "+clazz.getName()+"."+method.getName(), exc);
                    }
                }
            }
        } while ((clazz = clazz.getSuperclass()) != Object.class);
    }

    @Override
    public void invokePostConstruct(Object managedBean) throws InjectionProviderException
    {
        logger.log(Level.CONFIG, "managedBean={0}", new Object[]{managedBean});
        delegate.invokePostConstruct(managedBean);
    }

    @Override
    public void invokePreDestroy(Object managedBean) throws InjectionProviderException
    {
        logger.log(Level.CONFIG, "managedBean={0}", new Object[]{managedBean});
        delegate.invokePreDestroy(managedBean);
    }
}

E&OE

于 2014-11-18T03:34:32.707 に答える
1

別の可能性ですが、私はありそうにないと思います。metadata-complete="true"web.xml または web-fragment.xml ファイルで使用していますか。

定義された metadata-complete: metadata-complete 属性は、このデプロイメント記述子とこのモジュールの他の関連するデプロイメント記述子 (Web サービス記述子など) が完全であるかどうか、またはこのモジュールで使用でき、このアプリケーションでパッケージ化されたクラス ファイルを検査する必要があるかどうかを定義します。デプロイメント情報を指定するアノテーション用。metadata-complete が「true」に設定されている場合、デプロイメント ツールは、アプリケーションのクラス ファイルに存在する可能性のあるデプロイメント情報を指定するアノテーションを無視する必要があります。metadata-complete が指定されていないか、「false」に設定されている場合、デプロイメント ツールは、仕様で指定されているように、注釈についてアプリケーションのクラス ファイルを調べる必要があります。

例 web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app metadata-complete="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
  <display-name>ResourceTest</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
 </welcome-file-list>
</web-app>
于 2013-06-28T20:42:57.140 に答える
-1

申し訳ありませんが、担当者のためにコメントできません。または、表示されているエラーなどについてさらに明確にするようお願いしたいと思います。そうは言っても、Tomcat 7.0.27 と Tomcat 7.0.41 の両方で Java フルバージョン「1.6.0_51-b11-457」をテストし、@Resource を使用できました。

Context.xml

<?xml version="1.0" encoding="UTF-8"?>
<Context>
  <Resource name="jdbc/Sample" auth="Container"
      type="javax.sql.DataSource" username="nbuser" password="nbuser"
      driverClassName="org.apache.derby.jdbc.ClientDriver" 
      url="jdbc:derby://localhost/Sample"
      maxActive="8" maxIdle="4"/>
</Context>

ResourceTest.java

import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;

import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;

@WebServlet("/ResourceTest")
public class ResourceTest extends HttpServlet {
  private static final long serialVersionUID = 1L;
  @Resource(name="jdbc/Sample")
  private DataSource ds;


public ResourceTest() {
    // TODO Auto-generated constructor stub
}


protected void doGet(HttpServletRequest request,
        HttpServletResponse response) throws ServletException, IOException {
    // TODO Auto-generated method stub
    PrintWriter out = response.getWriter();
    out.println("<body>");


    try {
        //Context initCtx = new InitialContext();
        //Context envCtx = (Context) initCtx.lookup("java:comp/env");
        //DataSource ds = (DataSource) envCtx.lookup("jdbc/Sample");
        Connection conn = ds.getConnection();
        Statement s = conn.createStatement();
        s.execute("Select * From \"NBUSER\".\"Friends\"");
        ResultSet rs = s.getResultSet();
        while (rs.next()) {
            out.println(rs.getString("NAME") + " is my friend.");
        }
        conn.close();
    } catch (Exception ex) {
        ex.printStackTrace();
    }

    out.println("</body>");

}

/**
 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
 *      response)
 */
protected void doPost(HttpServletRequest request,
        HttpServletResponse response) throws ServletException, IOException {
    // TODO Auto-generated method stub
}

}
于 2013-06-27T16:50:33.040 に答える