blob: 7a997aea783c28f46acff5c76fa8464349f1fa26 [file] [log] [blame]
/*
* 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.google.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.google.gwt.uibinder.rebind.MortalLogger;
import com.google.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<String, OwnerField> uiFields =
new TreeMap<String, OwnerField>();
/**
* 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<JClassType, OwnerField> uiFieldTypes =
new HashMap<JClassType, OwnerField>();
/**
* Map from type to the method that produces it.
*/
private final Map<JClassType, JMethod> uiFactories =
new HashMap<JClassType, JMethod>();
/**
* List of all @UiHandler methods in the owner class.
*/
private final List<JMethod> uiHandlers = new ArrayList<JMethod>();
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.google.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<OwnerField> getUiFields() {
return uiFields.values();
}
/**
* Returns all the UiHandler methods defined in the owner class.
*/
public List<JMethod> 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);
}
}
}