dev@javaserverfaces.java.net

Re: Is JSF incompatible with generics?

From: Mike Kienenberger <mkienenb_at_gmail.com>
Date: Tue, 9 Jun 2009 13:27:43 -0400

Interesting. I didn't know that was possible -- I only have a
moderate understanding of generics.

On Tue, Jun 9, 2009 at 1:24 PM, Freire, Jose Luis (PT -
Lisbon)<jfreire_at_deloitte.pt> wrote:
> Hi Mike!
>
> Not really.. You can reflect the generic type of a getter/setter in runtime. You just need a little reflection magic! :)
>
> If you execute the main() at IntegerAndBigDecimalTestController.java below, you get the correct identification of the types for the properties "value" and "anotherValue".
>
> The code is just something I did as a proof of concept, and will probably fail if you get a generic super class that inherits from another generic super class.
>
> GenericsTestController.java
> ----------------------------------------
> package genericstest;
>
> public class GenericsTestController<E extends Object, Y extends Object> {
>
>        public E value;
>        public Y anotherValue;
>
>        public E getValue() {
>                return value;
>        }
>
>        public void setValue(E value) {
>                this.value = value;
>        }
>
>        public Y getAnotherValue() {
>                return anotherValue;
>        }
>
>        public void setAnotherValue(Y anotherValue) {
>                this.anotherValue = anotherValue;
>        }
>
> }
>
>
> IntegerAndBigDecimalTestController.java
> --------------------------------------
>
> package genericstest;
>
> import java.beans.BeanInfo;
> import java.beans.Introspector;
> import java.beans.PropertyDescriptor;
> import java.lang.reflect.GenericDeclaration;
> import java.lang.reflect.ParameterizedType;
> import java.lang.reflect.Type;
> import java.lang.reflect.TypeVariable;
> import java.math.BigDecimal;
>
> public class IntegerAndBigDecimalTestController extends GenericsTestController<Integer, BigDecimal> {
>
>
>        public static void dumpProperties(Class<?> clazz) throws Exception {
>                System.out.println("Dumping properties of class:" + clazz.getName());
>
>                BeanInfo beanInfo = Introspector.getBeanInfo(IntegerTestController.class);
>                PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
>                for (PropertyDescriptor item: propertyDescriptors) {
>                        Type type = item.getReadMethod().getGenericReturnType();
>                        TypeVariable<?> typeVariable = (type instanceof TypeVariable<?> ? (TypeVariable<?>) type : null);
>                        GenericDeclaration genericDeclaration = (typeVariable != null ? typeVariable.getGenericDeclaration() : null);
>                        if (genericDeclaration == null) {
>                                System.out.println(item.getName() + " : " + item.getPropertyType());
>                        } else {
>                                Class<?> genericClass = (Class<?>) genericDeclaration;
>                                //System.out.println(item.getName() + " : " + type + " defined in the generic class " + genericClass);
>
>                                Type[] typeParameters = genericClass.getTypeParameters();
>
>                                //System.out.println("Searching for definition of type " + type + " in generic class " + genericClass.getName() + " parameters");
>                                int index = 0;
>                                for (Type typeParameter : typeParameters) {
>                                        //System.out.println(" - " + typeParameter + " at position " + index);
>
>                                        if (typeParameter.equals(type)) {
>                                                //System.out.println("Searching for generic supertype " + genericClass.getName() + " of type " + clazz);
>                                                Type genericSuperclass = clazz.getGenericSuperclass();
>                                                if (genericSuperclass instanceof ParameterizedType) {
>                                                        ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;
>                                                        if (parameterizedType.getRawType().equals(genericClass)) {
>                                                                //System.out.println("Found it! We want parameter at index: " + index);
>                                                                System.out.println(item.getName()  + " : " + parameterizedType.getActualTypeArguments()[index]);
>                                                                break;
>                                                        }
>                                                }
>                                        }
>                                        index++;
>                                }
>
>                        }
>                }
>
>        }
>
>        public static void main(String[] args) throws Exception
>        {
>                dumpProperties(IntegerAndBigDecimalTestController.class);
>        }
> }
>
> José Freire
> Consulting - Financial Services Industry
> Deloitte Consultores, S.A.
> Deloitte | Edifício Atrium Saldanha, Praça Duque de Saldanha, 1 - 7º, 1050-094 Lisboa, Portugal
> Tel/Direct: +(351) 210 422 500 | Fax: +(351) 210 422 950
> jfreire_at_deloitte.pt | www.deloitte.pt
>
> Please consider the environment before printing.
>
>
>
>
> -----Original Message-----
> From: Mike Kienenberger [mailto:mkienenb_at_gmail.com]
> Sent: terça-feira, 9 de Junho de 2009 16:09
> To: dev_at_javaserverfaces.dev.java.net
> Subject: Re: Is JSF incompatible with generics?
>
> My guess is that it's not a bug.
>
> Generics don't exist at run-time, only compile-time, so your
> getters/setters would be of type java.lang.Object.
>
> A "non-converted" value binding would be of String type since that's
> what HTML forms submit by default.
>
> I can't think of a way to make it work any better than manually
> specifying a converter.
>
> On Tue, Jun 9, 2009 at 10:53 AM, Freire, Jose Luis (PT -
> Lisbon)<jfreire_at_deloitte.pt> wrote:
>> Hi Manfred!
>>
>> Manually forcing the converter to "javax.faces.Integer" works.
>>
>> Did a little debugging and inspecting MethodBindingMethodExpressionAdapter.java, the methodExpression property has expectedType=String.class.
>>
>> It looks like generic based properties are incorrectly evaluated as String.
>>
>> Should I file a bug?
>>
>> José Freire
>> Consulting - Financial Services Industry
>> Deloitte Consultores, S.A.
>> Deloitte | Edifício Atrium Saldanha, Praça Duque de Saldanha, 1 - 7º, 1050-094 Lisboa, Portugal
>> Tel/Direct: +(351) 210 422 500 | Fax: +(351) 210 422 950
>> jfreire_at_deloitte.pt | www.deloitte.pt
>>
>> Please consider the environment before printing.
>>
>>
>>
>> -----Original Message-----
>> From: Manfred Riem [mailto:mriem_at_manorrock.org]
>> Sent: terça-feira, 9 de Junho de 2009 15:16
>> To: dev_at_javaserverfaces.dev.java.net
>> Subject: RE: Is JSF incompatible with generics?
>>
>> Uhhh since when is the reference developer list deprecated? Note he
>> is talking about the Mojarra implementation not anything from JBoss.
>>
>> I don't know exactly why it is not working, but having you
>> tried registering the converter manually on the h:inputText?
>>
>> Manfred
>>
>>> -------- Original Message --------
>>> Subject: Re: Is JSF incompatible with generics?
>>> From: Ilya Shaikovsky <ishaikovsky_at_exadel.com>
>>> Date: Tue, June 09, 2009 8:02 am
>>> To: dev_at_javaserverfaces.dev.java.net
>>>
>>>
>>> This list is deprecated. Use Jboss.org resources in order to get support.
>>>
>>> Regards!
>>>
>>> Freire, Jose Luis (PT - Lisbon) пишет:
>>> >
>>> > Using JSF 1.2.12, Facelets 1.1.14, Tomcat 6.0.18.
>>> >
>>> >
>>> >
>>> > I’m not sure where to open this bug, since I’m not sure if it’s JSF,
>>> > Facelets, or EL related.
>>> >
>>> >
>>> >
>>> > If we have this simple class:
>>> >
>>> > *public* *class* GenericsTestController<E *extends* Object> {
>>> >
>>> >
>>> >
>>> >        *private* E value;
>>> >
>>> >
>>> >
>>> >        *public* E getValue() {
>>> >
>>> >               *return* value;
>>> >
>>> >        }
>>> >
>>> >
>>> >
>>> >        *public* *void* setValue(E value) {
>>> >
>>> >               *this*.value = value;
>>> >
>>> >        }
>>> >
>>> > }
>>> >
>>> >
>>> >
>>> > And we have this class to use as a managed bean (integerTest):
>>> >
>>> > *public* *class* IntegerTestController *extends*
>>> > GenericsTestController<Integer> {
>>> >
>>> >
>>> >
>>> >        *public* String add() {
>>> >
>>> >               setValue(getValue()+1);
>>> >
>>> >               *return* *null*;
>>> >
>>> >        }
>>> >
>>> >        *public* String subtract() {
>>> >
>>> >               setValue(getValue()-1);
>>> >
>>> >               *return* *null*;
>>> >
>>> >        }
>>> >
>>> > }
>>> >
>>> >
>>> >
>>> > This JSF code will not work:
>>> >
>>> > <h:form>
>>> >
>>> >        Value:
>>> >
>>> >        <h:inputText value="#{integerTest.value}" />
>>> >
>>> >        <h:commandButton action="#{integerTest.add}" value="+" />
>>> >
>>> >        <h:commandButton action="#{integerTest.subtract}" value="-" />
>>> >
>>> > </h:form>
>>> >
>>> >
>>> >
>>> > With this error:
>>> >
>>> > _java.lang.ClassCastException_: java.lang.String cannot be cast to
>>> > java.lang.Integer
>>> >
>>> >        at
>>> > genericstest.IntegerTestController.add(_IntegerTestController.java:18_)
>>> >
>>> >        at sun.reflect.NativeMethodAccessorImpl.invoke0(_Native Method_)
>>> >
>>> >        at
>>> > sun.reflect.NativeMethodAccessorImpl.invoke(_NativeMethodAccessorImpl.java:39_)
>>> >
>>> >        at
>>> > sun.reflect.DelegatingMethodAccessorImpl.invoke(_DelegatingMethodAccessorImpl.java:25_)
>>> >
>>> >        at java.lang.reflect.Method.invoke(_Method.java:597_)
>>> >
>>> >        at org.apache.el.parser.AstValue.invoke(_AstValue.java:172_)
>>> >
>>> >        at
>>> > org.apache.el.MethodExpressionImpl.invoke(_MethodExpressionImpl.java:276_)
>>> >
>>> >        at
>>> > com.sun.facelets.el.TagMethodExpression.invoke(_TagMethodExpression.java:68_)
>>> >
>>> >        at
>>> > javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(_MethodBindingMethodExpressionAdapter.java:88_)
>>> >
>>> >        at
>>> > com.sun.faces.application.ActionListenerImpl.processAction(_ActionListenerImpl.java:102_)
>>> >
>>> >        at javax.faces.component.UICommand.broadcast(_UICommand.java:387_)
>>> >
>>> >        at
>>> > javax.faces.component.UIViewRoot.broadcastEvents(_UIViewRoot.java:475_)
>>> >
>>> >        at
>>> > javax.faces.component.UIViewRoot.processApplication(_UIViewRoot.java:756_)
>>> >
>>> >        at
>>> > com.sun.faces.lifecycle.InvokeApplicationPhase.execute(_InvokeApplicationPhase.java:82_)
>>> >
>>> >        at com.sun.faces.lifecycle.Phase.doPhase(_Phase.java:100_)
>>> >
>>> >        at
>>> > com.sun.faces.lifecycle.LifecycleImpl.execute(_LifecycleImpl.java:118_)
>>> >
>>> >        at javax.faces.webapp.FacesServlet.service(_FacesServlet.java:265_)
>>> >
>>> >        at
>>> > org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(_ApplicationFilterChain.java:290_)
>>> >
>>> >        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:191_)
>>> >
>>> >        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:286_)
>>> >
>>> >        at
>>> > org.apache.coyote.http11.Http11Processor.process(_Http11Processor.java:845_)
>>> >
>>> >        at
>>> > org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(_Http11Protocol.java:583_)
>>> >
>>> >        at
>>> > org.apache.tomcat.util.net.JIoEndpoint$Worker.run(_JIoEndpoint.java:447_)
>>> >
>>> >        at java.lang.Thread.run(_Thread.java:619_)
>>> >
>>> >
>>> >
>>> > In fact, it fails with the same error even if we override getValue and
>>> > setValue on IntegerTestController.
>>> >
>>> >
>>> >
>>> > The only workaround is not to extend from GenericsTestController and
>>> > implement the “value” property as Integer in the IntegerTestController.
>>> >
>>> >
>>> >
>>> > Help anyone?**
>>> >
>>> > * *
>>> >
>>> > *José Freire
>>> > *Consulting - Financial Services Industry
>>> > Deloitte Consultores, S.A.
>>> > Deloitte | Edifício Atrium Saldanha, Praça Duque de Saldanha, 1 - 7º,
>>> > 1050-094 Lisboa, Portugal
>>> > Tel/Direct: +(351) 210 422 500 | Fax: +(351) 210 422 950
>>> > jfreire_at_deloitte.pt | www.deloitte.pt
>>> >
>>> > Please consider the environment before printing.
>>> >
>>> >
>>> >
>>> >
>>> >
>>> > *Disclaimer:*
>>> > Deloitte refers to one or more of Deloitte Touche Tohmatsu, a Swiss
>>> > Verein, its member firms, and their respective subsidiaries and
>>> > affiliates.  As a Swiss Verein (association), neither Deloitte Touche
>>> > Tohmatsu nor any of its member firms has any liability for each
>>> > other's acts or omissions.  Each of the member firms is a separate and
>>> > independent legal entity operating under the names "Deloitte,"
>>> > "Deloitte & Touche," "Deloitte Touche Tohmatsu," or other related
>>> > names.  Services are provided by the member firms or their
>>> > subsidiaries or affiliates and not by the Deloitte Touche Tohmatsu Verein.
>>> > Privileged/Confidential Information may be contained in this message.
>>> > If you are not the addressee indicated in this message (or responsible
>>> > for delivery of the message to such person), you may not copy or
>>> > deliver this message to anyone. In such case, you should destroy this
>>> > message and kindly notify the sender by reply email. Please advise
>>> > immediately if you or your employer do not consent to Internet email
>>> > for messages of this kind. Opinions, conclusions and other information
>>> > in this message that do not relate to the official business of my firm
>>> > shall be understood as neither given nor endorsed by it.
>>
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: dev-unsubscribe_at_javaserverfaces.dev.java.net
>> For additional commands, e-mail: dev-help_at_javaserverfaces.dev.java.net
>>
>>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe_at_javaserverfaces.dev.java.net
> For additional commands, e-mail: dev-help_at_javaserverfaces.dev.java.net
>
>