package er.rest;
import java.beans.BeanInfo;
import java.beans.IndexedPropertyDescriptor;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.MethodDescriptor;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import com.webobjects.eocontrol.EOClassDescription;
import com.webobjects.foundation.NSArray;
import com.webobjects.foundation.NSForwardException;
import com.webobjects.foundation.NSMutableArray;
public class BeanInfoClassDescription extends EOClassDescription implements IERXNonEOClassDescription {
private BeanInfo _beanInfo;
public BeanInfoClassDescription(Class clazz) {
if (clazz == null) {
throw new NullPointerException("You must provide a class name.");
}
try {
_beanInfo = Introspector.getBeanInfo(clazz);
}
catch (IntrospectionException e) {
throw NSForwardException._runtimeExceptionForThrowable(e);
}
}
@Override
public String entityName() {
return _beanInfo.getBeanDescriptor().getBeanClass().getSimpleName();
}
@Override
public Class classForAttributeKey(String key) {
for (PropertyDescriptor descriptor : _beanInfo.getPropertyDescriptors()) {
if (descriptor.getName().equals(key) && isAttribute(descriptor)) {
return descriptor.getPropertyType();
}
}
return null;
}
protected boolean isAttribute(PropertyDescriptor descriptor) {
return isAttribute(descriptor.getPropertyType());
}
protected boolean isAttribute(Class type) {
return ERXRestUtils.isPrimitive(type);
}
protected boolean isToMany(PropertyDescriptor descriptor) {
return isToMany(descriptor.getPropertyType());
}
protected boolean isToMany(Class type) {
return List.class.isAssignableFrom(type);
}
public boolean isAttributeMethod(String methodName) {
for (MethodDescriptor descriptor : _beanInfo.getMethodDescriptors()) {
Method descriptorMethod = descriptor.getMethod();
Class descriptorReturnType = descriptorMethod.getReturnType();
if (descriptor.getName().equals(methodName) && descriptorReturnType != void.class && descriptorMethod.getParameterTypes().length == 0 && isAttribute(descriptorReturnType)) {
return true;
}
}
return false;
}
public boolean isToOneMethod(String methodName) {
for (MethodDescriptor descriptor : _beanInfo.getMethodDescriptors()) {
Method descriptorMethod = descriptor.getMethod();
Class descriptorReturnType = descriptorMethod.getReturnType();
if (descriptor.getName().equals(methodName) && descriptorReturnType != void.class && descriptorMethod.getParameterTypes().length == 0 && !isAttribute(descriptorReturnType) && !isToMany(descriptorReturnType)) {
return true;
}
}
return false;
}
public boolean isToManyMethod(String methodName) {
for (MethodDescriptor descriptor : _beanInfo.getMethodDescriptors()) {
Method descriptorMethod = descriptor.getMethod();
Class descriptorReturnType = descriptorMethod.getReturnType();
if (descriptor.getName().equals(methodName) && descriptorReturnType != void.class && descriptorMethod.getParameterTypes().length == 0 && isToMany(descriptorReturnType)) {
return true;
}
}
return false;
}
@Override
public NSArray<String> attributeKeys() {
NSMutableArray<String> attributes = new NSMutableArray<>();
for (PropertyDescriptor descriptor : _beanInfo.getPropertyDescriptors()) {
if (isAttribute(descriptor)) {
attributes.addObject(descriptor.getName());
}
}
return attributes;
}
@Override
public NSArray<String> toOneRelationshipKeys() {
NSMutableArray<String> relationships = new NSMutableArray<>();
for (PropertyDescriptor descriptor : _beanInfo.getPropertyDescriptors()) {
if (!isAttribute(descriptor) && !isToMany(descriptor) && !"class".equals(descriptor.getName())) {
relationships.addObject(descriptor.getName());
}
}
return relationships;
}
@Override
public NSArray<String> toManyRelationshipKeys() {
NSMutableArray<String> relationships = new NSMutableArray<>();
for (PropertyDescriptor descriptor : _beanInfo.getPropertyDescriptors()) {
if (isToMany(descriptor)) {
relationships.addObject(descriptor.getName());
}
}
return relationships;
}
protected Class<?> toManyComponentType(Type componentType) {
Class<?> componentTypeClass = Object.class;
if (componentType instanceof ParameterizedType) {
Type[] typeArguments = ((ParameterizedType) componentType).getActualTypeArguments();
if (typeArguments.length == 1) {
componentTypeClass = (Class<?>) typeArguments[0];
}
}
return componentTypeClass;
}
@Override
public EOClassDescription classDescriptionForDestinationKey(String detailKey) {
for (PropertyDescriptor descriptor : _beanInfo.getPropertyDescriptors()) {
if (descriptor.getName().equals(detailKey)) {
if (isToMany(descriptor)) {
if (descriptor instanceof IndexedPropertyDescriptor) {
return ERXRestClassDescriptionFactory.classDescriptionForClass(((IndexedPropertyDescriptor)descriptor).getIndexedPropertyType(), true);
}
else {
Type componentType = null;
Method method = descriptor.getReadMethod();
if (method != null) {
componentType = method.getGenericReturnType();
}
else {
method = descriptor.getWriteMethod();
if (method != null) {
componentType = method.getGenericParameterTypes()[0];
}
}
return ERXRestClassDescriptionFactory.classDescriptionForClass(toManyComponentType(componentType), true);
}
}
else {
return ERXRestClassDescriptionFactory.classDescriptionForClass(descriptor.getPropertyType(), false);
}
}
}
// If we didn't find a getMethod, fall back and look for any method with that name
for (MethodDescriptor descriptor : _beanInfo.getMethodDescriptors()) {
Method descriptorMethod = descriptor.getMethod();
Class<?> descriptorReturnType = descriptorMethod.getReturnType();
if (descriptor.getName().equals(detailKey) && descriptorReturnType != void.class && descriptorMethod.getParameterTypes().length == 0) {
if (isToMany(descriptorReturnType)) {
return ERXRestClassDescriptionFactory.classDescriptionForClass(toManyComponentType(descriptorMethod.getGenericReturnType()), true);
}
else {
return ERXRestClassDescriptionFactory.classDescriptionForClass(descriptorReturnType, false);
}
}
}
return null;
}
@Override
public Object createInstance() {
try {
return _beanInfo.getBeanDescriptor().getBeanClass().newInstance();
}
catch (Exception e) {
throw NSForwardException._runtimeExceptionForThrowable(e);
}
}
}