2017-08-16 1 views
2

Ich schaue mit der "@Resource String ..." Injektion in Servlet 3.0+ Container für die Bereitstellung von Konfigurationsparametern leicht zu Servlets. Ich möchte für die Standardeinstellungen funktionieren und fehlschlagen, wenn der Schlüssel nicht in JNDI (Angabe eines Konfigurationsfehlers)@Resource-Fehler: "Naming Bindung existiert bereits für foo.NewServlet/userName im Namespace"

Ich habe mit einem einfachen Servlet in Netbeans 8.2 mit Glassfish 4.1.1 gespielt, wo ich möchte userName Feld und der setFullName(String fullName) Satz:

package foo; 

import java.io.IOException; 
import java.io.PrintWriter; 
import javax.annotation.Resource; 
import javax.servlet.ServletException; 
import javax.servlet.annotation.WebServlet; 
import javax.servlet.annotation.WebInitParam; 
import javax.servlet.http.HttpServlet; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 

@WebServlet(name = "NewServlet", urlPatterns = {"/NewServlet"}) 
public class NewServlet extends HttpServlet { 

    @Resource(description="user name") 
    String userName; 

    private String fullname; 

    @Resource() 
    public void setFullName(String fullName){ 
     this.fullname = fullName; 
    } 

    protected void processRequest(HttpServletRequest request, HttpServletResponse response) 
      throws ServletException, IOException { 
     response.setContentType("text/html;charset=UTF-8"); 
     try (PrintWriter out = response.getWriter()) { 
      /* TODO output your page here. You may use following sample code. */ 
      out.println("<!DOCTYPE html>"); 
      out.println("<html>"); 
      out.println("<head>"); 
      out.println("<title>Servlet NewServlet</title>");    
      out.println("</head>"); 
      out.println("<body>"); 
      out.println("Full name = " + fullname); 
      out.println("<h1>Servlet NewServlet at " + request.getContextPath() + "</h1>"); 
      out.println("Username = " + userName); 
      out.println("</body>"); 
      out.println("</html>"); 


     } 
    } 
// Autogenerated stuff omitted 
} 

Ohne "web.xml" die Felder sind nur null (und kein Fehler). Ich habe dann mit "web.xml" herumgespielt, um zu sehen, wie ich das definieren könnte. Der Name "java: comp/env/foo: NewServlet/vollständigerName" wird von Glassfish 4.1.1 als Name für den FullName-Setter erstellt.

<?xml version="1.0" encoding="UTF-8"?> 
<web-app 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/web-app_3_0.xsd" 
    version="3.0"> 
    <env-entry > 
     <env-entry-name>java:comp/env/foo.NewServlet/fullName</env-entry-name> 
     <env-entry-type>java.lang.String</env-entry-type> 
     <env-entry-value>!BAR!</env-entry-value> 
    </env-entry> 
    <env-entry > 
     <env-entry-name>java:comp/env/foo.NewServlet/userName</env-entry-name> 
     <env-entry-type>java.lang.String</env-entry-type> 
     <env-entry-value>!USERNAME!</env-entry-value> 
    </env-entry> 
</web-app> 

Dies scheitert dann mit

Severe: Exception while deploying the app [WebApplication4] : Naming binding already exists for foo.NewServlet/userName in namespace {java:module/env/foo.NewServlet/userName=Env-Prop: java:comp/env/foo.NewServlet/[email protected] [email protected]@[email protected]@, java:module/env/foo.NewServlet/fullName=Env-Prop: java:comp/env/foo.NewServlet/[email protected] [email protected]@[email protected]@} 

Es gibt nichts anderes, als diese beiden Dateien in das Projekt. Anscheinend verstehe ich etwas Grundlegendes falsch, aber das Lesen des Java EE Tutorials und das Suchen nach Vorschlägen hat mir nicht geholfen. Ich würde wirklich gerne zwei Dinge:

  1. Entweder keine Hinweise auf die @ Ressource-Tag Bereitstellung der Container erzeugt standardmäßig oder einfach nur einen Schlüssel wie „our.application.fullName“ verwenden.
  2. Fehlgeschlagen laut, wenn etwas falsch ist, einschließlich des Schlüsselwerts, der nicht vorhanden ist.

Vorschläge? Eine gute Antwort wird eine 500 Punkte Kopfgeld geben.

+0

Getrennte Frage auf Wildfly/Glassfish Verhalten geöffnet - https://stackoverflow.com/q/45716813/53897 –

Antwort

1

Sie haben eigentlich nur zwei wichtige Details übersehen:

  1. Wenn in einem Deployment Descriptor (wie der web.xml) den Namen einer Ressource Angabe, ob es sich um eine env-entry-name, resource-env-ref-name oder ejb-ref-name sein, usw. Der java:comp/env Teil des JNDI-Namens ist immer implizit. Deshalb, wenn Sie von einem env-entry definiert eine Ressource wollen bei java:comp/env/foo in JNDI erscheinen, dann geben Sie seine env-entry-name als:

     <env-entry-name>foo</env-entry-name> 
    
  2. Die Java EE-Spezifikation (§EE.5.2.5) ändert die Regeln für die „default“ Namen @Resource Anmerkungen angewendet:

    A field of a class may be the target of injection. The field must not be final. By default, the name of the field is combined with the fully qualified name of the class and used directly as the name in the application component’s naming context. For example, a field named myDatabase in the class MyApp in the package com.example would correspond to the JNDI name java:comp/env/ com.example.MyApp/myDatabase. The annotation also allows the JNDI name to be specified explicitly. When a deployment descriptor entry is used to specify injection, the JNDI name and the field name are both specified explicitly. Note that, by default, the JNDI name is relative to the java:comp/env naming context.

    Mit anderen Worten, wenn der vollständige Name des Servlet com.p45709634.NewServlet ist, dann ist der JNDI-Name des userName Feld sein java:comp/env/com.p45709634.NewServlet/userName wird. Daher seine env-entry-name wird sein:

     <env-entry-name>com.p45709634.NewServlet/userName</env-entry-name> 
    

Also, wenn Sie diese vollständig qualifizierten Namen in Ihrem Web verwenden.XML-Datei, dann können Sie gerne die kommentierten Felder erklären, wie Sie angefordert haben:

@Resource 
    private String userName; 

    private String fullname; 

    @Resource 
    public void setFullName(String fullName){ 
     this.fullname = fullName; 
    } 

Jetzt, wo gleiche Kapitel der Beschreibung heißt es:

If the container fails to find a resource needed for injection, initialization of the class must fail, and the class must not be put into service.

aber dies scheint nicht in der Praxis geschehen (zumindest auf GlassFish für dich und WildFly für mich). Dies kann auf eine gewisse Verzögerung der CDI-Spezifikation für die Injektion zurückzuführen sein, die nicht viel zu sagen hat, wenn die Ressourcen für die Injektion nicht lokalisiert werden.

Folglich können wir mit der Validierung dieser Felder in der init Methode oder einer annotierten Methode stecken bleiben.

+0

Ich entfernte den "java:/comp/env" Teil aus den env-Eintrag-Name-Tags, und es hat funktioniert ! Vielen Dank! Ich vermute, die Fehlermeldung wurde über "/ comp/env" bereits gebunden, nicht der eigentliche Schlüssel bereits verwendet wird. Ich frage mich, ob dies ein bekannter Bug oder ein Feature von Wildfly/Glassfish ist und ob es mit einem Switch erzwungen werden kann? Wie auch immer, ich werde dir die Belohnung geben, wenn ich kann. Erinnere mich, wenn ich es vergesse. –

Verwandte Themen