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

com.google.gwt.uibinder.rebind.GinFieldManager Maven / Gradle / Ivy

There is a newer version: 1.6
Show newest version
/**
 * Copyright 2010 ArcBees 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.uibinder.rebind;

import com.google.gwt.core.ext.TreeLogger.Type;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JMethod;
import com.google.gwt.core.ext.typeinfo.JType;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.google.gwt.uibinder.rebind.model.ImplicitCssResource;

import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.Map;

/**
 * This version of {@link FieldManager} makes it possible for UiBinder
 * files to use widgets that need to be instantiated with gin. 
 * See {@link GinUiBinderGenerator} for details. This 
 * is a slightly modified version of {@link FieldManager}
 * that allows fields to be instantiated using gin dependency 
 * injection. Modifications are clearly indicated by 
 * {@code MODIFICATION} comments.
 * 
 * @author Philippe Beaudoin ([email protected])
 */
public class GinFieldManager extends FieldManager {

  private static final String DUPLICATE_FIELD_ERROR = "Duplicate declaration of field %1$s.";

  private final TypeOracle types;
  private final MortalLogger logger;

  /**
   * Map of field name to FieldWriter. Note its a LinkedHashMap--we want to
   * write these out in the order they're declared.
   */
  private final LinkedHashMap fieldsMap = new LinkedHashMap();

  /**
   * A stack of the fields.
   */
  private final LinkedList parsedFieldStack = new LinkedList();

  private LinkedHashMap fieldReferences = new LinkedHashMap();

  // BEGIN MODIFICATION
  private Map ginjectorMethods = new HashMap();
  private JClassType ginjectorClass;
  
  public GinFieldManager(TypeOracle types, MortalLogger logger, JClassType ginjectorClass) {
    super(types, logger);
    this.types = types;
    this.logger = logger;
    this.ginjectorClass = ginjectorClass;
    for (JMethod method : ginjectorClass.getMethods()) {
      JClassType returnType = method.getReturnType().isClassOrInterface();
      if (method.getParameters().length == 0 && returnType != null) {
        ginjectorMethods.put(returnType, method.getName());
      }
    }  
  }
  // END MODIFICATION

  /**
   * @param fieldName the name of the {@link FieldWriter} to find
   * @return the {@link FieldWriter} instance indexed by fieldName or
   *         null in case fieldName is not found
   */
  public FieldWriter lookup(String fieldName) {
    return fieldsMap.get(fieldName);
  }

  /**
   * Remove the field at the top of the {@link #parsedFieldStack}.
   */
  public void pop() {
    parsedFieldStack.removeFirst();
  }

  /**
   * @param fieldWriter the field to push on the top of the
   *          {@link #parsedFieldStack}
   */
  public void push(FieldWriter fieldWriter) {
    parsedFieldStack.addFirst(fieldWriter);
  }

  /**
   * Used to declare fields of an existing type. If your field will hold a type
   * that is being generated, see {@link #registerFieldOfGeneratedType}.
   * 

* When making a field we peek at the {@link #parsedFieldStack} to make sure * that the field that holds the widget currently being parsed will depended * upon the field being declared. This ensures, for example, that dom id * fields (see {@link com.google.gwt.uibinder.rebind.UiBinderWriter#declareDomIdHolder()}) * used by an HTMLPanel will be declared before it is. * * @param fieldType the type of the new field * @param fieldName the name of the new field * @return a new {@link FieldWriter} instance * @throws UnableToCompleteException on duplicate name */ public FieldWriter registerField(JClassType fieldType, String fieldName) throws UnableToCompleteException { // BEGIN MODIFICATION String ginjectorMethod = ginjectorMethods.get(fieldType); FieldWriter field; if (ginjectorMethod != null) { // If the ginjector lets us create that fieldType then we use gin to instantiate it field = new FieldWriterOfInjectedType(fieldType, fieldName, ginjectorClass, ginjectorMethod, logger); } else { // Otherwise field = new FieldWriterOfExistingType(fieldType, fieldName, logger); } return registerField(fieldName, field); // END MODIFICATION } /** * Used to declare fields that will hold generated instances generated * CssResource interfaces. If your field will hold a reference of an existing * type, see {@link #registerField}. For other generated types, use * {@link #registerFieldOfGeneratedType} * {@link #registerFieldForGeneratedCssResource}. *

* When making a field we peek at the {@link #parsedFieldStack} to make sure * that the field that holds the widget currently being parsed will depended * upon the field being declared. This ensures, for example, that dom id * fields (see {@link com.google.gwt.uibinder.rebind.UiBinderWriter#declareDomIdHolder()}) * used by an HTMLPanel will be declared before it is. * * @throws UnableToCompleteException on duplicate name * @return a new {@link FieldWriter} instance */ public FieldWriter registerFieldForGeneratedCssResource( ImplicitCssResource cssResource) throws UnableToCompleteException { FieldWriter field = new FieldWriterOfGeneratedCssResource( types.findType(String.class.getCanonicalName()), cssResource, logger); return registerField(cssResource.getName(), field); } /** * Used to declare fields of a type (other than CssResource) that is to be * generated. If your field will hold a reference of an existing type, see * {@link #registerField}. For generated CssResources, see * {@link #registerFieldForGeneratedCssResource}. *

* When making a field we peek at the {@link #parsedFieldStack} to make sure * that the field that holds the widget currently being parsed will depended * upon the field being declared. This ensures, for example, that dom id * fields (see {@link com.google.gwt.uibinder.rebind.UiBinderWriter#declareDomIdHolder()}) * used by an HTMLPanel will be declared before it is. * * @param assignableType class or interface extened or implemented by this * type * @param typeName the full qualified name for the class associated with the * field * @param fieldName the name of the field * @throws UnableToCompleteException on duplicate name * @return a new {@link FieldWriter} instance */ public FieldWriter registerFieldOfGeneratedType(JClassType assignableType, String typePackage, String typeName, String fieldName) throws UnableToCompleteException { FieldWriter field = new FieldWriterOfGeneratedType(assignableType, typePackage, typeName, fieldName, logger); return registerField(fieldName, field); } /** * Called to register a {field.reference} encountered during * parsing, to be validated against the type oracle once parsing is complete. * * @throws UnableToCompleteException */ public void registerFieldReference(String fieldReferenceString, JType type) { FieldReference fieldReference = fieldReferences.get(fieldReferenceString); if (fieldReference == null) { fieldReference = new FieldReference(fieldReferenceString, this, types); fieldReferences.put(fieldReferenceString, fieldReference); } fieldReference.addLeftHandType(type); } /** * To be called after parsing is complete. Surveys all * {field.reference}s and checks they refer to existing types, * and have appropriate return types. * * @throws UnableToCompleteException if any {field.references} * can't be resolved */ public void validate() throws UnableToCompleteException { boolean failed = false; for (Map.Entry entry : fieldReferences.entrySet()) { FieldReference ref = entry.getValue(); MonitoredLogger monitoredLogger = new MonitoredLogger( logger.getTreeLogger().branch(Type.TRACE, "validating " + ref)); ref.validate(monitoredLogger); failed |= monitoredLogger.hasErrors(); } if (failed) { throw new UnableToCompleteException(); } } /** * Writes all stored gwt fields. * * @param writer the writer to output * @param ownerTypeName the name of the class being processed */ public void writeGwtFieldsDeclaration(IndentedWriter writer, String ownerTypeName) throws UnableToCompleteException { Collection fields = fieldsMap.values(); for (FieldWriter field : fields) { field.write(writer); } } private FieldWriter registerField(String fieldName, FieldWriter field) throws UnableToCompleteException { requireUnique(fieldName); fieldsMap.put(fieldName, field); if (parsedFieldStack.size() > 0) { parsedFieldStack.getFirst().needs(field); } return field; } private void requireUnique(String fieldName) throws UnableToCompleteException { if (fieldsMap.containsKey(fieldName)) { logger.die(DUPLICATE_FIELD_ERROR, fieldName); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy