1 2 3 Previous Next 31 Replies Latest reply on Nov 25, 2007 7:48 PM by kragoth Go to original post
      • 15. Re: selectItems - Is it possible?
        pmuir

        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?

          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

            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?

              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?

                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?

                  (remove the forClass=Object.class from the @Converter annotation; remnant of some experimentation)

                  • 21. Re: selectItems - Is it possible?
                    pmuir

                    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

                      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

                        Look at the EntityConverterStore.

                        • 24. Re: selectItems - Is it possible?
                          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.java

                          package 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.java
                          package 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?

                            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?

                              *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

                                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?

                                  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?

                                    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?