# HG changeset patch # User Jesse Glick # Date 1311027744 14400 #194545: constructors for LayerGenerationException specifying responsible annotation. diff --git a/core.multiview/src/org/netbeans/core/multiview/MultiViewProcessor.java b/core.multiview/src/org/netbeans/core/multiview/MultiViewProcessor.java --- a/core.multiview/src/org/netbeans/core/multiview/MultiViewProcessor.java +++ b/core.multiview/src/org/netbeans/core/multiview/MultiViewProcessor.java @@ -95,10 +95,10 @@ for (Element e : roundEnv.getElementsAnnotatedWith(MultiViewElement.Registration.class)) { MultiViewElement.Registration mvr = e.getAnnotation(MultiViewElement.Registration.class); if (mvr.mimeType().length == 0) { - throw new LayerGenerationException("You must specify mimeType", e); + throw new LayerGenerationException("You must specify mimeType", e, processingEnv, mvr, "mimeType"); } TypeMirror[] exprType = new TypeMirror[1]; - String[] binAndMethodNames = findDefinition(e, exprType); + String[] binAndMethodNames = findDefinition(e, exprType, mvr); String fileBaseName = binAndMethodNames[0].replace('.', '-'); if (binAndMethodNames[1] != null) { fileBaseName += "-" + binAndMethodNames[1]; @@ -108,7 +108,7 @@ f.methodvalue("instanceCreate", MultiViewFactory.class.getName(), "createMultiViewDescription"); f.stringvalue("instanceClass", ContextAwareDescription.class.getName()); f.stringvalue("class", binAndMethodNames[0]); - f.bundlevalue("displayName", mvr.displayName()); + f.bundlevalue("displayName", mvr.displayName(), mvr, "displayName"); f.stringvalue("iconBase", mvr.iconBase()); f.stringvalue("preferredID", mvr.preferredID()); f.intvalue("persistenceType", mvr.persistenceType()); @@ -125,13 +125,13 @@ return true; } - private String[] findDefinition(Element e, TypeMirror[] type) throws LayerGenerationException { + private String[] findDefinition(Element e, TypeMirror[] type, MultiViewElement.Registration mvr) throws LayerGenerationException { final TypeMirror lkp = processingEnv.getElementUtils().getTypeElement(Lookup.class.getCanonicalName()).asType(); final TypeMirror mve = processingEnv.getElementUtils().getTypeElement(MultiViewElement.class.getName()).asType(); if (e.getKind() == ElementKind.CLASS) { TypeElement clazz = (TypeElement) e; if (!processingEnv.getTypeUtils().isAssignable(clazz.asType(), mve)) { - throw new LayerGenerationException("Not assignable to " + mve, e); + throw new LayerGenerationException("Not assignable to " + mve, e, processingEnv, mvr); } int constructorCount = 0; CONSTRUCTOR: for (ExecutableElement constructor : ElementFilter.constructorsIn(clazz.getEnclosedElements())) { @@ -149,32 +149,32 @@ } } if (!clazz.getModifiers().contains(Modifier.PUBLIC)) { - throw new LayerGenerationException("Class must be public", e); + throw new LayerGenerationException("Class must be public", e, processingEnv, mvr); } type[0] = e.asType(); return new String[] {processingEnv.getElementUtils().getBinaryName(clazz).toString(), null}; } else { ExecutableElement meth = (ExecutableElement) e; if (!processingEnv.getTypeUtils().isAssignable(meth.getReturnType(), mve)) { - throw new LayerGenerationException("Not assignable to " + mve, e); + throw new LayerGenerationException("Not assignable to " + mve, e, processingEnv, mvr); } if (!meth.getModifiers().contains(Modifier.PUBLIC)) { - throw new LayerGenerationException("Method must be public", e); + throw new LayerGenerationException("Method must be public", e, processingEnv, mvr); } if (!meth.getModifiers().contains(Modifier.STATIC)) { - throw new LayerGenerationException("Method must be static", e); + throw new LayerGenerationException("Method must be static", e, processingEnv, mvr); } List params = meth.getParameters(); if (params.size() > 1) { - throw new LayerGenerationException("Method must take at most one parameter", e); + throw new LayerGenerationException("Method must take at most one parameter", e, processingEnv, mvr); } for (VariableElement param : params) { if (!param.asType().equals(lkp)) { - throw new LayerGenerationException("Method parameters may be either Lookup or Project", e); + throw new LayerGenerationException("Method parameters may be either Lookup or Project", e, processingEnv, mvr); } } if (!meth.getEnclosingElement().getModifiers().contains(Modifier.PUBLIC)) { - throw new LayerGenerationException("Class must be public", e); + throw new LayerGenerationException("Class must be public", e, processingEnv, mvr); } type[0] = meth.getReturnType(); return new String[] { diff --git a/javahelp/nbproject/project.xml b/javahelp/nbproject/project.xml --- a/javahelp/nbproject/project.xml +++ b/javahelp/nbproject/project.xml @@ -79,7 +79,7 @@ - 7.19 + 7.50 diff --git a/javahelp/src/org/netbeans/modules/javahelp/HelpSetRegistrationProcessor.java b/javahelp/src/org/netbeans/modules/javahelp/HelpSetRegistrationProcessor.java --- a/javahelp/src/org/netbeans/modules/javahelp/HelpSetRegistrationProcessor.java +++ b/javahelp/src/org/netbeans/modules/javahelp/HelpSetRegistrationProcessor.java @@ -126,9 +126,9 @@ } }); } catch (IOException x) { - throw new LayerGenerationException("Could not parse " + hs + ": " + x, e); + throw new LayerGenerationException("Could not parse " + hs + ": " + x, e, processingEnv, r, "helpSet"); } catch (SAXException x) { - throw new LayerGenerationException("Could not parse " + hs + ": " + x, e); + throw new LayerGenerationException("Could not parse " + hs + ": " + x, e, processingEnv, r, "helpSet"); } String searchDir = null; for (Element view : XMLUtil.findSubElements(doc.getDocumentElement())) { diff --git a/openide.awt/nbproject/project.xml b/openide.awt/nbproject/project.xml --- a/openide.awt/nbproject/project.xml +++ b/openide.awt/nbproject/project.xml @@ -54,7 +54,7 @@ - 7.39 + 7.50 diff --git a/openide.awt/src/org/netbeans/modules/openide/awt/ActionProcessor.java b/openide.awt/src/org/netbeans/modules/openide/awt/ActionProcessor.java --- a/openide.awt/src/org/netbeans/modules/openide/awt/ActionProcessor.java +++ b/openide.awt/src/org/netbeans/modules/openide/awt/ActionProcessor.java @@ -41,7 +41,6 @@ import java.awt.event.ActionListener; import java.io.IOException; -import java.io.InputStream; import java.util.Collections; import java.util.HashSet; import java.util.Set; @@ -65,7 +64,6 @@ import javax.swing.Action; import javax.swing.JSeparator; import javax.swing.KeyStroke; -import javax.tools.FileObject; import javax.tools.StandardLocation; import org.openide.awt.ActionID; import org.openide.awt.ActionReference; @@ -179,26 +177,26 @@ ActionRegistration ar = e.getAnnotation(ActionRegistration.class); ActionID aid = e.getAnnotation(ActionID.class); if (aid == null) { - throw new LayerGenerationException("@ActionRegistration can only be used together with @ActionID annotation", e); + throw new LayerGenerationException("@ActionRegistration can only be used together with @ActionID annotation", e, processingEnv, ar); } if (aid.category().startsWith("Actions/")) { - throw new LayerGenerationException("@ActionID category() cannot contain /", e); + throw new LayerGenerationException("@ActionID category() cannot contain /", e, processingEnv, aid, "category"); } if (!FQN.matcher(aid.id()).matches()) { - throw new LayerGenerationException("@ActionID id() must be valid fully qualified name", e); + throw new LayerGenerationException("@ActionID id() must be valid fully qualified name", e, processingEnv, aid, "id"); } String id = aid.id().replace('.', '-'); File f = layer(e).file("Actions/" + aid.category() + "/" + id + ".instance"); - f.bundlevalue("displayName", ar.displayName()); + f.bundlevalue("displayName", ar.displayName(), ar, "displayName"); String menuText = ar.menuText(); if(!menuText.isEmpty()) { - f.bundlevalue("menuText", menuText); + f.bundlevalue("menuText", menuText, ar, "menuText"); } String popupText = ar.popupText(); if (!popupText.isEmpty()) { - f.bundlevalue("popupText", popupText); + f.bundlevalue("popupText", popupText, ar, "popupText"); } String key; @@ -212,25 +210,25 @@ !e.getModifiers().contains(Modifier.STATIC) || !e.getModifiers().contains(Modifier.FINAL) ) { - throw new LayerGenerationException("Only static string constant fields can be annotated", e); + throw new LayerGenerationException("Only static string constant fields can be annotated", e, processingEnv, ar); } if (ar.key().length() != 0) { - throw new LayerGenerationException("When annotating field, one cannot define key()", e); + throw new LayerGenerationException("When annotating field, one cannot define key()", e, processingEnv, ar, "key"); } createDelegate = false; key = var.getConstantValue().toString(); } else if (e.getKind() == ElementKind.CLASS) { if (!isAssignable(e.asType(), actionListener)) { - throw new LayerGenerationException("Class annotated with @ActionRegistration must implement java.awt.event.ActionListener!", e); + throw new LayerGenerationException("Class annotated with @ActionRegistration must implement java.awt.event.ActionListener!", e, processingEnv, ar); } if (!e.getModifiers().contains(Modifier.PUBLIC)) { - throw new LayerGenerationException("Class has to be public", e); + throw new LayerGenerationException("Class has to be public", e, processingEnv, ar); } key = ar.key(); } else { assert e.getKind() == ElementKind.METHOD : e; - layer(e).instanceFile("dummy", null, ActionListener.class); + layer(e).instanceFile("dummy", null, ActionListener.class, ar, null); key = ar.key(); } @@ -244,7 +242,7 @@ if (direct) { if (key.length() != 0) { - throw new LayerGenerationException("Cannot specify key and implement Presenter interface", e); + throw new LayerGenerationException("Cannot specify key and implement Presenter interface", e, processingEnv, ar, "key"); } f.instanceAttribute("instanceCreate", Action.class); } else { @@ -259,9 +257,9 @@ } if (createDelegate) { try { - f.instanceAttribute("delegate", ActionListener.class); + f.instanceAttribute("delegate", ActionListener.class, ar, null); } catch (LayerGenerationException ex) { - generateContext(e, f); + generateContext(e, f, ar); } } if (ar.iconBase().length() > 0) { @@ -274,12 +272,12 @@ } catch (IOException ex) { continue; } catch (IllegalArgumentException x) { - throw new LayerGenerationException("Problem with " + ar.iconBase() + " (should be resource path with no leading slash)", e); + throw new LayerGenerationException("Problem with " + ar.iconBase() + " (should be resource path with no leading slash)", e, processingEnv, ar, "iconBase"); } } if (!found) { throw new LayerGenerationException( - "Cannot find iconBase file at " + ar.iconBase(), e + "Cannot find iconBase file at " + ar.iconBase(), e, processingEnv, ar, "iconBase" ); } f.stringvalue("iconBase", ar.iconBase()); @@ -310,35 +308,34 @@ if (e.getAnnotation(ActionRegistration.class) != null) { continue; } + ActionReference ref = e.getAnnotation(ActionReference.class); ActionID id = e.getAnnotation(ActionID.class); if (id != null) { - ActionReference ref = e.getAnnotation(ActionReference.class); processReferences(e, ref, id); continue; } - throw new LayerGenerationException("Don't use @ActionReference without @ActionID", e); + throw new LayerGenerationException("Don't use @ActionReference without @ActionID", e, processingEnv, ref); } for (Element e : roundEnv.getElementsAnnotatedWith(ActionReferences.class)) { if (e.getAnnotation(ActionRegistration.class) != null) { continue; } + ActionReferences refs = e.getAnnotation(ActionReferences.class); if (e.getKind() != ElementKind.PACKAGE) { ActionID id = e.getAnnotation(ActionID.class); if (id == null) { - throw new LayerGenerationException("Don't use @ActionReferences without @ActionRegistration", e); + throw new LayerGenerationException("Don't use @ActionReferences without @ActionRegistration", e, processingEnv, refs); } - ActionReferences refs = e.getAnnotation(ActionReferences.class); for (ActionReference actionReference : refs.value()) { if (!actionReference.id().id().isEmpty() || !actionReference.id().category().isEmpty()) { - throw new LayerGenerationException("Don't specify additional id=@ActionID(...) when using @ActionID on the element", e); + throw new LayerGenerationException("Don't specify additional id=@ActionID(...) when using @ActionID on the element", e, processingEnv, actionReference.id()); } processReferences(e, actionReference, id); } } else { - ActionReferences refs = e.getAnnotation(ActionReferences.class); for (ActionReference actionReference : refs.value()) { if (actionReference.id().id().isEmpty() || actionReference.id().category().isEmpty()) { - throw new LayerGenerationException("Specify real id=@ActionID(...)", e); + throw new LayerGenerationException("Specify real id=@ActionID(...)", e, processingEnv, actionReference.id()); } processReferences(e, actionReference, actionReference.id()); } @@ -352,7 +349,7 @@ return e == null ? null : e.asType(); } - private void generateContext(Element e, File f) throws LayerGenerationException { + private void generateContext(Element e, File f, ActionRegistration ar) throws LayerGenerationException { ExecutableElement ee = null; ExecutableElement candidate = null; for (ExecutableElement element : ElementFilter.constructorsIn(e.getEnclosedElements())) { @@ -362,7 +359,7 @@ continue; } if (ee != null) { - throw new LayerGenerationException("Only one public constructor allowed", e); // NOI18N + throw new LayerGenerationException("Only one public constructor allowed", e, processingEnv, ar); // NOI18N } ee = element; } @@ -412,7 +409,7 @@ private void processReferences(Element e, ActionReference ref, ActionID aid) throws LayerGenerationException { if (!ref.id().category().isEmpty() && !ref.id().id().isEmpty()) { if (!aid.id().equals(ref.id().id()) || !aid.category().equals(ref.id().category())) { - throw new LayerGenerationException("Can't specify id() attribute when @ActionID provided on the element", e); + throw new LayerGenerationException("Can't specify id() attribute when @ActionID provided on the element", e, processingEnv, aid); } } String name = ref.name(); @@ -427,7 +424,7 @@ "Registrations in Shortcuts folder need to represent a key. " + "Specify value for 'name' attribute.\n" + "See org.openide.util.Utilities.stringToKeys for possible values. Current " - + "name=\"" + name + "\" is not valid.\n" + + "name=\"" + name + "\" is not valid.\n", e, processingEnv, ref, "path" ); } } @@ -439,7 +436,7 @@ if (ref.separatorAfter() != Integer.MAX_VALUE) { if (ref.position() == Integer.MAX_VALUE || ref.position() >= ref.separatorAfter()) { - throw new LayerGenerationException("separatorAfter() must be greater than position()", e); + throw new LayerGenerationException("separatorAfter() must be greater than position()", e, processingEnv, ref); } File after = layer(e).file(ref.path() + "/" + name + "-separatorAfter.instance"); after.newvalue("instanceCreate", JSeparator.class.getName()); @@ -448,7 +445,7 @@ } if (ref.separatorBefore() != Integer.MAX_VALUE) { if (ref.position() == Integer.MAX_VALUE || ref.position() <= ref.separatorBefore()) { - throw new LayerGenerationException("separatorBefore() must be lower than position()", e); + throw new LayerGenerationException("separatorBefore() must be lower than position()", e, processingEnv, ref); } File before = layer(e).file(ref.path() + "/" + name + "-separatorBefore.instance"); before.newvalue("instanceCreate", JSeparator.class.getName()); diff --git a/openide.filesystems/apichanges.xml b/openide.filesystems/apichanges.xml --- a/openide.filesystems/apichanges.xml +++ b/openide.filesystems/apichanges.xml @@ -49,6 +49,28 @@ Filesystems API + + + LayerGenerationException has new constructors + + + + +

+ Code using the constructors not specifying an annotation should now do so. +

+
+ +

+ LayerGenerationException has new constructors making it easier to specify + the particular annotation responsible for a problem. + Some methods in LayerBuilder have new overloads to take advantage of it. +

+
+ + + +
FileUtil.getConfigObject @@ -59,7 +81,7 @@

One can convert files in SystemFileSystem to Object with - a + a single utility method.

diff --git a/openide.filesystems/manifest.mf b/openide.filesystems/manifest.mf --- a/openide.filesystems/manifest.mf +++ b/openide.filesystems/manifest.mf @@ -2,5 +2,5 @@ OpenIDE-Module: org.openide.filesystems OpenIDE-Module-Localizing-Bundle: org/openide/filesystems/Bundle.properties OpenIDE-Module-Layer: org/openide/filesystems/resources/layer.xml -OpenIDE-Module-Specification-Version: 7.49 +OpenIDE-Module-Specification-Version: 7.50 diff --git a/openide.filesystems/src/org/openide/filesystems/annotations/LayerBuilder.java b/openide.filesystems/src/org/openide/filesystems/annotations/LayerBuilder.java --- a/openide.filesystems/src/org/openide/filesystems/annotations/LayerBuilder.java +++ b/openide.filesystems/src/org/openide/filesystems/annotations/LayerBuilder.java @@ -45,7 +45,7 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; -import java.io.ObjectOutputStream; +import java.lang.annotation.Annotation; import java.net.URI; import java.util.Arrays; import java.util.LinkedHashMap; @@ -146,8 +146,27 @@ * {@linkplain TypeElement class} or {@linkplain ExecutableElement method} * @throws LayerGenerationException if the associated element would not be loadable as an instance of the specified type */ - public File instanceFile(String path, String name, Class type) throws IllegalArgumentException, LayerGenerationException { - String[] clazzOrMethod = instantiableClassOrMethod(type); + public File instanceFile(String path, String name, Class type) throws IllegalArgumentException, LayerGenerationException { + return instanceFile(path, name, type, null, null); + } + /** + * Generates an instance file whose {@code InstanceCookie} would load the associated class or method. + * Useful for {@link LayerGeneratingProcessor}s which define layer fragments which instantiate Java objects from the annotated code. + *

While you can pick a specific instance file name, if possible you should pass null for {@code name} + * as using the generated name will help avoid accidental name collisions between annotations. + * @param path path to folder of instance file, e.g. {@code "Menu/File"} + * @param name instance file basename, e.g. {@code "my-menu-Item"}, or null to pick a name according to the element + * @param type a type to which the instance ought to be assignable, or null to skip this check + * @param annotation as in {@link LayerGenerationException#LayerGenerationException(String,Element,ProcessingEnvironment,Annotation,String)} + * @param annotationMethod as in {@link LayerGenerationException#LayerGenerationException(String,Element,ProcessingEnvironment,Annotation,String)} + * @return an instance file (call {@link File#write} to finalize) + * @throws IllegalArgumentException if the builder is not associated with exactly one + * {@linkplain TypeElement class} or {@linkplain ExecutableElement method} + * @throws LayerGenerationException if the associated element would not be loadable as an instance of the specified type + * @since 7.50 + */ + public File instanceFile(String path, String name, Class type, Annotation annotation, String annotationMethod) throws IllegalArgumentException, LayerGenerationException { + String[] clazzOrMethod = instantiableClassOrMethod(type, annotation, annotationMethod); String clazz = clazzOrMethod[0]; String method = clazzOrMethod[1]; String basename; @@ -185,7 +204,28 @@ * @since org.openide.filesystems 7.27 */ public File instanceFile(String path, String name) throws IllegalArgumentException, LayerGenerationException { - String[] clazzOrMethod = instantiableClassOrMethod(null); + return instanceFile(path, name, null, null); + } + /** + * Generates an instance file that is not initialized with an instance. + * Useful for {@link LayerGeneratingProcessor}s which define layer fragments + * which indirectly instantiate Java objects from the annotated code via a generic factory method. + * Invoke the factory using {@link File#methodvalue} on {@code instanceCreate} + * and configure it with a {@link File#instanceAttribute} appropriate to the factory. + *

While you can pick a specific instance file name, if possible you should pass null for {@code name} + * as using the generated name will help avoid accidental name collisions between annotations. + * @param path path to folder of instance file, e.g. {@code "Menu/File"} + * @param name instance file basename, e.g. {@code "my-menu-Item"}, or null to pick a name according to the element + * @param annotation as in {@link LayerGenerationException#LayerGenerationException(String,Element,ProcessingEnvironment,Annotation,String)} + * @param annotationMethod as in {@link LayerGenerationException#LayerGenerationException(String,Element,ProcessingEnvironment,Annotation,String)} + * @return an instance file (call {@link File#write} to finalize) + * @throws IllegalArgumentException if the builder is not associated with exactly one + * {@linkplain TypeElement class} or {@linkplain ExecutableElement method} + * @throws LayerGenerationException if the associated element would not be loadable as an instance + * @since org.openide.filesystems 7.50 + */ + public File instanceFile(String path, String name, Annotation annotation, String annotationMethod) throws IllegalArgumentException, LayerGenerationException { + String[] clazzOrMethod = instantiableClassOrMethod(null, annotation, annotationMethod); String clazz = clazzOrMethod[0]; String method = clazzOrMethod[1]; String basename; @@ -200,7 +240,7 @@ return file(path + "/" + basename + ".instance"); } - private String[] instantiableClassOrMethod(Class type) throws IllegalArgumentException, LayerGenerationException { + private String[] instantiableClassOrMethod(Class type, Annotation annotation, String annotationMethod) throws IllegalArgumentException, LayerGenerationException { if (originatingElement == null) { throw new IllegalArgumentException("Only applicable to builders with exactly one associated element"); } @@ -212,7 +252,7 @@ case CLASS: { String clazz = processingEnv.getElementUtils().getBinaryName((TypeElement) originatingElement).toString(); if (originatingElement.getModifiers().contains(Modifier.ABSTRACT)) { - throw new LayerGenerationException(clazz + " must not be abstract", originatingElement); + throw new LayerGenerationException(clazz + " must not be abstract", originatingElement, processingEnv, annotation, annotationMethod); } { boolean hasDefaultCtor = false; @@ -223,14 +263,14 @@ } } if (!hasDefaultCtor) { - throw new LayerGenerationException(clazz + " must have a no-argument constructor", originatingElement); + throw new LayerGenerationException(clazz + " must have a no-argument constructor", originatingElement, processingEnv, annotation, annotationMethod); } } if (typeMirror != null && !processingEnv.getTypeUtils().isAssignable(originatingElement.asType(), typeMirror)) { - throw new LayerGenerationException(clazz + " is not assignable to " + typeMirror, originatingElement); + throw new LayerGenerationException(clazz + " is not assignable to " + typeMirror, originatingElement, processingEnv, annotation, annotationMethod); } if (!originatingElement.getModifiers().contains(Modifier.PUBLIC)) { - throw new LayerGenerationException(clazz + " is not public", originatingElement); + throw new LayerGenerationException(clazz + " is not public", originatingElement, processingEnv, annotation, annotationMethod); } return new String[] {clazz, null}; } @@ -238,13 +278,13 @@ String clazz = processingEnv.getElementUtils().getBinaryName((TypeElement) originatingElement.getEnclosingElement()).toString(); String method = originatingElement.getSimpleName().toString(); if (!originatingElement.getModifiers().contains(Modifier.STATIC)) { - throw new LayerGenerationException(clazz + "." + method + " must be static", originatingElement); + throw new LayerGenerationException(clazz + "." + method + " must be static", originatingElement, processingEnv, annotation, annotationMethod); } if (!((ExecutableElement) originatingElement).getParameters().isEmpty()) { - throw new LayerGenerationException(clazz + "." + method + " must not take arguments", originatingElement); + throw new LayerGenerationException(clazz + "." + method + " must not take arguments", originatingElement, processingEnv, annotation, annotationMethod); } if (typeMirror != null && !processingEnv.getTypeUtils().isAssignable(((ExecutableElement) originatingElement).getReturnType(), typeMirror)) { - throw new LayerGenerationException(clazz + "." + method + " is not assignable to " + typeMirror, originatingElement); + throw new LayerGenerationException(clazz + "." + method + " is not assignable to " + typeMirror, originatingElement, processingEnv, annotation, annotationMethod); } return new String[] {clazz, method}; } @@ -485,8 +525,23 @@ * @throws IllegalArgumentException if the associated element is not a {@linkplain TypeElement class} or {@linkplain ExecutableElement method} * @throws LayerGenerationException if the associated element would not be loadable as an instance of the specified type */ - public File instanceAttribute(String attr, Class type) throws IllegalArgumentException, LayerGenerationException { - String[] clazzOrMethod = instantiableClassOrMethod(type); + public File instanceAttribute(String attr, Class type) throws IllegalArgumentException, LayerGenerationException { + return instanceAttribute(attr, type, null, null); + } + /** + * Adds an attribute to load the associated class or method. + * Useful for {@link LayerGeneratingProcessor}s which define layer fragments which instantiate Java objects from the annotated code. + * @param attr the attribute name + * @param type a type to which the instance ought to be assignable, or null to skip this check + * @param annotation as in {@link LayerGenerationException#LayerGenerationException(String,Element,ProcessingEnvironment,Annotation,String)} + * @param annotationMethod as in {@link LayerGenerationException#LayerGenerationException(String,Element,ProcessingEnvironment,Annotation,String)} + * @return this builder + * @throws IllegalArgumentException if the associated element is not a {@linkplain TypeElement class} or {@linkplain ExecutableElement method} + * @throws LayerGenerationException if the associated element would not be loadable as an instance of the specified type + * @since 7.50 + */ + public File instanceAttribute(String attr, Class type, Annotation annotation, String annotationMethod) throws IllegalArgumentException, LayerGenerationException { + String[] clazzOrMethod = instantiableClassOrMethod(type, annotation, annotationMethod); if (clazzOrMethod[1] == null) { newvalue(attr, clazzOrMethod[0]); } else { @@ -518,6 +573,22 @@ * @throws LayerGenerationException if a bundle key is requested but it cannot be found in sources */ public File bundlevalue(String attr, String label) throws LayerGenerationException { + return bundlevalue(attr, label, null, null); + } + /** + * Adds an attribute for a possibly localized string. + * @param attr the attribute name + * @param label either a general string to store as is, or a resource bundle reference + * such as {@code "my.module.Bundle#some_key"}, + * or just {@code "#some_key"} to load from a {@code "Bundle"} + * in the same package as the element associated with this builder (if exactly one) + * @param annotation as in {@link LayerGenerationException#LayerGenerationException(String,Element,ProcessingEnvironment,Annotation,String)} + * @param annotationMethod as in {@link LayerGenerationException#LayerGenerationException(String,Element,ProcessingEnvironment,Annotation,String)} + * @return this builder + * @throws LayerGenerationException if a bundle key is requested but it cannot be found in sources + * @since 7.50 + */ + public File bundlevalue(String attr, String label, Annotation annotation, String annotationMethod) throws LayerGenerationException { String javaIdentifier = "(?:\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*)"; Matcher m = Pattern.compile("((?:" + javaIdentifier + "\\.)+[^\\s.#]+)?#(\\S*)").matcher(label); if (m.matches()) { @@ -533,14 +604,14 @@ } bundle = ((PackageElement) referenceElement).getQualifiedName() + ".Bundle"; } - verifyBundleKey(bundle, key, m.group(1) == null); + verifyBundleKey(bundle, key, m.group(1) == null, annotation, annotationMethod); bundlevalue(attr, bundle, key); } else { stringvalue(attr, label); } return this; } - private void verifyBundleKey(String bundle, String key, boolean samePackage) throws LayerGenerationException { + private void verifyBundleKey(String bundle, String key, boolean samePackage, Annotation annotation, String annotationMethod) throws LayerGenerationException { if (processingEnv == null) { return; } @@ -572,13 +643,13 @@ Properties p = new Properties(); p.load(is); if (p.getProperty(key) == null) { - throw new LayerGenerationException("No key '" + key + "' found in " + resource, originatingElement); + throw new LayerGenerationException("No key '" + key + "' found in " + resource, originatingElement, processingEnv, annotation, annotationMethod); } } finally { is.close(); } } catch (IOException x) { - throw new LayerGenerationException("Could not open " + resource + ": " + x, originatingElement); + throw new LayerGenerationException("Could not open " + resource + ": " + x, originatingElement, processingEnv, annotation, annotationMethod); } } diff --git a/openide.filesystems/src/org/openide/filesystems/annotations/LayerGenerationException.java b/openide.filesystems/src/org/openide/filesystems/annotations/LayerGenerationException.java --- a/openide.filesystems/src/org/openide/filesystems/annotations/LayerGenerationException.java +++ b/openide.filesystems/src/org/openide/filesystems/annotations/LayerGenerationException.java @@ -42,13 +42,19 @@ package org.openide.filesystems.annotations; +import java.lang.annotation.Annotation; +import java.util.Map; import javax.annotation.processing.Messager; +import javax.annotation.processing.ProcessingEnvironment; import javax.lang.model.element.AnnotationMirror; import javax.lang.model.element.AnnotationValue; import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; /** * Exception thrown when a layer entry cannot be generated due to erroneous sources. + * @see LayerGeneratingProcessor * @since org.openide.filesystems 7.15 */ public class LayerGenerationException extends Exception { @@ -63,7 +69,7 @@ * @see Messager#printMessage(javax.tools.Diagnostic.Kind, CharSequence) */ public LayerGenerationException(String message) { - this(message, null, null, null); + this(message, (Element) null, (AnnotationMirror) null, (AnnotationValue) null); } /** @@ -73,7 +79,7 @@ * @see Messager#printMessage(javax.tools.Diagnostic.Kind, CharSequence, Element) */ public LayerGenerationException(String message, Element erroneousElement) { - this(message, erroneousElement, null, null); + this(message, erroneousElement, (AnnotationMirror) null, (AnnotationValue) null); } /** @@ -84,7 +90,7 @@ * @see Messager#printMessage(javax.tools.Diagnostic.Kind, CharSequence, Element, AnnotationMirror) */ public LayerGenerationException(String message, Element erroneousElement, AnnotationMirror erroneousAnnotation) { - this(message, erroneousElement, erroneousAnnotation, null); + this(message, erroneousElement, erroneousAnnotation, (AnnotationValue) null); } /** @@ -102,4 +108,84 @@ this.erroneousAnnotationValue = erroneousAnnotationValue; } + /** + * An exception with an associated annotation. + * Convenience constructor which locates an annotation on the erroneous element for you. + * @param message a detail message which could be reported to the user + * @param erroneousElement the associated element + * @param processingEnv the processing environment passed to the processor + * @param erroneousAnnotation the reflected annotation on the element (may be null as a convenience) + * @see Messager#printMessage(javax.tools.Diagnostic.Kind, CharSequence, Element, AnnotationMirror) + * @since 7.50 + */ + public LayerGenerationException(String message, Element erroneousElement, ProcessingEnvironment processingEnv, + Annotation erroneousAnnotation) { + this(message, erroneousElement, processingEnv, erroneousAnnotation, (String) null); + } + + /** + * An exception with an associated annotation value. + * Convenience constructor which locates an annotation and its value on the erroneous element for you. + * @param message a detail message which could be reported to the user + * @param erroneousElement the associated element + * @param processingEnv the processing environment passed to the processor + * @param erroneousAnnotation the reflected annotation on the element (may be null as a convenience) + * @param erroneousAnnotationMethod the name of a method in that annotation (may be null) + * @see Messager#printMessage(javax.tools.Diagnostic.Kind, CharSequence, Element, AnnotationMirror, AnnotationValue) + * @since 7.50 + */ + public LayerGenerationException(String message, Element erroneousElement, ProcessingEnvironment processingEnv, + Annotation erroneousAnnotation, String erroneousAnnotationMethod) { + super(message); + this.erroneousElement = erroneousElement; + if (erroneousAnnotation != null) { + Class clazz = null; + Class implClass = erroneousAnnotation.getClass(); + for (Class xface : implClass.getInterfaces()) { + if (xface.isAnnotation()) { + if (clazz == null) { + clazz = xface.asSubclass(Annotation.class); + } else { + throw new IllegalArgumentException(">1 annotation implemented by " + implClass.getName()); + } + } + } + if (clazz == null) { + throw new IllegalArgumentException("no annotation implemented by " + implClass.getName()); + } + if (erroneousAnnotationMethod != null) { + try { + clazz.getMethod(erroneousAnnotationMethod); + } catch (NoSuchMethodException x) { + throw new IllegalArgumentException("No such method " + erroneousAnnotationMethod + " in " + erroneousAnnotation); + } catch (SecurityException x) {/* ignore? */} + } + this.erroneousAnnotation = findAnnotationMirror(erroneousElement, processingEnv, clazz); + this.erroneousAnnotationValue = this.erroneousAnnotation != null && erroneousAnnotationMethod != null ? + findAnnotationValue(this.erroneousAnnotation, erroneousAnnotationMethod) : null; + } else { + this.erroneousAnnotation = null; + this.erroneousAnnotationValue = null; + } + } + + private static AnnotationMirror findAnnotationMirror(Element element, ProcessingEnvironment processingEnv, Class annotation) { + for (AnnotationMirror ann : element.getAnnotationMirrors()) { + if (processingEnv.getElementUtils().getBinaryName((TypeElement) ann.getAnnotationType().asElement()). + contentEquals(annotation.getName())) { + return ann; + } + } + return null; + } + + private AnnotationValue findAnnotationValue(AnnotationMirror annotation, String name) { + for (Map.Entry entry : annotation.getElementValues().entrySet()) { + if (entry.getKey().getSimpleName().contentEquals(name)) { + return entry.getValue(); + } + } + return null; + } + } diff --git a/openide.filesystems/test/unit/src/org/openide/filesystems/annotations/LayerGenerationExceptionTest.java b/openide.filesystems/test/unit/src/org/openide/filesystems/annotations/LayerGenerationExceptionTest.java new file mode 100644 --- /dev/null +++ b/openide.filesystems/test/unit/src/org/openide/filesystems/annotations/LayerGenerationExceptionTest.java @@ -0,0 +1,126 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + *

+ * Copyright 2011 Oracle and/or its affiliates. All rights reserved. + *

+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + *

+ * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development and + * Distribution License("CDDL") (collectively, the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy of + * the License at http://www.netbeans.org/cddl-gplv2.html or + * nbbuild/licenses/CDDL-GPL-2-CP. See the License for the specific language + * governing permissions and limitations under the License. When distributing + * the software, include this License Header Notice in each file and include + * the License file at nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided by + * Oracle in the GPL Version 2 section of the License file that accompanied + * this code. If applicable, add the following below the License Header, with + * the fields enclosed by brackets [] replaced by your own identifying + * information: "Portions Copyrighted [year] [name of copyright owner]" + *

+ * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you do not indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to its + * licensees as provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the option applies only + * if the new code is made subject to such option by the copyright holder. + *

+ * Contributor(s): + *

+ * Portions Copyrighted 2011 Sun Microsystems, Inc. + */ + +package org.openide.filesystems.annotations; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; +import javax.annotation.processing.Processor; +import javax.annotation.processing.RoundEnvironment; +import javax.annotation.processing.SupportedSourceVersion; +import javax.lang.model.SourceVersion; +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; +import javax.tools.Diagnostic.Kind; +import org.netbeans.junit.NbTestCase; +import org.openide.util.lookup.ServiceProvider; +import org.openide.util.test.AnnotationProcessorTestUtils; + +public class LayerGenerationExceptionTest extends NbTestCase { + + public LayerGenerationExceptionTest(String name) { + super(name); + } + + public void testFindAnnotationMirror() throws Exception { + File src = new File(getWorkDir(), "src"); + AnnotationProcessorTestUtils.makeSource(src, "p.C", "@" + A.class.getCanonicalName() + "(attr1=\"one\", attr2=\"two\") public class C {}"); + File dest = new File(getWorkDir(), "dest"); + ByteArrayOutputStream err = new ByteArrayOutputStream(); + assertTrue(AnnotationProcessorTestUtils.runJavac(src, null, dest, null, err)); + assertTrue(err.toString(), err.toString().contains("p.C two")); + } + + /* XXX not yet implemented: + public void testFindAnnotationMirrorNested() throws Exception { + File src = new File(getWorkDir(), "src"); + AnnotationProcessorTestUtils.makeSource(src, "p.C", + "@" + AS.class.getCanonicalName() + "({", + "@" + A.class.getCanonicalName() + "(attr1=\"one\", attr2=\"two\"),", + "@" + A.class.getCanonicalName() + "(attr1=\"three\", attr2=\"four\")", + "})", + "public class C {}"); + File dest = new File(getWorkDir(), "dest"); + ByteArrayOutputStream err = new ByteArrayOutputStream(); + boolean r = AnnotationProcessorTestUtils.runJavac(src, null, dest, null, err); + String out = err.toString(); + assertTrue(out, r); + assertTrue(out,out.contains("p.C two")); + assertTrue(out,out.contains("p.C four")); + } + */ + + public @interface A { + String attr1(); + String attr2(); + } + + public @interface AS { + A[] value(); + } + + @ServiceProvider(service=Processor.class) + @SupportedSourceVersion(SourceVersion.RELEASE_6) + public static class AP extends LayerGeneratingProcessor { + public @Override Set getSupportedAnnotationTypes() { + return new HashSet(Arrays.asList(A.class.getCanonicalName(), AS.class.getCanonicalName())); + } + protected @Override boolean handleProcess(Set annotations, RoundEnvironment roundEnv) throws LayerGenerationException { + if (roundEnv.processingOver()) { + return false; + } + for (Element e : roundEnv.getElementsAnnotatedWith(A.class)) { + handle(e, e.getAnnotation(A.class)); + } + for (Element e : roundEnv.getElementsAnnotatedWith(AS.class)) { + for (A a : e.getAnnotation(AS.class).value()) { + handle(e, a); + } + } + return true; + } + private void handle(Element e, A a) { + LayerGenerationException lge = new LayerGenerationException("msg", e, processingEnv, a, "attr2"); + processingEnv.getMessager().printMessage(Kind.NOTE, lge.erroneousElement + " " + (lge.erroneousAnnotationValue != null ? lge.erroneousAnnotationValue.getValue() : null)); + } + } + +} diff --git a/openide.windows/src/org/netbeans/modules/openide/windows/TopComponentProcessor.java b/openide.windows/src/org/netbeans/modules/openide/windows/TopComponentProcessor.java --- a/openide.windows/src/org/netbeans/modules/openide/windows/TopComponentProcessor.java +++ b/openide.windows/src/org/netbeans/modules/openide/windows/TopComponentProcessor.java @@ -83,7 +83,7 @@ Description info = findInfo(e); if (info == null) { - throw new LayerGenerationException("Cannot find TopComponent.Description for this element", e); + throw new LayerGenerationException("Cannot find TopComponent.Description for this element", e, processingEnv, reg); } String id = info.preferredID().replace('.', '-'); @@ -112,11 +112,11 @@ File actionFile = layer(e). file("Actions/" + aid.category() + "/" + aid.id().replace('.', '-') + ".instance"). methodvalue("instanceCreate", "org.openide.windows.TopComponent", "openAction"); - actionFile.instanceAttribute("component", TopComponent.class); + actionFile.instanceAttribute("component", TopComponent.class, reg, null); if (reg.preferredID().length() > 0) { actionFile.stringvalue("preferredID", reg.preferredID()); } - actionFile.bundlevalue("displayName", reg.displayName()); + actionFile.bundlevalue("displayName", reg.displayName(), reg, "displayName"); if (info != null && info.iconBase().length() > 0) { actionFile.stringvalue("iconBase", info.iconBase()); } diff --git a/options.api/nbproject/project.xml b/options.api/nbproject/project.xml --- a/options.api/nbproject/project.xml +++ b/options.api/nbproject/project.xml @@ -120,7 +120,7 @@ - 7.27 + 7.50 diff --git a/options.api/src/org/netbeans/modules/options/OptionsPanelControllerProcessor.java b/options.api/src/org/netbeans/modules/options/OptionsPanelControllerProcessor.java --- a/options.api/src/org/netbeans/modules/options/OptionsPanelControllerProcessor.java +++ b/options.api/src/org/netbeans/modules/options/OptionsPanelControllerProcessor.java @@ -44,6 +44,7 @@ import java.io.FileNotFoundException; import java.io.IOException; +import java.lang.annotation.Annotation; import java.util.Arrays; import java.util.HashSet; import java.util.Set; @@ -83,26 +84,26 @@ } for (Element e : roundEnv.getElementsAnnotatedWith(TopLevelRegistration.class)) { TopLevelRegistration r = e.getAnnotation(TopLevelRegistration.class); - File file = layer(e).instanceFile("OptionsDialog", r.id().length() > 0 ? r.id() : null). + File file = layer(e).instanceFile("OptionsDialog", r.id().length() > 0 ? r.id() : null, r, null). methodvalue("instanceCreate", OptionsCategory.class.getName(), "createCategory"). instanceAttribute("controller", OptionsPanelController.class). bundlevalue("categoryName", r.categoryName()). position(r.position()); - iconBase(e, r.iconBase(), file); - keywords(e, r.keywords(), r.keywordsCategory(), file); + iconBase(e, r.iconBase(), r, file); + keywords(e, r.keywords(), r.keywordsCategory(), r, file); file.write(); } for (Element e : roundEnv.getElementsAnnotatedWith(SubRegistration.class)) { SubRegistration r = e.getAnnotation(SubRegistration.class); if (r.position() != Integer.MAX_VALUE && r.location().equals("Advanced")) { - throw new LayerGenerationException("position ignored for Advanced subpanels", e); + throw new LayerGenerationException("position ignored for Advanced subpanels", e, processingEnv, r, "position"); } - File file = layer(e).instanceFile("OptionsDialog/" + r.location(), r.id().length() > 0 ? r.id() : null). + File file = layer(e).instanceFile("OptionsDialog/" + r.location(), r.id().length() > 0 ? r.id() : null, r, null). methodvalue("instanceCreate", AdvancedOption.class.getName(), "createSubCategory"). instanceAttribute("controller", OptionsPanelController.class). bundlevalue("displayName", r.displayName()). position(r.position()); - keywords(e, r.keywords(), r.keywordsCategory(), file); + keywords(e, r.keywords(), r.keywordsCategory(), r, file); file.write(); } for (Element e : roundEnv.getElementsAnnotatedWith(ContainerRegistration.class)) { @@ -112,15 +113,15 @@ stringvalue("advancedOptionsFolder", "OptionsDialog/" + r.id()). bundlevalue("categoryName", r.categoryName()). position(r.position()); - iconBase(e, r.iconBase(), file); - keywords(e, r.keywords(), r.keywordsCategory(), file); + iconBase(e, r.iconBase(), r, file); + keywords(e, r.keywords(), r.keywordsCategory(), r, file); file.write(); layer(e).folder("OptionsDialog/" + r.id()).position(0).write(); } return true; } - private void iconBase(Element e, String iconBase, File file) throws LayerGenerationException { + private void iconBase(Element e, String iconBase, Annotation r, File file) throws LayerGenerationException { try { // XXX should probably be made a utility method in LayerBuilder try { processingEnv.getFiler().getResource(StandardLocation.SOURCE_PATH, "", iconBase).openInputStream().close(); @@ -132,20 +133,20 @@ } } } catch (IOException x) { - throw new LayerGenerationException("Could not open " + iconBase + ": " + x, e); + throw new LayerGenerationException("Could not open " + iconBase + ": " + x, e, processingEnv, r, "iconBase"); } file.stringvalue("iconBase", iconBase); } - private void keywords(Element e, String keywords, String keywordsCategory, File file) throws LayerGenerationException { + private void keywords(Element e, String keywords, String keywordsCategory, Annotation r, File file) throws LayerGenerationException { if (keywords.length() > 0) { if (keywordsCategory.length() == 0) { - throw new LayerGenerationException("Must specify both keywords and keywordsCategory", e); + throw new LayerGenerationException("Must specify both keywords and keywordsCategory", e, processingEnv, r, "keywordsCategory"); } - file.bundlevalue("keywords", keywords).bundlevalue("keywordsCategory", keywordsCategory); + file.bundlevalue("keywords", keywords, r, "keywords").bundlevalue("keywordsCategory", keywordsCategory, r, "keywordsCategory"); } else { if (keywordsCategory.length() > 0) { - throw new LayerGenerationException("Must specify both keywords and keywordsCategory", e); + throw new LayerGenerationException("Must specify both keywords and keywordsCategory", e, processingEnv, r, "keywords"); } } } diff --git a/project.ant/nbproject/project.xml b/project.ant/nbproject/project.xml --- a/project.ant/nbproject/project.xml +++ b/project.ant/nbproject/project.xml @@ -139,7 +139,7 @@ - 7.19 + 7.50 diff --git a/project.ant/src/org/netbeans/modules/project/ant/AntBasedProcessor.java b/project.ant/src/org/netbeans/modules/project/ant/AntBasedProcessor.java --- a/project.ant/src/org/netbeans/modules/project/ant/AntBasedProcessor.java +++ b/project.ant/src/org/netbeans/modules/project/ant/AntBasedProcessor.java @@ -95,10 +95,10 @@ name = classname.replace('.', '-'); methodname = null; if (!e.getModifiers().contains(Modifier.PUBLIC)) { - throw new LayerGenerationException("Class needs to be public"); // NOI18N + throw new LayerGenerationException("Class needs to be public", e, processingEnv, reg); // NOI18N } if (!processingEnv.getTypeUtils().isAssignable(e.asType(), project)) { - throw new LayerGenerationException("Class needs to extend Project"); // NOI18N + throw new LayerGenerationException("Class needs to extend Project", e, processingEnv, reg); // NOI18N } boolean found = false; for (Element cns : processingEnv.getElementUtils().getAllMembers((TypeElement)e)) { @@ -118,7 +118,7 @@ } } if (!found) { - throw new LayerGenerationException("There needs to be public constructor taking AntProjectHelper parameter"); // NOI18N + throw new LayerGenerationException("There needs to be public constructor taking AntProjectHelper parameter", e, processingEnv, reg); // NOI18N } break; @@ -128,7 +128,7 @@ name = (classname + "." + methodname).replace('.', '-'); if (!e.getEnclosingElement().getModifiers().contains(Modifier.PUBLIC)) { - throw new LayerGenerationException("Class needs to be public"); // NOI18N + throw new LayerGenerationException("Class needs to be public", e, processingEnv, reg); // NOI18N } ExecutableElement exec = (ExecutableElement)e; @@ -138,10 +138,10 @@ exec.getParameters().size() != 1 || !exec.getParameters().get(0).asType().equals(antHelper) ) { - throw new LayerGenerationException("The method needs to be public, static and take AntProjectHelper argument"); // NOI18N + throw new LayerGenerationException("The method needs to be public, static and take AntProjectHelper argument", e, processingEnv, reg); // NOI18N } if (!processingEnv.getTypeUtils().isAssignable(exec.getReturnType(), project)) { - throw new LayerGenerationException("Method needs to return Project"); // NOI18N + throw new LayerGenerationException("Method needs to return Project", e, processingEnv, reg); // NOI18N } break; diff --git a/projectapi/nbproject/project.xml b/projectapi/nbproject/project.xml --- a/projectapi/nbproject/project.xml +++ b/projectapi/nbproject/project.xml @@ -63,7 +63,7 @@ - 6.2 + 7.50 diff --git a/projectapi/src/org/netbeans/modules/projectapi/LookupProviderAnnotationProcessor.java b/projectapi/src/org/netbeans/modules/projectapi/LookupProviderAnnotationProcessor.java --- a/projectapi/src/org/netbeans/modules/projectapi/LookupProviderAnnotationProcessor.java +++ b/projectapi/src/org/netbeans/modules/projectapi/LookupProviderAnnotationProcessor.java @@ -96,32 +96,32 @@ for (Element e : roundEnv.getElementsAnnotatedWith(LookupProvider.Registration.class)) { LookupProvider.Registration lpr = e.getAnnotation(LookupProvider.Registration.class); if (lpr.projectType().length == 0 && lpr.projectTypes().length == 0) { - throw new LayerGenerationException("You must specify either projectType or projectTypes", e); + throw new LayerGenerationException("You must specify either projectType or projectTypes", e, processingEnv, lpr); } for (String type : lpr.projectType()) { - layer(e).instanceFile("Projects/" + type + "/Lookup", null, LookupProvider.class).write(); + layer(e).instanceFile("Projects/" + type + "/Lookup", null, LookupProvider.class, lpr, null).write(); } for (LookupProvider.Registration.ProjectType type : lpr.projectTypes()) { - layer(e).instanceFile("Projects/" + type.id() + "/Lookup", null, LookupProvider.class).position(type.position()).write(); + layer(e).instanceFile("Projects/" + type.id() + "/Lookup", null, LookupProvider.class, type, null).position(type.position()).write(); } } for (Element e : roundEnv.getElementsAnnotatedWith(ProjectServiceProvider.class)) { + ProjectServiceProvider psp = e.getAnnotation(ProjectServiceProvider.class); List services = findServiceAnnotation(e); if (services.isEmpty()) { - throw new LayerGenerationException("Must specify at least one service", e); + throw new LayerGenerationException("Must specify at least one service", e, processingEnv, psp); } String servicesBinName = null; for (TypeMirror service : services) { String n = processingEnv.getElementUtils().getBinaryName((TypeElement) processingEnv.getTypeUtils().asElement(service)).toString(); if (n.equals(LookupMerger.class.getName())) { - throw new LayerGenerationException("@ProjectServiceProvider should not be used on LookupMerger; use @LookupMerger.Registration instead", e); + throw new LayerGenerationException("@ProjectServiceProvider should not be used on LookupMerger; use @LookupMerger.Registration instead", e, processingEnv, psp); } servicesBinName = servicesBinName == null ? n : servicesBinName + "," + n; } - String[] binAndMethodNames = findPSPDefinition(e, services); - ProjectServiceProvider psp = e.getAnnotation(ProjectServiceProvider.class); + String[] binAndMethodNames = findPSPDefinition(e, services, psp); if (psp.projectType().length == 0 && psp.projectTypes().length == 0) { - throw new LayerGenerationException("You must specify either projectType or projectTypes", e); + throw new LayerGenerationException("You must specify either projectType or projectTypes", e, processingEnv, psp); } String fileBaseName = binAndMethodNames[0].replace('.', '-'); if (binAndMethodNames[1] != null) { @@ -163,11 +163,11 @@ } DeclaredType service = findLookupMergerType(impl); if (service == null) { - throw new LayerGenerationException("Not assignable to LookupMerger for some T", e); + throw new LayerGenerationException("Not assignable to LookupMerger for some T", e, processingEnv, lmr); } String serviceBinName = processingEnv.getElementUtils().getBinaryName((TypeElement) service.asElement()).toString(); if (lmr.projectType().length == 0 && lmr.projectTypes().length == 0) { - throw new LayerGenerationException("You must specify either projectType or projectTypes", e); + throw new LayerGenerationException("You must specify either projectType or projectTypes", e, processingEnv, lmr); } for (String type : lmr.projectType()) { layer(e).file("Projects/" + type + "/Lookup/" + fileBaseName + ".instance"). @@ -208,12 +208,12 @@ throw new LayerGenerationException("No @ProjectServiceProvider found", e); } - private String[] findPSPDefinition(Element e, List services) throws LayerGenerationException { + private String[] findPSPDefinition(Element e, List services, ProjectServiceProvider psp) throws LayerGenerationException { if (e.getKind() == ElementKind.CLASS) { TypeElement clazz = (TypeElement) e; for (TypeMirror service : services) { if (!processingEnv.getTypeUtils().isAssignable(clazz.asType(), service)) { - throw new LayerGenerationException("Not assignable to " + service, e); + throw new LayerGenerationException("Not assignable to " + service, e, processingEnv, psp); } } int constructorCount = 0; @@ -234,37 +234,37 @@ constructorCount++; } if (constructorCount != 1) { - throw new LayerGenerationException("Must have exactly one public constructor optionally taking Project and/or Lookup", e); + throw new LayerGenerationException("Must have exactly one public constructor optionally taking Project and/or Lookup", e, processingEnv, psp); } if (!clazz.getModifiers().contains(Modifier.PUBLIC)) { - throw new LayerGenerationException("Class must be public", e); + throw new LayerGenerationException("Class must be public", e, processingEnv, psp); } return new String[] {processingEnv.getElementUtils().getBinaryName(clazz).toString(), null}; } else { ExecutableElement meth = (ExecutableElement) e; for (TypeMirror service : services) { if (!processingEnv.getTypeUtils().isAssignable(meth.getReturnType(), service)) { - throw new LayerGenerationException("Not assignable to " + service, e); + throw new LayerGenerationException("Not assignable to " + service, e, processingEnv, psp); } } if (!meth.getModifiers().contains(Modifier.PUBLIC)) { - throw new LayerGenerationException("Method must be public", e); + throw new LayerGenerationException("Method must be public", e, processingEnv, psp); } if (!meth.getModifiers().contains(Modifier.STATIC)) { - throw new LayerGenerationException("Method must be static", e); + throw new LayerGenerationException("Method must be static", e, processingEnv, psp); } List params = meth.getParameters(); if (params.size() > 2) { - throw new LayerGenerationException("Method must take at most two parameters", e); + throw new LayerGenerationException("Method must take at most two parameters", e, processingEnv, psp); } for (VariableElement param : params) { if (!param.asType().equals(processingEnv.getElementUtils().getTypeElement(Project.class.getCanonicalName()).asType()) && !param.asType().equals(processingEnv.getElementUtils().getTypeElement(Lookup.class.getCanonicalName()).asType())) { - throw new LayerGenerationException("Method parameters may be either Lookup or Project", e); + throw new LayerGenerationException("Method parameters may be either Lookup or Project", e, processingEnv, psp); } } if (!meth.getEnclosingElement().getModifiers().contains(Modifier.PUBLIC)) { - throw new LayerGenerationException("Class must be public", e); + throw new LayerGenerationException("Class must be public", e, processingEnv, psp); } return new String[] { processingEnv.getElementUtils().getBinaryName((TypeElement) meth.getEnclosingElement()).toString(), diff --git a/projectuiapi/nbproject/project.xml b/projectuiapi/nbproject/project.xml --- a/projectuiapi/nbproject/project.xml +++ b/projectuiapi/nbproject/project.xml @@ -114,7 +114,7 @@ - 7.26 + 7.50 diff --git a/projectuiapi/src/org/netbeans/modules/project/uiapi/CompositeCategoryProviderAnnotationProcessor.java b/projectuiapi/src/org/netbeans/modules/project/uiapi/CompositeCategoryProviderAnnotationProcessor.java --- a/projectuiapi/src/org/netbeans/modules/project/uiapi/CompositeCategoryProviderAnnotationProcessor.java +++ b/projectuiapi/src/org/netbeans/modules/project/uiapi/CompositeCategoryProviderAnnotationProcessor.java @@ -97,10 +97,10 @@ } if (e.getKind() == ElementKind.PACKAGE) { if (!addsFolder) { - throw new LayerGenerationException("Must specify categoryLabel", e); + throw new LayerGenerationException("Must specify categoryLabel", e, processingEnv, r); } } else { - File f = layer(e).instanceFile(path, addsFolder ? "Self" : null, CompositeCategoryProvider.class); + File f = layer(e).instanceFile(path, addsFolder ? "Self" : null, CompositeCategoryProvider.class, r, null); f.position(addsFolder ? 0 : r.position()); f.write(); } @@ -108,9 +108,9 @@ private void handleFolder(String path, Element e, Registration r) throws LayerGenerationException { if (r.category().length() == 0) { - throw new LayerGenerationException("Must specify category", e); + throw new LayerGenerationException("Must specify category", e, processingEnv, r); } - layer(e).folder(path).bundlevalue("displayName", r.categoryLabel()).position(r.position()).write(); + layer(e).folder(path).bundlevalue("displayName", r.categoryLabel(), r, "categoryLabel").position(r.position()).write(); } } diff --git a/projectuiapi/src/org/netbeans/modules/project/uiapi/NodeFactoryAnnotationProcessor.java b/projectuiapi/src/org/netbeans/modules/project/uiapi/NodeFactoryAnnotationProcessor.java --- a/projectuiapi/src/org/netbeans/modules/project/uiapi/NodeFactoryAnnotationProcessor.java +++ b/projectuiapi/src/org/netbeans/modules/project/uiapi/NodeFactoryAnnotationProcessor.java @@ -73,10 +73,10 @@ return false; } for (Element e : roundEnv.getElementsAnnotatedWith(NodeFactory.Registration.class)) { - NodeFactory.Registration lpr = e.getAnnotation(NodeFactory.Registration.class); - for (String type : lpr.projectType()) { - layer(e).instanceFile("Projects/" + type + "/Nodes", null, NodeFactory.class). //NOI18N - position(lpr.position()).write(); + NodeFactory.Registration r = e.getAnnotation(NodeFactory.Registration.class); + for (String type : r.projectType()) { + layer(e).instanceFile("Projects/" + type + "/Nodes", null, NodeFactory.class, r, null). //NOI18N + position(r.position()).write(); } } return true; diff --git a/settings/nbproject/project.xml b/settings/nbproject/project.xml --- a/settings/nbproject/project.xml +++ b/settings/nbproject/project.xml @@ -88,7 +88,7 @@ - 7.49 + 7.50 diff --git a/settings/src/org/netbeans/modules/settings/convertors/ConvertorProcessor.java b/settings/src/org/netbeans/modules/settings/convertors/ConvertorProcessor.java --- a/settings/src/org/netbeans/modules/settings/convertors/ConvertorProcessor.java +++ b/settings/src/org/netbeans/modules/settings/convertors/ConvertorProcessor.java @@ -44,6 +44,7 @@ package org.netbeans.modules.settings.convertors; +import java.lang.annotation.Annotation; import java.util.Arrays; import java.util.HashSet; import java.util.Set; @@ -93,7 +94,7 @@ for (Element e : env.getElementsAnnotatedWith(ConvertAsProperties.class)) { ConvertAsProperties reg = e.getAnnotation(ConvertAsProperties.class); - String convElem = instantiableClassOrMethod(e, true); + String convElem = instantiableClassOrMethod(e, true, reg); final String dtd = reg.dtd(); String dtdCode = convertPublicId(dtd); @@ -146,7 +147,7 @@ for (Element e : env.getElementsAnnotatedWith(ConvertAsJavaBean.class)) { ConvertAsJavaBean reg = e.getAnnotation(ConvertAsJavaBean.class); - String convElem = instantiableClassOrMethod(e, false); + String convElem = instantiableClassOrMethod(e, false, reg); File f = layer(e).file("xml/memory/" + convElem.replace('.', '/')); f.stringvalue("settings.providerPath", "xml/lookups/NetBeans/DTD_XML_beans_1_0.instance"); if (reg.subclasses()) { @@ -228,12 +229,12 @@ return f.stringvalue("xmlproperties.ignoreChanges", sb.toString()); } - private String instantiableClassOrMethod(Element e, boolean checkMethods) throws IllegalArgumentException, LayerGenerationException { + private String instantiableClassOrMethod(Element e, boolean checkMethods, Annotation r) throws IllegalArgumentException, LayerGenerationException { switch (e.getKind()) { case CLASS: { String clazz = processingEnv.getElementUtils().getBinaryName((TypeElement) e).toString(); if (e.getModifiers().contains(Modifier.ABSTRACT)) { - throw new LayerGenerationException(clazz + " must not be abstract", e); + throw new LayerGenerationException(clazz + " must not be abstract", e, processingEnv, r); } { boolean hasDefaultCtor = false; @@ -244,7 +245,7 @@ } } if (!hasDefaultCtor) { - throw new LayerGenerationException(clazz + " must have a no-argument constructor", e); + throw new LayerGenerationException(clazz + " must have a no-argument constructor", e, processingEnv, r); } } if (checkMethods) { @@ -270,16 +271,16 @@ } } if (!hasRead) { - throw new LayerGenerationException(clazz + " must have proper readProperties method", e); + throw new LayerGenerationException(clazz + " must have proper readProperties method", e, processingEnv, r); } if (!hasWrite) { - throw new LayerGenerationException(clazz + " must have proper writeProperties method", e); + throw new LayerGenerationException(clazz + " must have proper writeProperties method", e, processingEnv, r); } } return clazz; } default: - throw new LayerGenerationException("Annotated element is not loadable as an instance: " + e); + throw new LayerGenerationException("Annotated element is not loadable as an instance", e, processingEnv, r); } } }