Package com.google.gwt.autobean.server

Source Code of com.google.gwt.autobean.server.ProxyAutoBean$Data

/*
* Copyright 2010 Google Inc.
*
* Licensed 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 com.google.gwt.autobean.server;

import com.google.gwt.autobean.server.impl.TypeUtils;
import com.google.gwt.autobean.shared.AutoBean;
import com.google.gwt.autobean.shared.AutoBeanFactory;
import com.google.gwt.autobean.shared.AutoBeanUtils;
import com.google.gwt.autobean.shared.AutoBeanVisitor;
import com.google.gwt.autobean.shared.impl.AbstractAutoBean;
import com.google.gwt.core.client.impl.WeakMapping;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;

/**
* An implementation of an AutoBean that uses reflection.
*
* @param <T> the type of interface being wrapped
*/
class ProxyAutoBean<T> extends AbstractAutoBean<T> {
  private static class Data {
    final List<Method> getters = new ArrayList<Method>();
    final List<String> getterNames = new ArrayList<String>();
    final List<PropertyType> propertyType = new ArrayList<PropertyType>();
  }

  private enum PropertyType {
    VALUE, REFERENCE, COLLECTION, MAP;
  }

  private static final Map<Class<?>, Data> cache = new WeakHashMap<Class<?>, Data>();

  private static Data calculateData(Class<?> beanType) {
    Data toReturn;
    synchronized (cache) {
      toReturn = cache.get(beanType);
      if (toReturn == null) {
        toReturn = new Data();
        for (Method method : beanType.getMethods()) {
          if (BeanMethod.GET.matches(method)) {
            toReturn.getters.add(method);

            String name;
            PropertyName annotation = method.getAnnotation(PropertyName.class);
            if (annotation != null) {
              name = annotation.value();
            } else {
              name = method.getName();
              name = Character.toLowerCase(name.charAt(3))
                  + (name.length() >= 5 ? name.substring(4) : "");
            }
            toReturn.getterNames.add(name);

            Class<?> returnType = method.getReturnType();
            if (TypeUtils.isValueType(returnType)) {
              toReturn.propertyType.add(PropertyType.VALUE);
            } else if (Collection.class.isAssignableFrom(returnType)) {
              toReturn.propertyType.add(PropertyType.COLLECTION);
            } else if (Map.class.isAssignableFrom(returnType)) {
              toReturn.propertyType.add(PropertyType.MAP);
            } else {
              toReturn.propertyType.add(PropertyType.REFERENCE);
            }
          }
        }
        cache.put(beanType, toReturn);
      }
    }
    return toReturn;
  }

  private final Class<T> beanType;
  private final Configuration configuration;
  private final Data data;
  private final T shim;

  // These constructors mirror the generated constructors.
  @SuppressWarnings("unchecked")
  public ProxyAutoBean(AutoBeanFactory factory, Class<?> beanType,
      Configuration configuration) {
    super(factory);
    this.beanType = (Class<T>) beanType;
    this.configuration = configuration;
    this.data = calculateData(beanType);
    this.shim = createShim();
  }

  @SuppressWarnings("unchecked")
  public ProxyAutoBean(AutoBeanFactory factory, Class<?> beanType,
      Configuration configuration, T toWrap) {
    super(factory, toWrap);
    if (Proxy.isProxyClass(toWrap.getClass())) {
      System.out.println("blah");
    }
    this.beanType = (Class<T>) beanType;
    this.configuration = configuration;
    this.data = calculateData(beanType);
    this.shim = createShim();
  }

  private ProxyAutoBean(ProxyAutoBean<T> toClone, boolean deep) {
    super(toClone, deep);
    this.beanType = toClone.beanType;
    this.configuration = toClone.configuration;
    this.data = toClone.data;
    this.shim = createShim();
  }

  @Override
  public T as() {
    return shim;
  }

  @Override
  public AutoBean<T> clone(boolean deep) {
    return new ProxyAutoBean<T>(this, deep);
  }

  public Configuration getConfiguration() {
    return configuration;
  }

  public Class<T> getType() {
    return beanType;
  }

  /**
   * Allow access by {@link ShimHandler}.
   */
  @Override
  protected void call(String method, Object returned, Object... parameters) {
    super.call(method, returned, parameters);
  }

  /**
   * Allow access by {@link ShimHandler}.
   */
  @Override
  protected void checkFrozen() {
    super.checkFrozen();
  }

  /**
   * Allow access by {@link ShimHandler}.
   */
  @Override
  protected void checkWrapped() {
    super.checkWrapped();
  }

  @Override
  protected T createSimplePeer() {
    return AutoBeanFactoryMagic.makeProxy(beanType, new SimpleBeanHandler<T>(
        this));
  }

  /**
   * Allow access by {@link ShimHandler}.
   */
  @Override
  protected <V> V get(String method, V toReturn) {
    return super.get(method, toReturn);
  }

  /**
   * Allow access by {@link BeanMethod}.
   */
  protected Map<String, Object> getValues() {
    return values;
  }

  /**
   * Allow access by {@link ShimHandler}.
   */
  protected T getWrapped() {
    return super.getWrapped();
  }

  /**
   * Allow access by {@link ShimHandler}.
   */
  @Override
  protected void set(String method, Object value) {
    super.set(method, value);
  }

  // TODO: Port to model-based when class-based TypeOracle is available.
  @Override
  protected void traverseProperties(AutoBeanVisitor visitor, OneShotContext ctx) {
    assert data.getters.size() == data.getterNames.size()
        && data.getters.size() == data.propertyType.size();
    Iterator<Method> getterIt = data.getters.iterator();
    Iterator<String> nameIt = data.getterNames.iterator();
    Iterator<PropertyType> typeIt = data.propertyType.iterator();
    while (getterIt.hasNext()) {
      Method getter = getterIt.next();
      String name = nameIt.next();
      PropertyType propertyType = typeIt.next();

      // Use the shim to handle automatic wrapping
      Object value;
      try {
        getter.setAccessible(true);
        value = getter.invoke(shim);
      } catch (IllegalArgumentException e) {
        throw new RuntimeException(e);
      } catch (IllegalAccessException e) {
        throw new RuntimeException(e);
      } catch (InvocationTargetException e) {
        throw new RuntimeException(e.getCause());
      }

      // Create the context used for the property visitation
      MethodPropertyContext x = isUsingSimplePeer() ? new BeanPropertyContext(
          this, getter) : new GetterPropertyContext(this, getter);

      switch (propertyType) {
        case VALUE: {
          if (visitor.visitValueProperty(name, value, x)) {
          }
          visitor.endVisitValueProperty(name, value, x);
          break;
        }
        case COLLECTION: {
          // Workaround for generics bug in mac javac 1.6.0_22
          @SuppressWarnings("rawtypes")
          AutoBean temp = AutoBeanUtils.getAutoBean((Collection) value);
          @SuppressWarnings("unchecked")
          AutoBean<Collection<?>> bean = (AutoBean<Collection<?>>) temp;
          if (visitor.visitCollectionProperty(name, bean, x)) {
            if (value != null) {
              ((ProxyAutoBean<?>) bean).traverse(visitor, ctx);
            }
          }
          visitor.endVisitCollectionProperty(name, bean, x);
          break;
        }
        case MAP: {
          // Workaround for generics bug in mac javac 1.6.0_22
          @SuppressWarnings("rawtypes")
          AutoBean temp = AutoBeanUtils.getAutoBean((Map) value);
          @SuppressWarnings("unchecked")
          AutoBean<Map<?, ?>> bean = (AutoBean<Map<?, ?>>) temp;
          if (visitor.visitMapProperty(name, bean, x)) {
            if (value != null) {
              ((ProxyAutoBean<?>) bean).traverse(visitor, ctx);
            }
          }
          visitor.endVisitMapProperty(name, bean, x);
          break;
        }
        case REFERENCE: {
          ProxyAutoBean<?> bean = (ProxyAutoBean<?>) AutoBeanUtils.getAutoBean(value);
          if (visitor.visitReferenceProperty(name, bean, x)) {
            if (value != null) {
              bean.traverse(visitor, ctx);
            }
          }
          visitor.endVisitReferenceProperty(name, bean, x);
          break;
        }
      }
    }
  }

  Class<?> getBeanType() {
    return beanType;
  }

  Map<String, Object> getPropertyMap() {
    return values;
  }

  private T createShim() {
    T toReturn = AutoBeanFactoryMagic.makeProxy(beanType, new ShimHandler<T>(
        this, getWrapped()));
    WeakMapping.set(toReturn, AutoBean.class.getName(), this);
    return toReturn;
  }
}
TOP

Related Classes of com.google.gwt.autobean.server.ProxyAutoBean$Data

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.