blob: fc0748b62f7b917c2d757cba76b18f13713bdc9d [file] [log] [blame]
/* Copyright 2004 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.xmlbeans.impl.jam_old.provider;
import org.apache.xmlbeans.impl.jam_old.provider.EClassBuilder;
import org.apache.xmlbeans.impl.jam_old.editable.*;
import org.apache.xmlbeans.impl.jam_old.editable.impl.EClassImpl;
import org.apache.xmlbeans.impl.jam_old.JClassLoader;
import org.apache.xmlbeans.impl.jam_old.internal.JClassLoaderImpl;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Field;
import java.lang.reflect.Constructor;
/**
*
* @author Patrick Calahan <pcal@bea.com>
*/
public class ReflectionClassBuilder implements EClassBuilder {
// ========================================================================
// Constants
private static final boolean REALLY_VERBOSE = false;
// ========================================================================
// Variables
private ClassLoader mLoader;
/**
* @deprecated just to wean us off the R* impls.
*/
public static JClassLoader createRClassLoader(ClassLoader cl) {
return new JClassLoaderImpl(new ReflectionClassBuilder(cl));
}
public static EClassBuilder getSystemClassBuilder() {
return new ReflectionClassBuilder(ClassLoader.getSystemClassLoader());
}
// ========================================================================
// Constructors
public ReflectionClassBuilder(ClassLoader rcl) {
if (rcl == null) throw new IllegalArgumentException("null rcl");
mLoader = rcl;
}
// ========================================================================
// EClassBuilder implementation
public EClass build(String packageName,
String className,
JClassLoader loader) {
try {
Class rclass = mLoader.loadClass(packageName+"."+className);
EClass out = new EClassImpl(packageName, className, loader, null);
populate(out,rclass);
return out;
} catch(ClassNotFoundException cnfe) {
if (REALLY_VERBOSE) cnfe.printStackTrace();
return null;
}
}
// ========================================================================
// Private methods
private void populate(EClass dest, Class src) {
dest.setModifiers(src.getModifiers());
dest.setIsInterface(src.isInterface());
// set the superclass
Class s = src.getSuperclass();
if (s != null) dest.setSuperclass(s.getName());
// set the interfaces
Class[] ints = src.getInterfaces();
for(int i=0; i<ints.length; i++) dest.addInterface(ints[i].getName());
// add the fields
Field[] fields = src.getFields();
for(int i=0; i<fields.length; i++) populate(dest.addNewField(),fields[i]);
// add the methods
Method[] methods = src.getDeclaredMethods();
for(int i=0; i<methods.length; i++) populate(dest.addNewMethod(),methods[i]);
// add the constructors
Constructor[] ctors = src.getDeclaredConstructors();
for(int i=0; i<ctors.length; i++) populate(dest.addNewConstructor(),ctors[i]);
// add the annotations
add175Annotations(dest, src);
}
private void populate(EField dest, Field src) {
dest.setSimpleName(src.getName());
dest.setType(src.getType().getName());
dest.setModifiers(src.getModifiers());
}
private void populate(EConstructor dest, Constructor src) {
dest.setSimpleName(src.getName());
dest.setModifiers(src.getModifiers());
Class[] exceptions = src.getExceptionTypes();
Class[] params = src.getParameterTypes();
populate(dest,exceptions,params);
}
private void populate(EMethod dest, Method src) {
dest.setSimpleName(src.getName());
dest.setModifiers(src.getModifiers());
dest.setReturnType(src.getReturnType().getName());
Class[] exceptions = src.getExceptionTypes();
Class[] params = src.getParameterTypes();
populate(dest,exceptions,params);
}
private void populate(EInvokable dest, Class[] exceptions, Class[] params) {
for(int i=0; i<exceptions.length; i++) {
dest.addException(exceptions[i].getName());
}
for(int i=0; i<params.length; i++) {
EParameter p = dest.addNewParameter();
p.setSimpleName("param"+i);
p.setType(params[i].getName());
}
}
private void add175Annotations(EElement dest, Object src) {
/*Annotation[]*/Object[] anns = get175AnnotationsOn(src);
if (anns == null || anns.length == 0) return;
for(int i=0; i<anns.length; i++) {
populate(dest.addNewAnnotation(),anns[i]);
}
}
private void populate(EAnnotation dest, Object ann) {
dest.setSimpleName(ann.getClass().getName()); //REVIEW
dest.setAnnotationObject(ann);
dest.setDefinition(ann.getClass().getName());
populateAnnotationMembers(dest, ann, ann.getClass());
}
/**
* Introspects the src object for annotation member methods, invokes them
* and creates corresponding EAnnotationMembers in the given dest object.
*/
private void populateAnnotationMembers(EAnnotation dest,
Object src,
Class srcClass)
{
Method[] methods = srcClass.getDeclaredMethods();
for(int i=0; i<methods.length; i++) {
if (methods[i].getParameterTypes().length > 0) continue;
EAnnotationMember member = dest.addNewMember();
member.setSimpleName(methods[i].getName());
try {
member.setValue(methods[i].invoke(src,null));
} catch(IllegalAccessException iae) {
iae.printStackTrace(); // this is not expected
} catch(InvocationTargetException ite) {
ite.printStackTrace();
}
}
//REVIEW will it be a superclass or an interface? this might be broken
srcClass = srcClass.getSuperclass();
if (srcClass != null &&
!srcClass.getName().equals("java.lang.annotation.Annotation") &&
!srcClass.getName().equals("java.lang.Object")) {
populateAnnotationMembers(dest,src,srcClass);
}
}
//FIXME this needs to support annotation inheritance
/**
* <p>Utility method for returning the java.lang.annoatation.Annotations
* associated with a given reflection object. This method accesses the
* annotations via reflection so that the code will still compile
* and run under 1.4.</p>
*/
private Object[] get175AnnotationsOn(Object reflectionThing) {
Method annGetter;
try {
annGetter = reflectionThing.getClass().getMethod("getDeclaredAnnotations",
null);
return (Object[])annGetter.invoke(reflectionThing,null);
} catch(NoSuchMethodException nsme) {
if (REALLY_VERBOSE) nsme.printStackTrace();
} catch(IllegalAccessException iae) {
iae.printStackTrace(); // this is not expected
} catch(InvocationTargetException ite) {
ite.printStackTrace();
}
return null;
}
private static String simpleName(Class clazz) {
String out = clazz.getName();
int dot = out.lastIndexOf('.');
if (dot != -1) out = out.substring(dot+1);
return out;
}
//salvaged from RClassLoader, may be useful for parser
private void validateClassName(String className)
throws IllegalArgumentException
{
if (!Character.isJavaIdentifierStart(className.charAt(0))) {
throw new IllegalArgumentException
("Invalid first character in class name: "+className);
}
for(int i=1; i<className.length(); i++) {
char c = className.charAt(i);
if (c == '.') {
if (className.charAt(i-1) == '.') {
throw new IllegalArgumentException
("'..' not allowed in class name: "+className);
}
if (i == className.length()-1) {
throw new IllegalArgumentException
("'.' not allowed at end of class name: "+className);
}
} else {
if (!Character.isJavaIdentifierPart(c)) {
throw new IllegalArgumentException
("Illegal character '"+c+"' in class name: "+className);
}
}
}
}
}