View Javadoc

1   /*
2    * Copyright 2011 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 1.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl1.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.student.r2.common.datadictionary.util;
17  
18  import java.beans.BeanInfo;
19  import java.beans.IntrospectionException;
20  import java.beans.Introspector;
21  import java.beans.PropertyDescriptor;
22  import java.lang.reflect.Method;
23  
24  import org.junit.Test;
25  import static org.junit.Assert.*;
26  
27  /**
28   * This workaround logic is used in Bean2DictionaryConverter
29   * 
30   * I want to keep this test here because when it fails that means the bug is finally
31   * fixed and we can remove the workaround from that code.
32   * 
33   * @author nwright
34   */
35  public class TestBeanInfoBugAndWorkaround {
36  
37      private static interface Sub {
38  
39          public String getFoo();
40      }
41  
42      private static class SubInfo implements Sub {
43  
44          private String foo;
45  
46          @Override
47          public String getFoo() {
48              return foo;
49          }
50  
51          public void setFoo(String foo) {
52              this.foo = foo;
53          }
54      }
55  
56      private static interface Main {
57  
58          public Sub getSub();
59      }
60  
61      private static class MainInfo implements Main {
62  
63          private SubInfo sub;
64  
65          @Override
66          public SubInfo getSub() {
67              return sub;
68          }
69  
70          public void setSub(SubInfo sub) {
71              this.sub = sub;
72          }
73      }
74  
75      private static class MainBean {
76  
77          private SubInfo sub;
78  
79          public SubInfo getSub() {
80              return sub;
81          }
82  
83          public void setSub(SubInfo sub) {
84              this.sub = sub;
85          }
86      }
87  
88      //    @Test
89      public void testBeanInfo() {
90          System.out.println("testing beanInfo bug and workaround introspection");
91          BeanInfo beanInfo;
92          // gets the Sub interface for the property type!
93          try {
94              beanInfo = Introspector.getBeanInfo(MainInfo.class);
95          } catch (IntrospectionException ex) {
96              throw new RuntimeException(ex);
97          }
98          for (PropertyDescriptor pd : beanInfo.getPropertyDescriptors()) {
99                  if (pd.getReadMethod().getName().equals("getSub")) {
100 //                System.out.println(pd.getName() + " " + pd.getPropertyType().getName());
101                 assertEquals(Sub.class.getName(), pd.getPropertyType().getName());
102             }           
103         }
104         // works for a regular bean
105         try {
106             beanInfo = Introspector.getBeanInfo(MainBean.class);
107         } catch (IntrospectionException ex) {
108             throw new RuntimeException(ex);
109         }
110         for (PropertyDescriptor pd : beanInfo.getPropertyDescriptors()) {
111             if (pd.getReadMethod().getName().equals("getSub")) {
112 //                System.out.println(pd.getName() + " " + pd.getPropertyType().getName());
113                 assertEquals(SubInfo.class.getName(), pd.getPropertyType().getName());
114             }
115         }
116         // try work around
117                 try {
118             beanInfo = Introspector.getBeanInfo(MainInfo.class);
119         } catch (IntrospectionException ex) {
120             throw new RuntimeException(ex);
121         }
122         for (PropertyDescriptor pd : beanInfo.getPropertyDescriptors()) {
123             if (pd.getReadMethod().getName().equals("getSub")) {
124 //                System.out.println(pd.getName() + " " + pd.getPropertyType().getName());
125                 assertEquals(Sub.class.getName(), pd.getPropertyType().getName());
126                 assertTrue (pd.getPropertyType().isInterface());
127                 Class<?> clazz = workAround (MainInfo.class, pd.getReadMethod().getName());
128 //                System.out.println(clazz.getName());
129                 assertEquals(SubInfo.class, clazz);               
130             }
131         }
132         
133     }
134 
135     private Class<?> workAround (Class <?> currentTargetClass, String methodName) {
136         Method method = findMethodImplFirst (currentTargetClass, methodName);
137         return method.getReturnType();
138     }
139     
140     /**
141      * from http://raulraja.com/2009/09/12/java-beans-introspector-odd-behavio/
142      * workaround for introspector odd behavior with javabeans that implement interfaces with comaptible return types
143      * but instrospection is unable to find the right accessors
144      *
145      * @param currentTargetClass the class being evaluated
146      * @param methodName		 the method name we are looking for
147      * @param argTypes		   the arg types for the method name
148      * @return a method if found
149      */
150     private Method findMethodImplFirst(Class<?> currentTargetClass, String methodName, Class<?>... argTypes) {
151         Method method = null;
152         if (currentTargetClass != null && methodName != null) {
153             try {
154                 method = currentTargetClass.getMethod(methodName, argTypes);
155             } catch (Throwable t) {
156                 // nothing we can do but continue
157             }
158             //Is the method in one of our parent classes
159             if (method == null) {
160                 Class<?> superclass = currentTargetClass.getSuperclass();
161                 if (!superclass.equals(Object.class)) {
162                     method = findMethodImplFirst(superclass, methodName, argTypes);
163                 }
164             }
165         }
166         return method;
167     }
168 }