-
15. Re: selectItems - Is it possible?
pmuir Oct 25, 2007 5:33 PM (in response to kragoth)1 & 2 are not mutually exclusive (just be clever and warn if an invalid combination comes up)
3 is not a viable option as it is basically a memory leak -
16. Re: selectItems - Is it possible?
igx89 Oct 25, 2007 5:45 PM (in response to kragoth)How hard/expensive would it be to determine if an object is or contains any entity classes? For simple POJO's I'd imagine it'd be pretty simple, but once you get into nesting or collections or stuff I imagine it'd be much more complex? Or is there a method in Seam which makes that all a piece of cake? That's why I split them into two options.
That's true, the only way around that would be to use the conversation scope (requiring it to be long-running) and find a way to determine when a page transition occurs (monitoring JSF lifecycle events?). -
17. Re: selectItems - Is it possible?
pmuir Oct 25, 2007 6:14 PM (in response to kragoth)It's relatively easy to determine if an object is an entity through PersistenceProvider (if its not, it can be added). I can't see why you would worry about whether it contains a collection of entities.
-
18. Re: selectItems - Is it possible?
igx89 Oct 26, 2007 12:14 AM (in response to kragoth)So while it's not fine to put an entity into a client-side state, putting an object wrapping the entity into there is fine? But would't the entity be serialized in either case? I guess I'm just a little confused on how that all works. However, I'm fine with just taking your word for it :).
-
19. Re: selectItems - Is it possible?
igx89 Oct 26, 2007 5:07 PM (in response to kragoth)How's this look?
@Name("org.jboss.seam.ui.ObjectConverter") @Scope(PAGE) @Install @Converter(forClass=Object.class) @BypassInterceptors public class ObjectConverter implements javax.faces.convert.Converter, Serializable { private Map<String, Object> objects; @Create public void create() { objects = new HashMap<String, Object>(); } public String getAsString(FacesContext facesContext, UIComponent cmp, Object value) throws ConverterException { if(value == null) return null; for(Map.Entry<String,Object> entry: objects.entrySet()) if(entry.getValue() == value) return entry.getKey(); if(facesContext.getApplication().getStateManager().isSavingStateInClient(facesContext) && Seam.isEntityClass(value.getClass())) throw new ConverterException("ObjectConverter is unable to handle entity classes when client-side " + "state saving is enabled. Please use EntityConverter instead, or enable server-side state saving"); String key = new UID().toString(); objects.put(key, value); return key; } public Object getAsObject(FacesContext facesContext, UIComponent cmp, String key) throws ConverterException { if (key == null) return null; return objects.get(key); } }
-
20. Re: selectItems - Is it possible?
igx89 Oct 26, 2007 5:16 PM (in response to kragoth)(remove the forClass=Object.class from the @Converter annotation; remnant of some experimentation)
-
21. Re: selectItems - Is it possible?
pmuir Oct 27, 2007 7:00 AM (in response to kragoth)I think you need to separate out the converter and the store. This way Seam manages the scope of the store, whilst the converter is handled by JSF.
-
22. Re: selectItems - Is it possible?
kragoth Oct 27, 2007 8:38 PM (in response to kragoth)Well guys, thanks for all the input.
I didn't really know any other way to solve my problem so the converter is it for now I guess.
@IGx89
I'll try your code when I get back to work and see if it works.
@pete.muir@jboss.org
How should the store be done pete? I'm really quite new to the seam world as you probably can gather.... in fact I'm basically straight out of uni as far as Java programming goes! So, I'm still a little slow on some of the concepts.
Thanks for all your help. It is great getting support so quickly. -
23. Re: selectItems - Is it possible?
pmuir Oct 28, 2007 5:40 AM (in response to kragoth)Look at the EntityConverterStore.
-
24. Re: selectItems - Is it possible?
kragoth Oct 28, 2007 11:08 PM (in response to kragoth)Ok, I've tried using IGx89's converter but moving the store outside of the converter. And it *almost* works!
I'm running into a small problem though.
My code is as follows:
ObjectConverter.javapackage gekko.web.converter; import static org.jboss.seam.ScopeType.CONVERSATION; import gekko.util.StringUtils; import javax.faces.component.UIComponent; import javax.faces.context.FacesContext; import javax.faces.convert.ConverterException; import org.jboss.seam.Seam; import org.jboss.seam.annotations.Create; import org.jboss.seam.annotations.Install; import org.jboss.seam.annotations.Name; import org.jboss.seam.annotations.Scope; import org.jboss.seam.annotations.faces.Converter; import org.jboss.seam.annotations.intercept.BypassInterceptors; @Name("GenericObjectConverter") @Scope(CONVERSATION) @Install(precedence = Install.APPLICATION) @Converter @BypassInterceptors public class ObjectConverter implements javax.faces.convert.Converter { private ObjectConverterStore objectStore; @Create public void create() { objectStore = ObjectConverterStore.instance(); } @Override public Object getAsObject(FacesContext context, UIComponent component, String value) throws ConverterException { if (value == null) { return null; } return objectStore.get(value); } @Override public String getAsString(FacesContext context, UIComponent component, Object value) throws ConverterException { if (value == null) { return null; } String key = objectStore.contains(value); if (! StringUtils.isBlank(key)) { return key; } if(context.getApplication().getStateManager().isSavingStateInClient(context) && Seam.isEntityClass(value.getClass())) throw new ConverterException("ObjectConverter is unable to handle entity classes when client-side " + "state saving is enabled. Please use EntityConverter instead, or enable server-side state saving"); return objectStore.put(value).toString(); } }
ObjectConverterStore.javapackage gekko.web.converter; import static org.jboss.seam.ScopeType.PAGE; import static org.jboss.seam.annotations.Install.APPLICATION; import java.rmi.server.UID; import java.util.HashMap; import java.util.Map; import org.jboss.seam.Component; import org.jboss.seam.annotations.Install; import org.jboss.seam.annotations.Name; import org.jboss.seam.annotations.Scope; import org.jboss.seam.contexts.Contexts; @Name("ObjectConverterStore") @Install(precedence = APPLICATION) @Scope(PAGE) public class ObjectConverterStore { private Map<String, Object> objects = new HashMap<String, Object>(); // Add an object to the store public String put(Object entity) { String key = new UID().toString(); objects.put(key, entity); return key; } // Get an object from the store public Object get(String key) { return objects.get(key); } // Check if store contains the object already. public String contains(Object object) { for (Map.Entry<String, Object> entry : objects.entrySet()) { if (entry.getValue() == object) { entry.getKey(); } } return null; } public static ObjectConverterStore instance() { if (!Contexts.isPageContextActive()) { throw new IllegalArgumentException("Page scope not active"); } return (ObjectConverterStore) Component .getInstance(ObjectConverterStore.class); } }
And finally my faces-config.xml<?xml version="1.0" encoding="UTF-8"?> <faces-config version="1.2" 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-facesconfig_1_2.xsd"> <!-- Facelets support --> <application> <variable-resolver> org.springframework.web.jsf.DelegatingVariableResolver </variable-resolver> <view-handler>com.sun.facelets.FaceletViewHandler</view-handler> <message-bundle>messages</message-bundle> </application> <!-- The gekko project's Date Converter --> <converter> <converter-id>gekkoDateConverter</converter-id> <converter-class> gekko.web.converter.DateConverter </converter-class> </converter> <!-- The gekko project's Persistent Entity Converter: Only to be used with the h:selectMenus --> <converter> <converter-id>SelectItemsPersistentEntityConverter</converter-id> <converter-class> gekko.web.converter.SelectItemsPersistentEntityConverter </converter-class> </converter> <!-- The generic object converter --> <converter> <converter-id>GenericObjectConverter</converter-id> <converter-class> gekko.web.converter.ObjectConverter </converter-class> </converter> <!-- This is the gekko:defaultAction tag to use for when a user presses the enter key to submit a form --> <component> <component-type>gekko.web.defaultAction</component-type> <component-class> gekko.web.components.UIDefaultAction </component-class> </component> </faces-config>
OK, now for the problem.
The converter works fine when it comes to the getAsString method, everything does exactly what it should do.
But when I do the getAsObject my objectStore variable is null!????!!??
Can someone please tell me why?
I have tried to copy the entityManagerStore but I must be missing something!
I'll keep looking into it but... so far I've not made any progress, changing scopes does not help either.
Thanks for any input!
Just in case the stack trace is as follows:WARNING: executePhase(PROCESS_VALIDATIONS 3,com.sun.faces.context.FacesContextImpl@14563aa) threw exception javax.faces.FacesException at com.sun.faces.lifecycle.ProcessValidationsPhase.execute(ProcessValidationsPhase.java:108) at com.sun.faces.lifecycle.LifecycleImpl.phase(LifecycleImpl.java:251) at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:117) at javax.faces.webapp.FacesServlet.service(FacesServlet.java:244) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at org.ajax4jsf.webapp.BaseFilter.doFilter(BaseFilter.java:307) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:83) at org.jboss.seam.web.MultipartFilter.doFilter(MultipartFilter.java:85) at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69) at org.jboss.seam.web.ExceptionFilter.doFilter(ExceptionFilter.java:64) at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69) at org.jboss.seam.web.RedirectFilter.doFilter(RedirectFilter.java:44) at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69) at org.ajax4jsf.webapp.BaseXMLFilter.doXmlFilter(BaseXMLFilter.java:141) at org.ajax4jsf.webapp.BaseFilter.doFilter(BaseFilter.java:281) at org.jboss.seam.web.Ajax4jsfFilter.doFilter(Ajax4jsfFilter.java:60) at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69) at org.jboss.seam.web.LoggingFilter.doFilter(LoggingFilter.java:58) at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69) at org.jboss.seam.servlet.SeamFilter.doFilter(SeamFilter.java:150) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:263) at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:844) at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:584) at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447) at java.lang.Thread.run(Thread.java:619) Caused by: java.lang.NullPointerException at gekko.web.converter.ObjectConverter.getAsObject(ObjectConverter.java:39) at org.jboss.seam.ui.converter.PrioritizableConverter.getAsObject(PrioritizableConverter.java:61) at org.jboss.seam.ui.converter.ConverterChain.getAsObject(ConverterChain.java:107) at com.sun.faces.renderkit.html_basic.HtmlBasicInputRenderer.getConvertedValue(HtmlBasicInputRenderer.java:152) at com.sun.faces.renderkit.html_basic.MenuRenderer.convertSelectOneValue(MenuRenderer.java:197) at com.sun.faces.renderkit.html_basic.MenuRenderer.getConvertedValue(MenuRenderer.java:359) at javax.faces.component.UIInput.getConvertedValue(UIInput.java:934) at javax.faces.component.UIInput.validate(UIInput.java:860) at javax.faces.component.UIInput.executeValidate(UIInput.java:1065) at javax.faces.component.UIInput.processValidators(UIInput.java:666) at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1033) at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1033) at javax.faces.component.UIForm.processValidators(UIForm.java:229) at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1033) at javax.faces.component.UIViewRoot.processValidators(UIViewRoot.java:662) at org.ajax4jsf.component.AjaxViewRoot.access$201(AjaxViewRoot.java:57) at org.ajax4jsf.component.AjaxViewRoot$3.invokeRoot(AjaxViewRoot.java:319) at org.ajax4jsf.context.JsfOneOneInvoker.invokeOnRegionOrRoot(JsfOneOneInvoker.java:56) at org.ajax4jsf.context.AjaxContextImpl.invokeOnRegionOrRoot(AjaxContextImpl.java:173) at org.ajax4jsf.component.AjaxViewRoot.processValidators(AjaxViewRoot.java:333) at com.sun.faces.lifecycle.ProcessValidationsPhase.execute(ProcessValidationsPhase.java:100) ... 34 more
-
25. Re: selectItems - Is it possible?
igx89 Oct 29, 2007 10:57 AM (in response to kragoth)Pete, why do they need to be separate? @Create's being called only once per page and everything seems to work fine. Changing the scope doesn't seem to work, but that doesn't seem to affect anything negatively in this case.
-
26. Re: selectItems - Is it possible?
igx89 Oct 31, 2007 10:30 AM (in response to kragoth)*bump*
From the recent posts in http://www.jboss.com/index.html?module=bb&op=viewtopic&t=122653, it would seem that while Converter has an Event/Page scope (which one? code says former, but my observations show latter), you plan in the future to force it to have a Stateless scope? If that's the case, then creating an ObjectConverterStore class would be needed for future-proofing (irregardless of anything else). -
27. Re: selectItems - Is it possible?
pmuir Oct 31, 2007 10:47 AM (in response to kragoth)It has Event scope by default. It should (maybe) have stateless scope by default, I'm still not sure.
I guess making the converter page scope and not separating them should work, but I've never tried (I'm not sure how this will interact with JSF's state saving). -
28. Re: selectItems - Is it possible?
igx89 Oct 31, 2007 11:03 AM (in response to kragoth)So far I've yet to run across any problems, though I've just been using it for selectOneItem's and am using server-side state saving with no clustering.
Testers would be nice... -
29. Re: selectItems - Is it possible?
sefai Nov 21, 2007 11:30 AM (in response to kragoth)I have a selectOneMenu where selectItems come from a WebService which returns a collection of a simple POJO class.It has an identifier,and some fields,but since it is not managed by any EntityManager or HibernateSession I can not use s:convertEntity. I think this is the case you didn't come accross pete and dan :/
I have to convert that collection to a List and define an Integer in the backing bean which stores the selected index or write a converter for that class. (But I have more than one selectOneMenu with this case and all uses different POJOs). Either way,selectitem or converter,does not seem right to me,because within my tidy code,thanks to seam, they look ugly.
On http://jira.jboss.com/jira/browse/JBSEAM-1801, pete says:"I've implemented something similar: override and extend the org.jboss.seam.ui.entityIdentiferStore component implementing the get and put methods. You can then use e.g. a HashMap, and using the identifier and entity arguements to put, store it under whatever key you like". I am working on this without success. pete can you please show a sample or at least give more info on this subject?