001 /* 002 * Copyright 2011 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 1.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl1.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 package org.kuali.student.datadictionary.util; 017 018 import java.beans.BeanInfo; 019 import java.beans.IntrospectionException; 020 import java.beans.Introspector; 021 import java.beans.PropertyDescriptor; 022 import java.lang.reflect.Field; 023 import java.lang.reflect.ParameterizedType; 024 import java.lang.reflect.Type; 025 import java.lang.reflect.TypeVariable; 026 import java.util.Date; 027 import java.util.LinkedHashSet; 028 import java.util.List; 029 import java.util.Set; 030 031 public class ComplexSubstructuresHelper { 032 033 public Set<String> getComplexStructures(String className) { 034 Set<String> complexStructures = new LinkedHashSet<String>(); 035 loadComplexStructures(className, complexStructures); 036 return complexStructures; 037 } 038 039 private void loadComplexStructures(String className, 040 Set<String> complexStructures) { 041 if (!complexStructures.add(className)) { 042 return; 043 } 044 BeanInfo beanInfo; 045 Class<?> clazz; 046 try { 047 clazz = Thread.currentThread().getContextClassLoader().loadClass(className); 048 // had to change the standard Class.forName below to the above so it uses the right class loader 049 // that is defined in KSDictionaryDocMojo.java 050 // clazz = Class.forName(className); 051 } catch (ClassNotFoundException ex) { 052 System.out.println("ComplexSubstructuresHelper: Could not process because the class must be a freestanding object: " + className); 053 return; 054 } 055 try { 056 beanInfo = Introspector.getBeanInfo(clazz); 057 } catch (IntrospectionException ex) { 058 throw new RuntimeException(ex); 059 } 060 for (PropertyDescriptor pd : beanInfo.getPropertyDescriptors()) { 061 Class<?> subClass = pd.getPropertyType(); 062 if (List.class.equals(subClass)) { 063 // recursively check super classes for field if not declared on this class 064 subClass = getActualClassFromList(clazz, pd.getName()); 065 } 066 if (!Class.class.equals(subClass) 067 && !String.class.equals(subClass) 068 && !Integer.class.equals(subClass) 069 && !Long.class.equals(subClass) 070 && !Boolean.class.equals(subClass) 071 && !boolean.class.equals(subClass) 072 && !int.class.equals(subClass) 073 && !long.class.equals(subClass) 074 && !Double.class.equals(subClass) 075 && !Float.class.equals(subClass) 076 && !Date.class.equals(subClass) 077 && !Enum.class.isAssignableFrom(subClass) 078 && !Object.class.equals(subClass)) { 079 loadComplexStructures(subClass.getName(), complexStructures); 080 } 081 } 082 } 083 084 public static Class<?> getActualClassFromList(Class<?> originalClass, String fieldName) { 085 if (originalClass.isInterface()) { 086 throw new RuntimeException("Interface used in getter, use xxxInfo instead for field: " + originalClass.getName() + "." + fieldName); 087 } 088 // recursively check super classes for field if not declared on this class 089 Class<?> classToCheck = originalClass; 090 while (true) { 091 try { 092 Field field = classToCheck.getDeclaredField(fieldName); 093 Type type = field.getGenericType(); 094 ParameterizedType pt = (ParameterizedType) type; 095 Type actualType = pt.getActualTypeArguments()[0]; 096 return (Class<?>) actualType; 097 } catch (NoSuchFieldException ex) { 098 classToCheck = classToCheck.getSuperclass(); 099 if (classToCheck == null) { 100 throw new RuntimeException("No such field: " + originalClass.getName() + "." + fieldName, ex); 101 } 102 if (classToCheck.equals(Object.class)) { 103 throw new RuntimeException("No such field: " + originalClass.getName() + "." + fieldName, ex); 104 } 105 } catch (SecurityException ex) { 106 throw new RuntimeException(originalClass.getName() + "." + fieldName, ex); 107 } 108 } 109 } 110 }