Revision: 5978 Author: [email protected] Date: Thu Aug 20 05:44:21 2009 Log: Formalize how default extensions are provided by ClientBundle resource types.
Patch by: bobv Review by: rjrjr http://code.google.com/p/google-web-toolkit/source/detail?r=5978 Added: /trunk/user/src/com/google/gwt/resources/ext/DefaultExtensions.java Modified: /trunk/dev/core/src/com/google/gwt/core/ext/typeinfo/JClassType.java /trunk/user/src/com/google/gwt/resources/client/CssResource.java /trunk/user/src/com/google/gwt/resources/client/ExternalTextResource.java /trunk/user/src/com/google/gwt/resources/client/ImageResource.java /trunk/user/src/com/google/gwt/resources/client/TextResource.java /trunk/user/src/com/google/gwt/resources/ext/ResourceGeneratorUtil.java /trunk/user/src/com/google/gwt/resources/rebind/context/AbstractClientBundleGenerator.java /trunk/user/src/com/google/gwt/resources/rg/CssResourceGenerator.java /trunk/user/src/com/google/gwt/resources/rg/ExternalTextResourceGenerator.java /trunk/user/src/com/google/gwt/resources/rg/ImageResourceGenerator.java /trunk/user/src/com/google/gwt/resources/rg/TextResourceGenerator.java ======================================= --- /dev/null +++ /trunk/user/src/com/google/gwt/resources/ext/DefaultExtensions.java Thu Aug 20 05:44:21 2009 @@ -0,0 +1,36 @@ +/* + * 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.resources.ext; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Specifies the default extensions for a resource type. This annotation is + * intended to allow external tooling to know which filename extensions the + * ClientBundle system will search for if no + * {...@link com.google.gwt.resources.client.ClientBundle.Source} annotation is + * present on an accessor method. + */ +...@inherited +...@retention(RetentionPolicy.RUNTIME) +...@target(ElementType.TYPE) +public @interface DefaultExtensions { + String[] value(); +} ======================================= --- /trunk/dev/core/src/com/google/gwt/core/ext/typeinfo/JClassType.java Wed Apr 1 13:03:34 2009 +++ /trunk/dev/core/src/com/google/gwt/core/ext/typeinfo/JClassType.java Thu Aug 20 05:44:21 2009 @@ -19,6 +19,9 @@ import com.google.gwt.dev.util.collect.Sets; import java.lang.annotation.Annotation; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; import java.util.Map; import java.util.Set; @@ -45,8 +48,8 @@ } /** - * Returns <code>true</code> if the rhs array type can be assigned to the - * lhs array type. + * Returns <code>true</code> if the rhs array type can be assigned to the lhs + * array type. */ private static boolean areArraysAssignable(JArrayType lhsType, JArrayType rhsType) { @@ -327,8 +330,8 @@ } /** - * Cached set of supertypes for this type (including itself). If null, - * the set has not been calculated yet. + * Cached set of supertypes for this type (including itself). If null, the set + * has not been calculated yet. */ private Set<JClassType> flattenedSupertypes; @@ -357,6 +360,65 @@ return null; } + + /** + * Find an annotation on a type or on one of its superclasses or + * superinterfaces. + * <p> + * This provides semantics similar to that of + * {...@link java.lang.annotation.Inherited} except that it checks all types to + * which this type is assignable. {...@code @Inherited} only works on + * superclasses, not superinterfaces. + * <p> + * Annotations present on the superclass chain will be returned preferentially + * over those found in the superinterface hierarchy. Note that the annotation + * does not need to be tagged with {...@code @Inherited} in order to be returned + * from the superclass chain. + * + * @param annotationType the type of the annotation to look for + * @return the desired annotation or <code>null</code> if the annotation is + * not present in the type's type hierarchy + */ + public <T extends Annotation> T findAnnotationInTypeHierarchy( + Class<T> annotationType) { + + // Remember what we've seen to avoid loops + Set<JClassType> seen = new HashSet<JClassType>(); + + // Work queue + List<JClassType> searchTypes = new LinkedList<JClassType>(); + searchTypes.add(this); + + T toReturn = null; + + while (!searchTypes.isEmpty()) { + JClassType current = searchTypes.remove(0); + + if (!seen.add(current)) { + continue; + } + + toReturn = current.getAnnotation(annotationType); + if (toReturn != null) { + /* + * First one wins. It might be desirable at some point to have a + * variation that can return more than one instance of the annotation if + * it is present on multiple supertypes. + */ + break; + } + + if (current.getSuperclass() != null) { + // Add the superclass at the front of the list + searchTypes.add(0, current.getSuperclass()); + } + + // Superinterfaces + Collections.addAll(searchTypes, current.getImplementedInterfaces()); + } + + return toReturn; + } public abstract JConstructor findConstructor(JType[] paramTypes); @@ -446,12 +508,12 @@ Class<? extends Annotation> annotationClass); /** - * Returns <code>true</code> if this {...@link JClassType} is assignable from - * the specified {...@link JClassType} parameter. + * Returns <code>true</code> if this {...@link JClassType} is assignable from the + * specified {...@link JClassType} parameter. * * @param possibleSubtype possible subtype of this {...@link JClassType} - * @return <code>true</code> if this {...@link JClassType} is assignable from - * the specified {...@link JClassType} parameter + * @return <code>true</code> if this {...@link JClassType} is assignable from the + * specified {...@link JClassType} parameter * * @throws NullPointerException if <code>possibleSubtype</code> is * <code>null</code> @@ -487,7 +549,7 @@ * Determines if the class can be constructed using a simple <code>new</code> * operation. Specifically, the class must * <ul> - * <li>be a class rather than an interface, </li> + * <li>be a class rather than an interface,</li> * <li>have either no constructors or a parameterless constructor, and</li> * <li>be a top-level class or a static nested class.</li> * </ul> ======================================= --- /trunk/user/src/com/google/gwt/resources/client/CssResource.java Fri Jul 3 08:33:45 2009 +++ /trunk/user/src/com/google/gwt/resources/client/CssResource.java Thu Aug 20 05:44:21 2009 @@ -15,6 +15,7 @@ */ package com.google.gwt.resources.client; +import com.google.gwt.resources.ext.DefaultExtensions; import com.google.gwt.resources.ext.ResourceGeneratorType; import com.google.gwt.resources.rg.CssResourceGenerator; @@ -32,9 +33,9 @@ * <li>{...@code String someClassName();} will allow the css class * <code>.someClassName</code> to be obfuscated at runtime. The function will * return the obfuscated class name.</li> - * <li>{...@code <primitive numeric type or String> someDefName();} will allow - * access to the values defined by {...@literal @def} rules within the CSS file. - * The defined value must be a raw number, a CSS length, or a percentage value + * <li>{...@code <primitive numeric type or String> someDefName();} will allow + * access to the values defined by {...@literal @def} rules within the CSS file. + * The defined value must be a raw number, a CSS length, or a percentage value * if it is to be returned as a numeric type. * </ul> * @@ -94,6 +95,7 @@ * @see <a href="http://code.google.com/p/google-web-toolkit/wiki/CssResource" * >CssResource design doc</a> */ +...@defaultextensions(value = {".css"}) @ResourceGeneratorType(CssResourceGenerator.class) public interface CssResource extends ResourcePrototype { /** ======================================= --- /trunk/user/src/com/google/gwt/resources/client/ExternalTextResource.java Wed Mar 11 17:58:41 2009 +++ /trunk/user/src/com/google/gwt/resources/client/ExternalTextResource.java Thu Aug 20 05:44:21 2009 @@ -15,6 +15,7 @@ */ package com.google.gwt.resources.client; +import com.google.gwt.resources.ext.DefaultExtensions; import com.google.gwt.resources.ext.ResourceGeneratorType; import com.google.gwt.resources.rg.ExternalTextResourceGenerator; @@ -23,6 +24,7 @@ * not inlined into the compiled output. This is suitable for resources that are * not required as part of program initialization. */ +...@defaultextensions(value = {".txt"}) @ResourceGeneratorType(ExternalTextResourceGenerator.class) public interface ExternalTextResource extends ResourcePrototype { void getText(ResourceCallback<TextResource> callback) ======================================= --- /trunk/user/src/com/google/gwt/resources/client/ImageResource.java Thu Jul 30 11:19:40 2009 +++ /trunk/user/src/com/google/gwt/resources/client/ImageResource.java Thu Aug 20 05:44:21 2009 @@ -15,6 +15,7 @@ */ package com.google.gwt.resources.client; +import com.google.gwt.resources.ext.DefaultExtensions; import com.google.gwt.resources.ext.ResourceGeneratorType; import com.google.gwt.resources.rg.ImageResourceGenerator; @@ -25,6 +26,7 @@ /** * Provides access to image resources at runtime. */ +...@defaultextensions(value = {".png", ".jpg", ".gif", ".bmp"}) @ResourceGeneratorType(ImageResourceGenerator.class) public interface ImageResource extends ResourcePrototype { ======================================= --- /trunk/user/src/com/google/gwt/resources/client/TextResource.java Wed Mar 11 17:58:41 2009 +++ /trunk/user/src/com/google/gwt/resources/client/TextResource.java Thu Aug 20 05:44:21 2009 @@ -15,6 +15,7 @@ */ package com.google.gwt.resources.client; +import com.google.gwt.resources.ext.DefaultExtensions; import com.google.gwt.resources.ext.ResourceGeneratorType; import com.google.gwt.resources.rg.TextResourceGenerator; @@ -22,6 +23,7 @@ * A resource that contains text that should be incorporated into the compiled * output. */ +...@defaultextensions(value = {".txt"}) @ResourceGeneratorType(TextResourceGenerator.class) public interface TextResource extends ResourcePrototype { String getText(); ======================================= --- /trunk/user/src/com/google/gwt/resources/ext/ResourceGeneratorUtil.java Wed Jun 17 13:49:44 2009 +++ /trunk/user/src/com/google/gwt/resources/ext/ResourceGeneratorUtil.java Thu Aug 20 05:44:21 2009 @@ -20,6 +20,7 @@ import com.google.gwt.core.ext.SelectionProperty; import com.google.gwt.core.ext.TreeLogger; 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.JPackage; import com.google.gwt.dev.resource.Resource; @@ -171,6 +172,10 @@ * will fall back to using the current thread's context ClassLoader. If it is * necessary to alter the way in which resources are located, use the overload * that accepts a ClassLoader. + * <p> + * If the method's return type declares the {...@link DefaultExtensions} + * annotation, the value of this annotation will be used to find matching + * resource names if the method lacks an {...@link Source} annotation. * * @param logger a TreeLogger that will be used to report errors or warnings * @param context the ResourceContext in which the ResourceGenerator is @@ -184,7 +189,16 @@ */ public static URL[] findResources(TreeLogger logger, ResourceContext context, JMethod method) throws UnableToCompleteException { - return findResources(logger, context, method, new String[0]); + JClassType returnType = method.getReturnType().isClassOrInterface(); + assert returnType != null; + DefaultExtensions annotation = returnType.findAnnotationInTypeHierarchy(DefaultExtensions.class); + String[] extensions; + if (annotation != null) { + extensions = annotation.value(); + } else { + extensions = new String[0]; + } + return findResources(logger, context, method, extensions); } /** ======================================= --- /trunk/user/src/com/google/gwt/resources/rebind/context/AbstractClientBundleGenerator.java Mon Jun 22 07:10:10 2009 +++ /trunk/user/src/com/google/gwt/resources/rebind/context/AbstractClientBundleGenerator.java Thu Aug 20 05:44:21 2009 @@ -418,40 +418,18 @@ private Class<? extends ResourceGenerator> findResourceGenerator( TreeLogger logger, TypeOracle typeOracle, JMethod method) throws UnableToCompleteException { - JClassType resourceType = method.getReturnType().isClassOrInterface(); assert resourceType != null; - List<JClassType> searchTypes = new ArrayList<JClassType>(); - searchTypes.add(resourceType); - - ResourceGeneratorType generatorType = null; - - while (!searchTypes.isEmpty()) { - JClassType current = searchTypes.remove(0); - generatorType = current.getAnnotation(ResourceGeneratorType.class); - if (generatorType != null) { - break; - } - - if (current.getSuperclass() != null) { - searchTypes.add(current.getSuperclass()); - } - - for (JClassType t : current.getImplementedInterfaces()) { - searchTypes.add(t); - } - } - - if (generatorType == null) { + ResourceGeneratorType annotation = resourceType.findAnnotationInTypeHierarchy(ResourceGeneratorType.class); + if (annotation == null) { logger.log(TreeLogger.ERROR, "No @" - + ResourceGeneratorType.class.getName() - + " was specifed for resource type " + + ResourceGeneratorType.class.getName() + " was specifed for type " + resourceType.getQualifiedSourceName() + " or its supertypes"); throw new UnableToCompleteException(); } - return generatorType.value(); + return annotation.value(); } /** ======================================= --- /trunk/user/src/com/google/gwt/resources/rg/CssResourceGenerator.java Mon Jul 6 08:09:11 2009 +++ /trunk/user/src/com/google/gwt/resources/rg/CssResourceGenerator.java Thu Aug 20 05:44:21 2009 @@ -1002,8 +1002,6 @@ */ private static final int CONCAT_EXPRESSION_LIMIT = 20; - private static final String[] DEFAULT_EXTENSIONS = new String[] {".css"}; - /** * These constants are used to cache obfuscated class names. */ @@ -1377,7 +1375,7 @@ } URL[] resources = ResourceGeneratorUtil.findResources(logger, context, - method, DEFAULT_EXTENSIONS); + method); if (resources.length == 0) { logger.log(TreeLogger.ERROR, "At least one source must be specified"); ======================================= --- /trunk/user/src/com/google/gwt/resources/rg/ExternalTextResourceGenerator.java Thu Mar 12 11:16:43 2009 +++ /trunk/user/src/com/google/gwt/resources/rg/ExternalTextResourceGenerator.java Thu Aug 20 05:44:21 2009 @@ -41,7 +41,6 @@ */ public final class ExternalTextResourceGenerator extends AbstractResourceGenerator { - private static final String[] DEFAULT_EXTENSIONS = new String[] {".txt"}; private StringBuffer data; private boolean first; private String urlExpression; @@ -112,8 +111,7 @@ ClientBundleRequirements requirements, JMethod method) throws UnableToCompleteException { - URL[] urls = ResourceGeneratorUtil.findResources(logger, context, method, - DEFAULT_EXTENSIONS); + URL[] urls = ResourceGeneratorUtil.findResources(logger, context, method); if (urls.length != 1) { logger.log(TreeLogger.ERROR, "Exactly one resource must be specified", ======================================= --- /trunk/user/src/com/google/gwt/resources/rg/ImageResourceGenerator.java Thu Jul 30 11:19:40 2009 +++ /trunk/user/src/com/google/gwt/resources/rg/ImageResourceGenerator.java Thu Aug 20 05:44:21 2009 @@ -45,8 +45,6 @@ * Builds an image strip for all ImageResources defined within an ClientBundle. */ public final class ImageResourceGenerator extends AbstractResourceGenerator { - private static final String[] DEFAULT_EXTENSIONS = new String[] { - ".png", ".jpg", ".gif", ".bmp"}; private Map<String, ImageRect> imageRectsByName; private Map<ImageRect, ImageBundleBuilder> buildersByImageRect; private Map<RepeatStyle, ImageBundleBuilder> buildersByRepeatStyle; @@ -199,7 +197,7 @@ ClientBundleRequirements requirements, JMethod method) throws UnableToCompleteException { URL[] resources = ResourceGeneratorUtil.findResources(logger, context, - method, DEFAULT_EXTENSIONS); + method); if (resources.length != 1) { logger.log(TreeLogger.ERROR, "Exactly one image may be specified", null); ======================================= --- /trunk/user/src/com/google/gwt/resources/rg/TextResourceGenerator.java Thu Mar 12 11:16:43 2009 +++ /trunk/user/src/com/google/gwt/resources/rg/TextResourceGenerator.java Thu Aug 20 05:44:21 2009 @@ -33,13 +33,11 @@ */ public final class TextResourceGenerator extends AbstractResourceGenerator { - private static final String[] DEFAULT_EXTENSIONS = new String[] {".txt"}; - @Override public String createAssignment(TreeLogger logger, ResourceContext context, JMethod method) throws UnableToCompleteException { URL[] resources = ResourceGeneratorUtil.findResources(logger, context, - method, DEFAULT_EXTENSIONS); + method); if (resources.length != 1) { logger.log(TreeLogger.ERROR, "Exactly one resource must be specified", --~--~---------~--~----~------------~-------~--~----~ http://groups.google.com/group/Google-Web-Toolkit-Contributors -~----------~----~----~----~------~----~------~--~---
