#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. Вполне допустимо выполнять двунаправленные инъекции.