package org.skyscreamer.yoga.configuration; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.util.ArrayList; import java.util.Collection; import java.util.List; import org.skyscreamer.yoga.annotations.ExtraField; import org.skyscreamer.yoga.exceptions.YogaRuntimeException; import org.skyscreamer.yoga.selector.Property; /** * Interface for a class that configures an entity. An implementation of this interface must return the class being * configured. It can be used instead of or in conjunction with entity-level annotations. * * @see SimpleYogaEntityConfiguration * @see org.skyscreamer.yoga.annotations.Core */ public abstract class YogaEntityConfiguration<T> { private volatile Class<T> _instanceClass = null; @SuppressWarnings("unchecked") public YogaEntityConfiguration() { try { _instanceClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]; } catch (ClassCastException e) { throw new YogaRuntimeException("Unable to initialize class " + getClass().getName() + " because " + "entity class could not be determined. Either specify it in the generic type when extending " + "YogaEntityConfiguration, or explicitly override getEntityClass() with the correct value."); } } /** * Identifies the class supported by this configuration. * * @return A class object for the entity being configured */ public Class<T> getEntityClass() { return _instanceClass; } /** * Returns a collection of core fields for an entity. Core fields are returned by default, and do not require a * selector. If an empty collection is returned no fields are considered core. If a null is returned, this setting * will be ignored and the entity will be analyzed for core annotations. Except in the case of a null being * returned, this configuration overrides (rather than extends) the entity configuration. * * @return The collection of core field names */ public Collection<String> getCoreFields() { return null; } /** * Returns a collection of fields that can be selected on an entity similar to getSelectableFields(). * This gives you the opportunity to use a serialization method other than reflection. * * @return The collection of Property objects used for serialization * @see Property */ public Collection<Property<T>> getProperties() { return null; } /** * Returns a collection of fields that can be selected on an entity. If an empty collection is return, nothing can * be selected. If a null is returned, this setting is ignored, and all getters on an entity and extra fields can * be selected. * * @return */ public Collection<String> getSelectableFields() { return null; } /** * Specifies the template for the URL represented by this entity. This overrides any definition of @URITemplate * in the entity itself. If this method returns null, it will default back to entity-specified behavior. * * @return A URITemplate, or null if the entity should be examined for the template value. */ public String getURITemplate() { return null; } /** * This method returns a list of valid extra field methods on this object. * * A valid field must: * 1. Be annotated with @ExtraField * 2. Take either no parameters, or a single parameter with the entity supported by the configuration * * @return A list of method objects */ public List<Method> getExtraFieldMethods() { return getExtraFieldMethods( new ArrayList<Method>(), getClass() ); } private List<Method> getExtraFieldMethods(List<Method> result, Class<?> current) { for ( Method method : current.getDeclaredMethods() ) { Class<?>[] parameterTypes = method.getParameterTypes(); if ( method.isAnnotationPresent( ExtraField.class ) && (parameterTypes.length == 0 || (parameterTypes.length == 1 && parameterTypes[0].equals( getEntityClass() )))) { result.add( method ); } } if(current.getSuperclass() != null) { getExtraFieldMethods( result, current.getSuperclass() ); } return result; } /** * This method returns a list of the field names for @ExtraField methods in this object. * * @return A list of string field names */ public List<String> getExtraFieldNames() { List<String> result = new ArrayList<String>(); for (Method method : getExtraFieldMethods()) { ExtraField extraField = method.getAnnotation( ExtraField.class ); result.add( extraField.value() ); } return result; } }