JSF внедряет вспомогательный компонент в синглтон

#java #jsf #jsf-2

#java #jsf #jsf-2

Вопрос:

Я пытаюсь отобразить представление JSF в строку. У меня есть одноэлементный компонент, вспомогательный компонент и представление, аналогичное приведенным ниже примерам.

Я не могу понять, как внедрить мой вспомогательный компонент в мой синглтон. С помощью приведенного ниже кода в консоли выводится строка журнала «Fine: testBean создан вручную», что означает, что экземпляр компонента создан неправильно. Я также получаю следующее предупреждение:

Серьезная проблема: невозможно вызвать аннотированный метод @PostConstruct для экземпляра javax.faces.ViewRoot

И стек исключений:

 com.sun.faces.spi.InjectionProviderException: com.sun.enterprise.container.common.spi.util.InjectionException: Wrong invocation type
    at org.glassfish.faces.integration.GlassFishInjectionProvider.invokePostConstruct(GlassFishInjectionProvider.java:231)
[...]
Caused by: com.sun.enterprise.container.common.spi.util.InjectionException: Wrong invocation type
at org.glassfish.faces.integration.GlassFishInjectionProvider.getNamingEnvironment(GlassFishInjectionProvider.java:262)
at org.glassfish.faces.integration.GlassFishInjectionProvider.invokePostConstruct(GlassFishInjectionProvider.java:229)
  

Цель кода — отображать персонализированную почту. Я пытаюсь поместить некоторые значения в вспомогательный компонент, а затем отобразить представление в виде строки в качестве тела письма.
Я пробовал различные области для резервного компонента.

Спасибо,

Чарли

test.xhtml:

     <!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:c="http://java.sun.com/jsp/jstl/core">

    <h:body>
        <h1> Hello </h1>
        <p>
            Bean String : #{testBean.theString}
        </p>
        <h:form>
            <h:commandLink value="Render it"
                           action="#{testBean.actionRenderTest()}"/>
        </h:form>
    </h:body>
</html>
  

TestBean.java:

 // skipped package and imports

@ManagedBean
@ApplicationScoped
public class TestBean implements Serializable{

    @EJB
    private TestSingleton singleton;

    private String theString;

    public String getTheString() {
        return theString;
    }

    public void setTheString(String theString) {
        this.theString = theString;
    }

    public void actionRenderTest() {
        singleton.renderTest();
    }

}
  

TestSingleton.java:

 // packageamp;imports

@Singleton
@Startup
public class TestSingleton implements Serializable {

    @ManagedProperty("#{testBean}")
    private TestBean testBean;


    public void renderTest() {
        if (testBean == null) {
            FacesContext context = FacesContext.getCurrentInstance();
            testBean = context.getApplication().evaluateExpressionGet(context, "#{testBean}", TestBean.class);
            Logger.getLogger(TestSingleton.class.getName()).fine("TestBean created manually");
        }

        testBean.setTheString("string set from my singleton");
        try {
            FacesContext context = FacesContext.getCurrentInstance();
// store the original response writer
            ResponseWriter originalWriter = context.getResponseWriter();

// put in a StringWriter to capture the output
            StringWriter stringWriter = new StringWriter();
            ResponseWriter writer = createResponseWriter(context, stringWriter);
            context.setResponseWriter(writer);

// create a UIViewRoot instance
            ViewHandler viewHandler = context.getApplication().getViewHandler();
            final String template = "/test/test.xhtml";
            UIViewRoot view = viewHandler.createView(context, template);

// the fun part -- do the actual rendering here
            ViewDeclarationLanguage vdl = viewHandler
                    .getViewDeclarationLanguage(context, template);
            vdl.buildView(context, view);
            renderChildren(context, view);

// restore the response writer
            if (originalWriter != null) {
                context.setResponseWriter(originalWriter);
            }

            Logger.getLogger(TestSingleton.class.getName()).log(Level.FINE, stringWriter.toString());
        } catch (IOException ex) {
            Logger.getLogger(TestSingleton.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * Create ResponseWriter. Taken from FaceletViewDeclarationLanguage.java of
     * MyFaces.
     */
    private ResponseWriter createResponseWriter(FacesContext context,
            Writer writer) {
        ExternalContext extContext = context.getExternalContext();
        Map<String, Object> requestMap = extContext.getRequestMap();
        String contentType = (String) requestMap.get("facelets.ContentType");
        String encoding = (String) requestMap.get("facelets.Encoding");
        RenderKit renderKit = context.getRenderKit();
        return renderKit.createResponseWriter(writer, contentType, encoding);
    }

    /**
     * Render a UIComponent. Taken from JSF.java of Seam 2.2.
     */
    private void renderChildren(FacesContext context, UIComponent component)
            throws IOException {
        List<UIComponent> children = component.getChildren();
        for (int i = 0, size = component.getChildCount(); i < size; i  ) {
            UIComponent child = (UIComponent) children.get(i);
            renderChild(context, child);
        }
    }

    /**
     * Render the child and all its children components.
     */
    private void renderChild(FacesContext context, UIComponent child)
            throws IOException {
        if (child.isRendered()) {
            child.encodeAll(context);
        }
    }
}
  

Ответ №1:

@ManagedProperty аннотация не имеет никакого эффекта вне @ManagedBean .

От http://docs.oracle.com/javaee/6/api/javax/faces/bean/ManagedProperty.html

Если эта аннотация присутствует в классе, у которого нет аннотации ManagedBean, реализация не должна предпринимать никаких действий с этой аннотацией

Аннотируйте свой компонент, используя @Inject и @ApplicationScoped

 import javax.inject.Named;
import javax.enterprise.context.ApplicationScoped;

@Named
@ApplicationScoped
public class TestBean implements Serializable
  

И добавьте аннотацию @Inject в свой @Singleton

 @Singleton
@Startup
public class TestSingleton implements Serializable {

    @Inject
    private TestBean testBean;
  

Комментарии:

1. Я думаю, вы имели в виду @Named в вспомогательном компоненте

2. Это не имеет никакого эффекта. Переменная testBean по-прежнему равна нулю при вызове метода singleton, и я получаю то же сообщение об ошибке и исключения.

3. Пожалуйста, убедитесь, что все импортированные файлы верны, а @ApplicationScoped — из javax.enterprise.context. ApplicationScoped . Это работает в нашем проекте. Есть ли какие-либо предупреждения или ошибки?

4. Также убедитесь, что включен CDI (у вас есть beans.xml в WEB-INF)

5. Извините. Компонент правильно вводится после чистого повторного развертывания.

Ответ №2:

Я думаю, это потому, что у вас циклическая зависимость. TestBean ссылайтесь TestSingleton и TestSingleton запрашивайте внедрение TestBean .

Комментарии:

1. Вполне допустимо выполнять двунаправленные инъекции.