Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* #%L
* JAXX :: Compiler
* %%
* Copyright (C) 2008 - 2020 Code Lutin, Ultreia.io
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* .
* #L%
*/
package org.nuiton.jaxx.compiler.beans;
import org.nuiton.jaxx.compiler.reflect.ClassDescriptor;
import org.nuiton.jaxx.compiler.reflect.ClassDescriptorHelper;
import org.nuiton.jaxx.compiler.reflect.MethodDescriptor;
import java.beans.BeanDescriptor;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyChangeListener;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.Enumeration;
import java.util.EventListener;
import java.util.HashMap;
import java.util.Map;
/**
* Performs introspection on a ClassDescriptor. Ideally, I could just have copied Sun's Introspector
* and changed a few things, but the licensing terms are incompatible. This implementation is incomplete -- it only
* bothers to report info that JAXX actually checks. It also relaxes some of Introspector's rules a bit, but I
* don't believe it results in any meaningful incompatibilities.
*
* JAXX uses its own introspector rather than the built-in
* java.beans.Introspector so that it can introspect {@link ClassDescriptor},
* not just java.lang.Class.
*/
public class JAXXIntrospector {
private final ClassDescriptor classDescriptor;
private final Map propertyDescriptors = new HashMap<>();
private final Map eventSetDescriptors = new HashMap<>();
private JAXXIntrospector(ClassDescriptor classDescriptor) {
this.classDescriptor = classDescriptor;
}
/**
* Returns the JAXXBeanInfo for a given class.
*
* @param classDescriptor the class to introspect
* @return the JAXXBeanInfo for the bean class
*/
public static JAXXBeanInfo getJAXXBeanInfo(ClassDescriptor classDescriptor) {
JAXXIntrospector introspector = new JAXXIntrospector(classDescriptor);
return introspector.createBeanInfo();
}
private JAXXBeanInfo createBeanInfo() {
ClassDescriptor explicitInfoClass = classDescriptor;
BeanInfo explicitBeanInfo = null;
while (explicitInfoClass != null) {
explicitBeanInfo = getExplicitBeanInfo(explicitInfoClass);
if (explicitBeanInfo != null) {
break;
}
explicitInfoClass = explicitInfoClass.getSuperclass();
}
if (explicitBeanInfo != null) {
PropertyDescriptor[] explicitProperties = explicitBeanInfo.getPropertyDescriptors();
for (PropertyDescriptor explicitProperty : explicitProperties) {
Class> type = explicitProperty.getPropertyType();
if (type == null) {
continue;
}
Method readMethod = explicitProperty.getReadMethod();
Method writeMethod = explicitProperty.getWriteMethod();
try {
ClassDescriptor typeDescriptor = null;
if (writeMethod != null) {
type = writeMethod.getParameterTypes()[0];
typeDescriptor = ClassDescriptorHelper.getClassDescriptor(writeMethod.getParameterTypes()[0].getName(), type.getClassLoader());
}
JAXXPropertyDescriptor propertyDescriptor = new JAXXPropertyDescriptor(classDescriptor, explicitProperty.getName(),
readMethod != null ? classDescriptor.getMethodDescriptor(readMethod.getName()) : null,
writeMethod != null ? classDescriptor.getMethodDescriptor(writeMethod.getName(), typeDescriptor) : null);
propertyDescriptor.setBound(explicitProperty.isBound());
Enumeration attributeNames = explicitProperty.attributeNames();
while (attributeNames.hasMoreElements()) {
String name = attributeNames.nextElement();
propertyDescriptor.setValue(name, explicitProperty.getValue(name));
}
propertyDescriptors.put(propertyDescriptor.getName(), propertyDescriptor);
} catch (ClassNotFoundException e) {
throw new RuntimeException("Internal error: Could not find ClassDescriptor corresponding to Java " + type, e);
} catch (NoSuchMethodException e) {
throw new RuntimeException("Internal error: Could not find expected MethodDescriptor in " + classDescriptor, e);
}
}
}
// if the class broadcasts PropertyChangeEvent, assume all properties are bound (java.beans.Introspector
// does the same)
boolean propertyChangeSource;
try {
classDescriptor.getMethodDescriptor("addPropertyChangeListener", ClassDescriptorHelper.getClassDescriptor(PropertyChangeListener.class));
propertyChangeSource = true;
} catch (NoSuchMethodException e) {
propertyChangeSource = false;
}
MethodDescriptor[] methods = classDescriptor.getMethodDescriptors();
for (MethodDescriptor method : methods) {
String name = method.getName();
if (name.startsWith("get") && name.length() > 3 && Character.isUpperCase(name.charAt(3)) && method.getParameterTypes().length == 0) {
String propertyName = Introspector.decapitalize(name.substring(3));
if (!propertyDescriptors.containsKey(propertyName)) {
propertyDescriptors.put(propertyName, new JAXXPropertyDescriptor(classDescriptor, propertyName, method, null, propertyChangeSource));
}
} else if (name.startsWith("is") && name.length() > 2 && Character.isUpperCase(name.charAt(2)) && method.getParameterTypes().length == 0) {
String propertyName = Introspector.decapitalize(name.substring(2));
if (!propertyDescriptors.containsKey(propertyName)) {
propertyDescriptors.put(propertyName, new JAXXPropertyDescriptor(classDescriptor, propertyName, method, null, propertyChangeSource));
}
} else if (name.startsWith("set") && name.length() > 3 && Character.isUpperCase(name.charAt(3)) && method.getParameterTypes().length == 1) {
String propertyName = Introspector.decapitalize(name.substring(3));
if (!propertyDescriptors.containsKey(propertyName)) {
propertyDescriptors.put(propertyName, new JAXXPropertyDescriptor(classDescriptor, propertyName, null, method, propertyChangeSource));
}
} else if (name.startsWith("add") && name.length() > 3 && Character.isUpperCase(name.charAt(3))) {
ClassDescriptor[] parameters = method.getParameterTypes();
if (parameters.length != 1 || !ClassDescriptorHelper.getClassDescriptor(EventListener.class).isAssignableFrom(parameters[0])) {
continue; // not an event listener method
}
try {
String eventSetName = method.getName().substring(3);
MethodDescriptor remove = classDescriptor.getMethodDescriptor("remove" + eventSetName, parameters);
eventSetDescriptors.put(eventSetName, new JAXXEventSetDescriptor(classDescriptor, eventSetName, method, remove, parameters[0].getMethodDescriptors()));
} catch (NoSuchMethodException e) {
// no matching remove method, not a valid event
}
}
}
JAXXBeanDescriptor beanDescriptor = new JAXXBeanDescriptor(classDescriptor);
if (explicitBeanInfo != null) {
BeanDescriptor explicitBeanDescriptor = explicitBeanInfo.getBeanDescriptor();
if (explicitBeanDescriptor != null) {
Enumeration attributeNames =
explicitBeanDescriptor.attributeNames();
while (attributeNames.hasMoreElements()) {
String name = attributeNames.nextElement();
Object value = explicitBeanDescriptor.getValue(name);
if ("containerDelegate".equals(name) && "".equals(value)) {
// Since java > 8 this returns an empty value and then breaks jaxx compiler
continue;
}
beanDescriptor.setValue(name, value);
}
}
}
return new JAXXBeanInfo(beanDescriptor,
propertyDescriptors.values().toArray(new JAXXPropertyDescriptor[0]),
eventSetDescriptors.values().toArray(new JAXXEventSetDescriptor[0]));
}
private static BeanInfo getExplicitBeanInfo(ClassDescriptor classDescriptor) {
try {
Class> beanClass = Class.forName(classDescriptor.getName(), true, classDescriptor.getClassLoader()); // see if there is a class by that name in this package
return Introspector.getBeanInfo(beanClass);
// Method findExplicitBeanInfo = Introspector.class.getDeclaredMethod("findExplicitBeanInfo", Class.class);
// findExplicitBeanInfo.setAccessible(true);
// return (BeanInfo) findExplicitBeanInfo.invoke(null, beanClass);
} catch (ClassNotFoundException | NoClassDefFoundError e) {
return null; // happens for uncompiled classes
// } catch (NoSuchMethodException e) {
// throw new RuntimeException("Error: could not find method 'findExplicitBeanInfo' in java.beans.Introspector. You are most likely running a version of Java against which JAXX has not been tested.");
// } catch (InvocationTargetException | IllegalAccessException e) {
// throw new RuntimeException(e);
} catch (IntrospectionException e) {
throw new RuntimeException(e);
}
}
}