jexx.bean.SimpleBeanInfo Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jexx-bean Show documentation
Show all versions of jexx-bean Show documentation
This is a simple tool for java!
The newest version!
package jexx.bean;
import java.awt.*;
import java.beans.*;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.List;
public class SimpleBeanInfo implements BeanInfo {
private final BeanInfo delegate;
private final Set propertyDescriptors = new TreeSet<>(new PropertyDescriptorComparator());
public SimpleBeanInfo(BeanInfo delegate) {
this.delegate = delegate;
for (PropertyDescriptor pd : delegate.getPropertyDescriptors()) {
try {
this.propertyDescriptors.add(pd instanceof IndexedPropertyDescriptor ?
new SimpleIndexedPropertyDescriptor((IndexedPropertyDescriptor) pd) :
new SimplePropertyDescriptor(pd));
}
catch (IntrospectionException ex) {
// Probably simply a method that wasn't meant to follow the JavaBeans pattern...
}
}
MethodDescriptor[] methodDescriptors = delegate.getMethodDescriptors();
if (methodDescriptors != null) {
for (Method method : findCandidateWriteMethods(methodDescriptors)) {
try {
handleWriteMethod(method);
}
catch (IntrospectionException ex) {
// We're only trying to find candidates, can easily ignore extra ones here...
}
}
}
}
/**
* 找到候选写方法
* @param methodDescriptors 方法描述集合
*/
private java.util.List findCandidateWriteMethods(MethodDescriptor[] methodDescriptors) {
List matches = new ArrayList<>();
for (MethodDescriptor methodDescriptor : methodDescriptors) {
Method method = methodDescriptor.getMethod();
if (isWriteMethod(method)) {
matches.add(method);
}
}
// Sort non-void returning write methods to guard against the ill effects of
// non-deterministic sorting of methods returned from Class#getDeclaredMethods
// under JDK 7. See http://bugs.sun.com/view_bug.do?bug_id=7023180
matches.sort((m1, m2) -> m2.toString().compareTo(m1.toString()));
return matches;
}
/**
* 是否为候选写方法
* @param method 方法
*/
public static boolean isWriteMethod(Method method) {
String methodName = method.getName();
Class>[] parameterTypes = method.getParameterTypes();
int nParams = parameterTypes.length;
return (methodName.length() > 3 && methodName.startsWith("set") && Modifier.isPublic(method.getModifiers()) &&
(!void.class.isAssignableFrom(method.getReturnType()) || Modifier.isStatic(method.getModifiers())) &&
(nParams == 1 || (nParams == 2 && int.class == parameterTypes[0])));
}
/**
* 处理写方法;
* 方法参数长度是1时为PropertyDescriptor,是2时为IndexedPropertyDescriptor
* @param method 写方法
*/
private void handleWriteMethod(Method method) throws IntrospectionException {
int nParams = method.getParameterCount();
String propertyName = propertyNameFor(method);
Class> propertyType = method.getParameterTypes()[nParams - 1];
PropertyDescriptor existingPd = findExistingPropertyDescriptor(propertyName, propertyType);
if (nParams == 1) {
if (existingPd == null) {
this.propertyDescriptors.add(new SimplePropertyDescriptor(propertyName, null, method));
}
else {
existingPd.setWriteMethod(method);
}
}
else if (nParams == 2) {
if (existingPd == null) {
this.propertyDescriptors.add(
new SimpleIndexedPropertyDescriptor(propertyName, null, null, null, method));
}
else if (existingPd instanceof IndexedPropertyDescriptor) {
((IndexedPropertyDescriptor) existingPd).setIndexedWriteMethod(method);
}
else {
this.propertyDescriptors.remove(existingPd);
this.propertyDescriptors.add(new SimpleIndexedPropertyDescriptor(
propertyName, existingPd.getReadMethod(), existingPd.getWriteMethod(), null, method));
}
}
else {
throw new IllegalArgumentException("Write method must have exactly 1 or 2 parameters: " + method);
}
}
/**
* 方法对应的属性名称
* @param method 方法
*/
private String propertyNameFor(Method method) {
return Introspector.decapitalize(method.getName().substring(3, method.getName().length()));
}
/**
* 找到对应的属性描述
* @param propertyName 属性名称
* @param propertyType 属性类型
*/
private PropertyDescriptor findExistingPropertyDescriptor(String propertyName, Class> propertyType) {
for (PropertyDescriptor pd : this.propertyDescriptors) {
final Class> candidateType;
final String candidateName = pd.getName();
if (pd instanceof IndexedPropertyDescriptor) {
IndexedPropertyDescriptor ipd = (IndexedPropertyDescriptor) pd;
candidateType = ipd.getIndexedPropertyType();
if (candidateName.equals(propertyName) &&
(candidateType.equals(propertyType) || candidateType.equals(propertyType.getComponentType()))) {
return pd;
}
}
else {
candidateType = pd.getPropertyType();
if (candidateName.equals(propertyName) &&
(candidateType.equals(propertyType) || propertyType.equals(candidateType.getComponentType()))) {
return pd;
}
}
}
return null;
}
@Override
public BeanDescriptor getBeanDescriptor() {
return this.delegate.getBeanDescriptor();
}
@Override
public EventSetDescriptor[] getEventSetDescriptors() {
return this.delegate.getEventSetDescriptors();
}
@Override
public int getDefaultEventIndex() {
return this.delegate.getDefaultEventIndex();
}
@Override
public PropertyDescriptor[] getPropertyDescriptors() {
return this.propertyDescriptors.toArray(new PropertyDescriptor[0]);
}
@Override
public int getDefaultPropertyIndex() {
return this.delegate.getDefaultPropertyIndex();
}
@Override
public MethodDescriptor[] getMethodDescriptors() {
return this.delegate.getMethodDescriptors();
}
@Override
public BeanInfo[] getAdditionalBeanInfo() {
return this.delegate.getAdditionalBeanInfo();
}
@Override
public Image getIcon(int iconKind) {
return this.delegate.getIcon(iconKind);
}
static class SimplePropertyDescriptor extends PropertyDescriptor {
private Method readMethod;
private Method writeMethod;
private Class> propertyType;
private Class> propertyEditorClass;
public SimplePropertyDescriptor(PropertyDescriptor original) throws IntrospectionException {
this(original.getName(), original.getReadMethod(), original.getWriteMethod());
PropertyDescriptorUtil.copyNonMethodProperties(original, this);
}
public SimplePropertyDescriptor(String propertyName, Method readMethod, Method writeMethod)
throws IntrospectionException {
super(propertyName, null, null);
this.readMethod = readMethod;
this.writeMethod = writeMethod;
this.propertyType = PropertyDescriptorUtil.findPropertyType(readMethod, writeMethod);
}
public Method getReadMethod() {
return this.readMethod;
}
@Override
public void setReadMethod(Method readMethod) {
this.readMethod = readMethod;
}
@Override
public Method getWriteMethod() {
return this.writeMethod;
}
@Override
public void setWriteMethod(Method writeMethod) {
this.writeMethod = writeMethod;
}
@Override
public Class> getPropertyType() {
if (this.propertyType == null) {
try {
this.propertyType = PropertyDescriptorUtil.findPropertyType(this.readMethod, this.writeMethod);
}
catch (IntrospectionException ex) {
// Ignore, as does PropertyDescriptor#getPropertyType
}
}
return this.propertyType;
}
@Override
public Class> getPropertyEditorClass() {
return this.propertyEditorClass;
}
@Override
public void setPropertyEditorClass(Class> propertyEditorClass) {
this.propertyEditorClass = propertyEditorClass;
}
@Override
public boolean equals(Object other) {
return (this == other || (other instanceof PropertyDescriptor &&
PropertyDescriptorUtil.equals(this, (PropertyDescriptor) other)));
}
@Override
public String toString() {
return String.format("%s[name=%s, propertyType=%s, readMethod=%s, writeMethod=%s]",
getClass().getSimpleName(), getName(), getPropertyType(), this.readMethod, this.writeMethod);
}
}
static class SimpleIndexedPropertyDescriptor extends IndexedPropertyDescriptor {
private Method readMethod;
private Method writeMethod;
private Class> propertyType;
private Method indexedReadMethod;
private Method indexedWriteMethod;
private Class> indexedPropertyType;
public SimpleIndexedPropertyDescriptor(IndexedPropertyDescriptor original) throws IntrospectionException {
super(original.getName(), original.getReadMethod(), original.getWriteMethod(), original.getIndexedReadMethod(), original.getIndexedWriteMethod());
}
public SimpleIndexedPropertyDescriptor(String propertyName, Method readMethod, Method writeMethod, Method indexedReadMethod, Method indexedWriteMethod) throws IntrospectionException {
super(propertyName, readMethod, writeMethod, indexedReadMethod, indexedWriteMethod);
this.readMethod = readMethod;
this.writeMethod = writeMethod;
this.propertyType = PropertyDescriptorUtil.findPropertyType(readMethod, writeMethod);
this.indexedReadMethod = indexedReadMethod;
this.indexedWriteMethod = indexedWriteMethod;
this.indexedPropertyType = PropertyDescriptorUtil.findIndexedPropertyType(propertyName, this.propertyType, indexedReadMethod, indexedWriteMethod);
}
@Override
public Method getReadMethod() {
return readMethod;
}
@Override
public Method getWriteMethod() {
return writeMethod;
}
@Override
public Class> getPropertyType() {
if (this.propertyType == null) {
try {
this.propertyType = PropertyDescriptorUtil.findPropertyType(this.readMethod, this.writeMethod);
}
catch (IntrospectionException ex) {
// Ignore, as does IndexedPropertyDescriptor#getPropertyType
}
}
return this.propertyType;
}
@Override
public Method getIndexedReadMethod() {
return indexedReadMethod;
}
@Override
public Method getIndexedWriteMethod() {
return indexedWriteMethod;
}
@Override
public Class> getIndexedPropertyType() {
if (this.indexedPropertyType == null) {
try {
this.indexedPropertyType = PropertyDescriptorUtil.findIndexedPropertyType(
getName(), getPropertyType(), this.indexedReadMethod, this.indexedWriteMethod);
}
catch (IntrospectionException ex) {
// Ignore, as does IndexedPropertyDescriptor#getIndexedPropertyType
}
}
return this.indexedPropertyType;
}
@Override
public String toString() {
return String.format("%s[name=%s, propertyType=%s, indexedPropertyType=%s, " +
"readMethod=%s, writeMethod=%s, indexedReadMethod=%s, indexedWriteMethod=%s]",
getClass().getSimpleName(), getName(), getPropertyType(), getIndexedPropertyType(),
this.readMethod, this.writeMethod, this.indexedReadMethod, this.indexedWriteMethod);
}
}
static class PropertyDescriptorComparator implements Comparator {
@Override
public int compare(PropertyDescriptor desc1, PropertyDescriptor desc2) {
String left = desc1.getName();
String right = desc2.getName();
for (int i = 0; i < left.length(); i++) {
if (right.length() == i) {
return 1;
}
int result = left.getBytes()[i] - right.getBytes()[i];
if (result != 0) {
return result;
}
}
return left.length() - right.length();
}
}
}