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 }