Subversion Repositories bacoAlunos

Rev

Blame | Last modification | View Log | RSS feed

package com.owlike.genson.reflect;

import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import static com.owlike.genson.Trilean.FALSE;
import static com.owlike.genson.Trilean.TRUE;

import com.owlike.genson.JsonBindingException;
import com.owlike.genson.Trilean;
import com.owlike.genson.annotation.JsonCreator;
import com.owlike.genson.annotation.JsonIgnore;
import com.owlike.genson.annotation.JsonProperty;

/**
 * BeanMutatorAccessorResolver interface must be implemented by class who want to resolve mutators
 * (fields or methods that allow you to modify a property), accessors (fields or methods that allow
 * you to retrieve the value of a property) and creators (constructors or static methods that allow
 * you to create objects).
 * <p/>
 * All methods return a {@link com.owlike.genson.Trilean Trilean}, so it may be TRUE, FALSE or UNKNOWN.
 * This will allow us to separate the kind of information each implementation works on (one for
 * annotations, another for visibility, etc) and to chain them. It also allows an easier addition of
 * new features without modifying the existing code. Have a look at <a href=
 * "http://code.google.com/p/genson/source/browse/src/main/java/com/owlike/genson/reflect/BeanMutatorAccessorResolver.java"
 * >StandardMutaAccessorResolver</a> for an example of BeanMutatorAccessorResolver implementation.
 * <p/>
 * To register your own implementation instead of the one by default use the genson builder.
 * <p/>
 * <pre>
 * new Genson.Builder().set(yourImplementation).create();
 * </pre>
 *
 * @author eugen
 * @see com.owlike.genson.Trilean Trilean
 * @see StandardMutaAccessorResolver
 * @see AbstractBeanDescriptorProvider
 * @see BaseBeanDescriptorProvider
 * @see BeanViewDescriptorProvider
 */

public interface BeanMutatorAccessorResolver {
  Trilean isCreator(Constructor<?> constructor, Class<?> fromClass);

  Trilean isCreator(1.5.0/docs/api/java/lang/reflect/Method.html">Method method, Class<?> fromClass);

  Trilean isAccessor(1.5.0/docs/api/java/lang/reflect/Field.html">Field field, Class<?> fromClass);

  Trilean isAccessor(1.5.0/docs/api/java/lang/reflect/Method.html">Method method, Class<?> fromClass);

  Trilean isMutator(1.5.0/docs/api/java/lang/reflect/Field.html">Field field, Class<?> fromClass);

  Trilean isMutator(1.5.0/docs/api/java/lang/reflect/Method.html">Method method, Class<?> fromClass);

  class PropertyBaseResolver implements BeanMutatorAccessorResolver {
    @1.5.0/docs/api/java/lang/Override.html">Override
    public Trilean isAccessor(1.5.0/docs/api/java/lang/reflect/Field.html">Field field, Class<?> fromClass) {
      return Trilean.5+0%2Fdocs%2Fapi+UNKNOWN">UNKNOWN;
    }

    @1.5.0/docs/api/java/lang/Override.html">Override
    public Trilean isAccessor(1.5.0/docs/api/java/lang/reflect/Method.html">Method method, Class<?> fromClass) {
      return Trilean.5+0%2Fdocs%2Fapi+UNKNOWN">UNKNOWN;
    }

    @1.5.0/docs/api/java/lang/Override.html">Override
    public Trilean isCreator(Constructor<?> constructor, Class<?> fromClass) {
      return Trilean.5+0%2Fdocs%2Fapi+UNKNOWN">UNKNOWN;
    }

    @1.5.0/docs/api/java/lang/Override.html">Override
    public Trilean isCreator(1.5.0/docs/api/java/lang/reflect/Method.html">Method method, Class<?> fromClass) {
      return Trilean.5+0%2Fdocs%2Fapi+UNKNOWN">UNKNOWN;
    }

    @1.5.0/docs/api/java/lang/Override.html">Override
    public Trilean isMutator(1.5.0/docs/api/java/lang/reflect/Field.html">Field field, Class<?> fromClass) {
      return Trilean.5+0%2Fdocs%2Fapi+UNKNOWN">UNKNOWN;
    }

    @1.5.0/docs/api/java/lang/Override.html">Override
    public Trilean isMutator(1.5.0/docs/api/java/lang/reflect/Method.html">Method method, Class<?> fromClass) {
      return Trilean.5+0%2Fdocs%2Fapi+UNKNOWN">UNKNOWN;
    }
  }

  class CompositeResolver implements BeanMutatorAccessorResolver {
    private List<BeanMutatorAccessorResolver> components;

    public CompositeResolver(List<BeanMutatorAccessorResolver> components) {
      if (components == null || components.isEmpty()) {
        throw new 1.5.0/docs/api/java/lang/IllegalArgumentException.html">IllegalArgumentException(
          "The composite resolver must have at least one resolver as component!");
      }
      this.components = new LinkedList<BeanMutatorAccessorResolver>(components);
    }

    public CompositeResolver add(BeanMutatorAccessorResolver... resolvers) {
      components.addAll(0, 1.5.0/docs/api/java/util/Arrays.html">Arrays.asList(resolvers));
      return this;
    }

    @1.5.0/docs/api/java/lang/Override.html">Override
    public Trilean isAccessor(1.5.0/docs/api/java/lang/reflect/Field.html">Field field, Class<?> fromClass) {
      Trilean resolved = Trilean.5+0%2Fdocs%2Fapi+UNKNOWN">UNKNOWN;
      for (Iterator<BeanMutatorAccessorResolver> it = components.iterator(); resolved == null || resolved.equals(Trilean.5+0%2Fdocs%2Fapi+UNKNOWN">UNKNOWN)
        && it.hasNext(); ) {
        resolved = it.next().isAccessor(field, fromClass);
      }
      return resolved;
    }

    @1.5.0/docs/api/java/lang/Override.html">Override
    public Trilean isAccessor(1.5.0/docs/api/java/lang/reflect/Method.html">Method method, Class<?> fromClass) {
      Trilean resolved = Trilean.5+0%2Fdocs%2Fapi+UNKNOWN">UNKNOWN;
      for (Iterator<BeanMutatorAccessorResolver> it = components.iterator(); resolved == null || resolved.equals(Trilean.5+0%2Fdocs%2Fapi+UNKNOWN">UNKNOWN)
        && it.hasNext(); ) {
        resolved = it.next().isAccessor(method, fromClass);
      }
      return resolved;
    }

    @1.5.0/docs/api/java/lang/Override.html">Override
    public Trilean isCreator(Constructor<?> constructor, Class<?> fromClass) {
      Trilean resolved = Trilean.5+0%2Fdocs%2Fapi+UNKNOWN">UNKNOWN;
      for (Iterator<BeanMutatorAccessorResolver> it = components.iterator(); resolved == null || resolved.equals(Trilean.5+0%2Fdocs%2Fapi+UNKNOWN">UNKNOWN)
        && it.hasNext(); ) {
        resolved = it.next().isCreator(constructor, fromClass);
      }
      return resolved;
    }

    @1.5.0/docs/api/java/lang/Override.html">Override
    public Trilean isCreator(1.5.0/docs/api/java/lang/reflect/Method.html">Method method, Class<?> fromClass) {
      Trilean resolved = Trilean.5+0%2Fdocs%2Fapi+UNKNOWN">UNKNOWN;
      for (Iterator<BeanMutatorAccessorResolver> it = components.iterator(); resolved == null || resolved.equals(Trilean.5+0%2Fdocs%2Fapi+UNKNOWN">UNKNOWN)
        && it.hasNext(); ) {
        resolved = it.next().isCreator(method, fromClass);
      }
      return resolved;
    }

    @1.5.0/docs/api/java/lang/Override.html">Override
    public Trilean isMutator(1.5.0/docs/api/java/lang/reflect/Field.html">Field field, Class<?> fromClass) {
      Trilean resolved = Trilean.5+0%2Fdocs%2Fapi+UNKNOWN">UNKNOWN;
      for (Iterator<BeanMutatorAccessorResolver> it = components.iterator(); resolved == null || resolved.equals(Trilean.5+0%2Fdocs%2Fapi+UNKNOWN">UNKNOWN)
        && it.hasNext(); ) {
        resolved = it.next().isMutator(field, fromClass);
      }
      return resolved;
    }

    @1.5.0/docs/api/java/lang/Override.html">Override
    public Trilean isMutator(1.5.0/docs/api/java/lang/reflect/Method.html">Method method, Class<?> fromClass) {
      Trilean resolved = Trilean.5+0%2Fdocs%2Fapi+UNKNOWN">UNKNOWN;
      for (Iterator<BeanMutatorAccessorResolver> it = components.iterator(); resolved == null || resolved.equals(Trilean.5+0%2Fdocs%2Fapi+UNKNOWN">UNKNOWN)
        && it.hasNext(); ) {
        resolved = it.next().isMutator(method, fromClass);
      }
      return resolved;
    }
  }

  class GensonAnnotationsResolver implements BeanMutatorAccessorResolver {
    public Trilean isAccessor(1.5.0/docs/api/java/lang/reflect/Field.html">Field field, Class<?> fromClass) {
      // ok to look for this$ is ugly but it will do the job for the moment
      if (mustIgnore(field, true) || field.getName().startsWith("this$"))
        return FALSE;
      if (mustInclude(field, true))
        return TRUE;
      return Trilean.5+0%2Fdocs%2Fapi+UNKNOWN">UNKNOWN;
    }

    public Trilean isAccessor(1.5.0/docs/api/java/lang/reflect/Method.html">Method method, Class<?> fromClass) {
      if (mustIgnore(method, true))
        return FALSE;
      if (mustInclude(method, true) && method.getParameterTypes().length == 0)
        return TRUE;

      return Trilean.5+0%2Fdocs%2Fapi+UNKNOWN">UNKNOWN;
    }

    public Trilean isCreator(Constructor<?> constructor, Class<?> fromClass) {
      /*
                         * hum... it depends on different things, such as parameters name resolution, types, etc
                         * but we are not supposed to handle it here... lets only check visibility and handle it
                         * in the provider implementations
                         */

      if (mustIgnore(constructor, false))
        return FALSE;
      return Trilean.5+0%2Fdocs%2Fapi+UNKNOWN">UNKNOWN;
    }

    public Trilean isCreator(1.5.0/docs/api/java/lang/reflect/Method.html">Method method, Class<?> fromClass) {
      if (method.getAnnotation(JsonCreator.class) != null) {
        if (1.5.0/docs/api/java/lang/reflect/Modifier.html">Modifier.isPublic(method.getModifiers())
          && 1.5.0/docs/api/java/lang/reflect/Modifier.html">Modifier.isStatic(method.getModifiers()))
          return TRUE;
        throw new JsonBindingException("Method " + method.toGenericString()
          + " annotated with @JsonCreator must be static!");
      }
      return FALSE;
    }

    public Trilean isMutator(1.5.0/docs/api/java/lang/reflect/Field.html">Field field, Class<?> fromClass) {
      if (mustIgnore(field, false) || field.getName().startsWith("this$"))
        return FALSE;
      if (mustInclude(field, false))
        return TRUE;
      return Trilean.5+0%2Fdocs%2Fapi+UNKNOWN">UNKNOWN;
    }

    public Trilean isMutator(1.5.0/docs/api/java/lang/reflect/Method.html">Method method, Class<?> fromClass) {
      if (mustIgnore(method, false))
        return FALSE;
      if (mustInclude(method, false) && method.getParameterTypes().length == 1)
        return TRUE;

      return Trilean.5+0%2Fdocs%2Fapi+UNKNOWN">UNKNOWN;
    }

    protected boolean mustIgnore(1.5.0/docs/api/java/lang/reflect/AccessibleObject.html">AccessibleObject property, boolean forSerialization) {
      JsonIgnore ignore = property.getAnnotation(JsonIgnore.class);
      if (ignore != null) {
        if (forSerialization)
          return !ignore.serialize();
        else
          return !ignore.deserialize();
      }
      return false;
    }

    protected boolean mustInclude(1.5.0/docs/api/java/lang/reflect/AccessibleObject.html">AccessibleObject property, boolean forSerialization) {
      JsonProperty prop = property.getAnnotation(JsonProperty.class);
      if (prop != null) {
        if (forSerialization)
          return prop.serialize();
        else
          return prop.deserialize();
      }
      return false;
    }
  }

  /**
   * Standard implementation of BeanMutatorAccessorResolver.
   * Actually this implementation handles filtering by signature conventions (Java Bean) and visibility.
   *
   * @author eugen
   */

  class StandardMutaAccessorResolver implements BeanMutatorAccessorResolver {
    private final VisibilityFilter fieldVisibilityFilter;
    private final VisibilityFilter methodVisibilityFilter;
    private final VisibilityFilter creatorVisibilityFilter;

    /**
     * Creates a new instance of StandardMutaAccessorResolver with
     * {@link VisibilityFilter#PACKAGE_PUBLIC} visibility for fields,
     * {@link VisibilityFilter#PACKAGE_PUBLIC} visibility for methods and creators.
     */

    public StandardMutaAccessorResolver() {
      this(VisibilityFilter.PACKAGE_PUBLIC, VisibilityFilter.PACKAGE_PUBLIC,
        VisibilityFilter.PACKAGE_PUBLIC);
    }

    /**
     * Use this constructor if you want to customize the visibility filtering.
     *
     * @param filedVisibilityFilter
     * @param methodVisibilityFilter
     * @param creatorVisibilityFilter
     */

    public StandardMutaAccessorResolver(VisibilityFilter filedVisibilityFilter,
                                        VisibilityFilter methodVisibilityFilter, VisibilityFilter creatorVisibilityFilter) {
      super();
      this.fieldVisibilityFilter = filedVisibilityFilter;
      this.methodVisibilityFilter = methodVisibilityFilter;
      this.creatorVisibilityFilter = creatorVisibilityFilter;
    }

    /**
     * Will resolve all public/package and non transient/static fields as accesssors.
     */

    public Trilean isAccessor(1.5.0/docs/api/java/lang/reflect/Field.html">Field field, Class<?> fromClass) {
      return Trilean.valueOf(fieldVisibilityFilter.isVisible(field));
    }

    /**
     * Resolves all public methods starting with get/is (boolean) and parameter less as
     * accessors.
     */

    public Trilean isAccessor(1.5.0/docs/api/java/lang/reflect/Method.html">Method method, Class<?> fromClass) {
      if (!method.isBridge()) {
        1.5.0/docs/api/java/lang/String.html">String name = method.getName();
        int len = name.length();
        if (methodVisibilityFilter.isVisible(method)
          && ((len > 3 && name.startsWith("get")) || (len > 2 && name.startsWith("is") && (TypeUtil
          .match(TypeUtil.expandType(method.getGenericReturnType(), fromClass),
            1.5.0/docs/api/java/lang/Boolean.html">Boolean.class, false) || TypeUtil.match(
          method.getGenericReturnType(), boolean.class, false))))
          && method.getParameterTypes().length == 0)
          return TRUE;
      }

      return FALSE;
    }

    public Trilean isCreator(Constructor<?> constructor, Class<?> fromClass) {
      return Trilean.valueOf(creatorVisibilityFilter.isVisible(constructor));
    }

    public Trilean isCreator(1.5.0/docs/api/java/lang/reflect/Method.html">Method method, Class<?> fromClass) {
      return FALSE;
    }

    public Trilean isMutator(1.5.0/docs/api/java/lang/reflect/Field.html">Field field, Class<?> fromClass) {
      return Trilean.valueOf(fieldVisibilityFilter.isVisible(field));
    }

    public Trilean isMutator(1.5.0/docs/api/java/lang/reflect/Method.html">Method method, Class<?> fromClass) {
      if (!method.isBridge()) {
        if (methodVisibilityFilter.isVisible(method) && method.getName().length() > 3
          && method.getName().startsWith("set") && method.getParameterTypes().length == 1
          && method.getReturnType() == void.class)
          return TRUE;
      }

      return FALSE;
    }
  }

}