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 import org.kuali.student.contract.model.impl.ServiceContractModelPescXsdLoader;
032 import org.slf4j.Logger;
033 import org.slf4j.LoggerFactory;
034
035 public class ComplexSubstructuresHelper {
036
037 private static Logger log = LoggerFactory.getLogger(ComplexSubstructuresHelper.class);
038
039
040 public Set<String> getComplexStructures(String className) {
041 Set<String> complexStructures = new LinkedHashSet<String>();
042 loadComplexStructures(className, complexStructures);
043 return complexStructures;
044 }
045
046 private void loadComplexStructures(String className,
047 Set<String> complexStructures) {
048 if (!complexStructures.add(className)) {
049 return;
050 }
051 BeanInfo beanInfo;
052 Class<?> clazz;
053 try {
054 clazz = Thread.currentThread().getContextClassLoader().loadClass(className);
055 // had to change the standard Class.forName below to the above so it uses the right class loader
056 // that is defined in KSDictionaryDocMojo.java
057 // clazz = Class.forName(className);
058 } catch (ClassNotFoundException ex) {
059 log.warn("ComplexSubstructuresHelper: Could not process because the class must be a freestanding object: " + className);
060 return;
061 }
062 try {
063 beanInfo = Introspector.getBeanInfo(clazz);
064 } catch (IntrospectionException ex) {
065 throw new RuntimeException(ex);
066 }
067 for (PropertyDescriptor pd : beanInfo.getPropertyDescriptors()) {
068 Class<?> subClass = pd.getPropertyType();
069 if (List.class.equals(subClass)) {
070 // recursively check super classes for field if not declared on this class
071 subClass = getActualClassFromList(clazz, pd.getName());
072 }
073 if (!Class.class.equals(subClass)
074 && !String.class.equals(subClass)
075 && !Integer.class.equals(subClass)
076 && !Long.class.equals(subClass)
077 && !Boolean.class.equals(subClass)
078 && !boolean.class.equals(subClass)
079 && !int.class.equals(subClass)
080 && !long.class.equals(subClass)
081 && !Double.class.equals(subClass)
082 && !Float.class.equals(subClass)
083 && !Date.class.equals(subClass)
084 && !Enum.class.isAssignableFrom(subClass)
085 && !Object.class.equals(subClass)) {
086 loadComplexStructures(subClass.getName(), complexStructures);
087 }
088 }
089 }
090
091 public static Class<?> getActualClassFromList(Class<?> originalClass, String fieldName) {
092 if (originalClass.isInterface()) {
093 throw new RuntimeException("Interface used in getter, use xxxInfo instead for field: " + originalClass.getName() + "." + fieldName);
094 }
095 // recursively check super classes for field if not declared on this class
096 Class<?> classToCheck = originalClass;
097 while (true) {
098 try {
099 Field field = classToCheck.getDeclaredField(fieldName);
100 Type type = field.getGenericType();
101 ParameterizedType pt = (ParameterizedType) type;
102 Type actualType = pt.getActualTypeArguments()[0];
103 return (Class<?>) actualType;
104 } catch (NoSuchFieldException ex) {
105 classToCheck = classToCheck.getSuperclass();
106 if (classToCheck == null) {
107 throw new RuntimeException("No such field: " + originalClass.getName() + "." + fieldName, ex);
108 }
109 if (classToCheck.equals(Object.class)) {
110 throw new RuntimeException("No such field: " + originalClass.getName() + "." + fieldName, ex);
111 }
112 } catch (SecurityException ex) {
113 throw new RuntimeException(originalClass.getName() + "." + fieldName, ex);
114 }
115 }
116 }
117 }