All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sencha.gwt.uibinder.rebind.model.OwnerClass Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2009 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.sencha.gwt.uibinder.rebind.model;

import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JField;
import com.google.gwt.core.ext.typeinfo.JGenericType;
import com.google.gwt.core.ext.typeinfo.JMethod;
import com.google.gwt.core.ext.typeinfo.JParameterizedType;
import com.google.gwt.uibinder.client.UiFactory;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
import com.sencha.gwt.uibinder.rebind.MortalLogger;
import com.sencha.gwt.uibinder.rebind.UiBinderContext;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

/**
 * Model class with all attributes of the owner class.
 * This includes factories, fields and handlers.
 */
public class OwnerClass {

  /**
   * Map from field name to model.
   */
  private final Map uiFields =
      new TreeMap();

  /**
   * Map from field type to model.
   *
   * This is used for binding resources - for widgets, there may be multiple
   * widgets with the same type, in which case this becomes meaningless.
   */
  private final Map uiFieldTypes =
      new HashMap();

  /**
   * Map from type to the method that produces it.
   */
  private final Map uiFactories =
      new HashMap();

  /**
   * List of all @UiHandler methods in the owner class.
   */
  private final List uiHandlers = new ArrayList();

  private final MortalLogger logger;

  private final JClassType ownerType;

  private final UiBinderContext context;

  /**
   * Constructor.
   *
   * @param ownerType the type of the owner class
   * @param logger
   */
  public OwnerClass(JClassType ownerType, MortalLogger logger,
      UiBinderContext context) throws UnableToCompleteException {
    this.logger = logger;
    this.ownerType = ownerType;
    this.context = context;
    findUiFields(ownerType);
    findUiFactories(ownerType);
    findUiHandlers(ownerType);
  }

  public JClassType getOwnerType() {
    return ownerType;
  }

  /**
   * Returns the method annotated with @UiFactory which returns the given type.
   *
   * @param forType the type to look for a factory of
   * @return the factory method, or null if none exists
   */
  public JMethod getUiFactoryMethod(JClassType forType) {
    JGenericType genericType = forType.isGenericType();
    if (genericType != null) {
      forType = genericType.getRawType();
    }

    return uiFactories.get(forType);
  }

  /**
   * Gets a field with the given name.
   * It's important to notice that a field may not exist on the owner class even
   * if it has a name in the XML and even has handlers attached to it -  such a
   * field will only exist in the generated binder class.
   *
   * @param name the name of the field to get
   * @return the field descriptor, or null if the owner doesn't have that field
   */
  public OwnerField getUiField(String name) {
    return uiFields.get(name);
  }

  /**
   * Gets the field with the given type.
   * Note that multiple fields can have the same type, so it only makes sense to
   * call this to retrieve resource fields, such as messages and image bundles,
   * for which only one instance is expected.
   *
   * @param type the type of the field
   * @return the field descriptor
   * @deprecated This will die with {@link com.sencha.gwt.uibinder.attributeparsers.BundleAttributeParser}
   */
  @Deprecated
  public OwnerField getUiFieldForType(JClassType type) {
    return uiFieldTypes.get(type);
  }

  /**
   * Returns a collection of all fields in the owner class.
   */
  public Collection getUiFields() {
    return uiFields.values();
  }

  /**
   * Returns all the UiHandler methods defined in the owner class.
   */
  public List getUiHandlers() {
    return uiHandlers;
  }

  /**
   * Scans the owner class to find all methods annotated with @UiFactory, and
   * puts them in {@link #uiFactories}.
   *
   * @param ownerType the type of the owner class
   * @throws UnableToCompleteException
   */
  private void findUiFactories(JClassType ownerType)
      throws UnableToCompleteException {
    JMethod[] methods = ownerType.getMethods();
    for (JMethod method : methods) {
      if (method.isAnnotationPresent(UiFactory.class)) {
        JClassType factoryType = method.getReturnType().isClassOrInterface();

        if (factoryType == null) {
          logger.die("Factory return type is not a class in method "
              + method.getName());
        }
        
        JParameterizedType paramType = factoryType.isParameterized();
        if (paramType != null) {
          factoryType = paramType.getRawType();
        }

        if (uiFactories.containsKey(factoryType)) {
          logger.die("Duplicate factory in class "
              + method.getEnclosingType().getName() + " for type "
              + factoryType.getName());
        }

        uiFactories.put(factoryType, method);
      }
    }

    // Recurse to superclass
    JClassType superclass = ownerType.getSuperclass();
    if (superclass != null) {
      findUiFactories(superclass);
    }
  }

  /**
   * Scans the owner class to find all fields annotated with @UiField, and puts
   * them in {@link #uiFields} and {@link #uiFieldTypes}.
   *
   * @param ownerType the type of the owner class
   */
  private void findUiFields(JClassType ownerType)
      throws UnableToCompleteException {
    JField[] fields = ownerType.getFields();
    for (JField field : fields) {
      if (field.isAnnotationPresent(UiField.class)) {
        JClassType ownerFieldType = field.getType().isClassOrInterface();

        if (ownerFieldType == null) {
          logger.die("Field type is not a class in field "
              + field.getName());
        }

        OwnerField ownerField = new OwnerField(field, logger, context);
        String ownerFieldName = field.getName();

        uiFields.put(ownerFieldName, ownerField);
        uiFieldTypes.put(ownerFieldType, ownerField);
      }
    }

    // Recurse to superclass
    JClassType superclass = ownerType.getSuperclass();
    if (superclass != null) {
      findUiFields(superclass);
    }
  }

  /**
   * Scans the owner class to find all methods annotated with @UiHandler, and
   * adds them to their respective fields.
   *
   * @param ownerType the type of the owner class
   */
  private void findUiHandlers(JClassType ownerType) {
    JMethod[] methods = ownerType.getMethods();
    for (JMethod method : methods) {
      if (method.isAnnotationPresent(UiHandler.class)) {
        uiHandlers.add(method);
      }
    }

    // Recurse to superclass
    JClassType superclass = ownerType.getSuperclass();
    if (superclass != null) {
      findUiHandlers(superclass);
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy