blob: 78465453c92cf912363fb7b3f1d4a622d170cd57 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.directmemory.lightning.internal.util;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;
import org.apache.directmemory.lightning.exceptions.SerializerDefinitionException;
import org.apache.directmemory.lightning.metadata.Attribute;
import org.apache.directmemory.lightning.metadata.PropertyAccessor;
import org.apache.directmemory.lightning.metadata.PropertyDescriptor;
import org.objectweb.asm.Type;
public final class BeanUtil
{
private BeanUtil()
{
}
public static Set<Field> findPropertiesByClass( Class<?> type, Class<? extends Annotation> attributeAnnotation )
{
Set<Field> properties = new HashSet<Field>();
properties.addAll( findPropertiesByInstanceFields( type, attributeAnnotation ) );
properties.addAll( findPropertiesByMethods( type, type, attributeAnnotation ) );
properties.addAll( findPropertiesByInterfaces( type, attributeAnnotation ) );
if ( type.getSuperclass() != null && type.getSuperclass() != Object.class )
{
properties.addAll( findPropertiesByClass( type.getSuperclass(), attributeAnnotation ) );
}
return properties;
}
public static Set<Field> findPropertiesByInstanceFields( Class<?> type,
Class<? extends Annotation> attributeAnnotation )
{
Set<Field> attributes = new HashSet<Field>();
for ( Field field : type.getDeclaredFields() )
{
if ( field.isAnnotationPresent( attributeAnnotation ) )
{
attributes.add( field );
}
}
return attributes;
}
public static Set<Field> findPropertiesByMethods( Class<?> type, Class<?> searchType,
Class<? extends Annotation> attributeAnnotation )
{
Set<Field> attributes = new HashSet<Field>();
for ( Method method : searchType.getDeclaredMethods() )
{
if ( method.isAnnotationPresent( attributeAnnotation ) )
{
String propertyName = BeanUtil.buildPropertyName( method );
Field field = BeanUtil.getFieldByPropertyName( propertyName, type );
if ( field == null )
{
if ( attributeAnnotation == Attribute.class )
{
Attribute attribute = method.getAnnotation( Attribute.class );
field = BeanUtil.getFieldByPropertyName( attribute.property(), type );
}
if ( field == null )
{
throw new SerializerDefinitionException( "No property for method " + method + " was found" );
}
}
attributes.add( field );
}
}
return attributes;
}
public static Set<Field> findPropertiesByInterfaces( Class<?> type, Class<? extends Annotation> attributeAnnotation )
{
Set<Field> attributes = new HashSet<Field>();
for ( Class<?> interfaze : type.getInterfaces() )
{
// Add all annotated methods in interface
attributes.addAll( findInterfaceProperties0( type, interfaze, attributeAnnotation ) );
}
return attributes;
}
private static Set<Field> findInterfaceProperties0( Class<?> type, Class<?> interfaze,
Class<? extends Annotation> attributeAnnotation )
{
Set<Field> attributes = new HashSet<Field>();
// Add all annotated methods in interface
attributes.addAll( findPropertiesByMethods( type, interfaze, attributeAnnotation ) );
// Look up super-interface
if ( interfaze.getSuperclass() != null )
{
attributes.addAll( findInterfaceProperties0( type, interfaze.getSuperclass(), attributeAnnotation ) );
}
return attributes;
}
public static Field getFieldByPropertyName( String propertyName, Class<?> type )
{
try
{
return type.getDeclaredField( propertyName );
}
catch ( NoSuchFieldException e )
{
if ( type.getSuperclass() != null && type.getSuperclass() != Object.class )
{
return getFieldByPropertyName( propertyName, type.getSuperclass() );
}
return null;
}
}
public static Method findSetterMethod( Method method )
{
if ( method.getName().startsWith( "set" ) )
{
return method;
}
String propertyName = StringUtil.toUpperCamelCase( extractPropertyName( method.getName() ) );
Class<?> type = method.getReturnType();
Class<?> clazz = method.getDeclaringClass();
String setterName = "set" + propertyName;
try
{
return clazz.getDeclaredMethod( setterName, type );
}
catch ( Exception e )
{
// Seems there's no setter, so ignore all exceptions
return null;
}
}
public static Method findArraySetterMethod( Method method )
{
if ( method.getName().startsWith( "set" ) )
{
return method;
}
String propertyName = StringUtil.toUpperCamelCase( extractPropertyName( method.getName() ) );
Class<?> type = method.getReturnType();
Class<?> clazz = method.getDeclaringClass();
String setterName = "set" + propertyName;
try
{
return clazz.getDeclaredMethod( setterName, type, int.class );
}
catch ( Exception e )
{
// Seems there's no setter, so ignore all exceptions
return null;
}
}
public static Method findGetterMethod( Method method )
{
if ( method.getName().startsWith( "get" ) || method.getName().startsWith( "is" ) )
{
return method;
}
String propertyName = StringUtil.toUpperCamelCase( extractPropertyName( method.getName() ) );
Class<?> type = method.getParameterTypes()[0];
Class<?> clazz = method.getDeclaringClass();
String getterObjectName = "get" + propertyName;
String getterBooleanName = "is" + propertyName;
try
{
return clazz.getDeclaredMethod( getterObjectName, type );
}
catch ( Exception e )
{
if ( type == boolean.class )
{
try
{
return clazz.getDeclaredMethod( getterBooleanName, type );
}
catch ( Exception ex )
{
// Intentionally left blank - just fall through
}
}
// Seems there's no setter, so ignore all exceptions
return null;
}
}
public static Method findArrayGetterMethod( Method method )
{
if ( method.getName().startsWith( "get" ) || method.getName().startsWith( "is" ) )
{
return method;
}
String propertyName = StringUtil.toUpperCamelCase( extractPropertyName( method.getName() ) );
Class<?> type = method.getParameterTypes()[0];
Class<?> clazz = method.getDeclaringClass();
String getterObjectName = "get" + propertyName;
String getterBooleanName = "is" + propertyName;
try
{
return clazz.getDeclaredMethod( getterObjectName, type );
}
catch ( Exception e )
{
if ( type == boolean.class )
{
try
{
return clazz.getDeclaredMethod( getterBooleanName, type, int.class );
}
catch ( Exception ex )
{
// Intentionally left blank - just fall through
}
}
// Seems there's no setter, so ignore all exceptions
return null;
}
}
public static String buildPropertyName( Method method )
{
return buildPropertyName( method.getName() );
}
public static String buildPropertyName( String methodName )
{
return StringUtil.toLowerCamelCase( extractPropertyName( methodName ) );
}
public static String buildInternalSignature( Iterable<PropertyDescriptor> propertyDescriptors )
{
StringBuilder internalSignature = new StringBuilder();
for ( PropertyDescriptor propertyDescriptor : propertyDescriptors )
{
internalSignature.append( propertyDescriptor.getInternalSignature() );
}
return internalSignature.toString();
}
public static <T> String buildInternalSignature( String propertyName, PropertyAccessor propertyAccessor )
{
String type = Type.getDescriptor( propertyAccessor.getType() );
return new StringBuilder( "{" ).append( propertyName ).append( "}" ).append( type ).toString();
}
private static String extractPropertyName( String methodName )
{
if ( methodName.toUpperCase().startsWith( "GET" ) || methodName.toUpperCase().startsWith( "IS" )
|| methodName.toUpperCase().startsWith( "SET" ) )
{
char[] characters = methodName.toCharArray();
for ( int i = 1; i < characters.length; i++ )
{
if ( Character.isUpperCase( characters[i] ) )
{
return StringUtil.toLowerCamelCase( methodName.substring( i ) );
}
}
}
return StringUtil.toLowerCamelCase( methodName );
}
}