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 }