blob: 675d59460280a2edab6a64d9604ce713395f2ac2 [file] [log] [blame]
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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.
//
= DevFaqAnnotationDevelopDebug
:jbake-type: wiki
:jbake-tags: wiki, devfaq, needsreview
:jbake-status: published
:keywords: Apache NetBeans wiki DevFaqAnnotationDevelopDebug
:description: Apache NetBeans wiki DevFaqAnnotationDevelopDebug
:toc: left
:toc-title:
:syntax: true
== How do I develop and debug annotations for NetBeans platform apps?
The NetBeans platform has API support for creating XML layer entries from annotations. The popular book "NetBeans Platform for Beginners" has several examples of writing your own annotations. Familiarity with developing annotations and annotation processing is a prerequisite. Though not specifically about NetBeans platform annotations, link:https://netbeans.org/kb/docs/java/annotations.html[Annotation Processors Support in the NetBeans IDE] may also be useful for those new to working with annotions.
The relevant NetBeans platform APIs are described at
link:http://bits.netbeans.org/dev/javadoc/org-openide-filesystems/org/openide/filesystems/annotations/package-summary.html[Package org.openide.filesystems.annotations]. Note that link:http://bits.netbeans.org/dev/javadoc/org-openide-filesystems/org/openide/filesystems/annotations/LayerBuilder.File.html[Class LayerBuilder.File] has the methods for adding specific attributes to a layer file. Near the end of the package description there is mention of _AnnotationProcessorTestUtils_ this is found in the NetBeans sources at _openide.util.lookup/test/unit/src/org/openide/util/test/AnnotationProcessorTestUtils.java_.
Much of the following is found in messages of the thread link:https://forums.netbeans.org/topic63404.html[Debugging Platform annotations], from the platform mailing list.
== Debugging Custom Annotations
=== Printf is your friend
Tim Boudreau says: I've written quite a few annotation processors, and System.out.println() is your friend. Trying to actually step through this stuff in a debugger is pretty useless, but I've never hit something I couldn't solve with plain old console logging.
=== If you really want to use a debugger
There is a mailing list thread link:http://forums.netbeans.org/topic53688.html[Debugging an annotation processor] from a few years ago which has a messy/complicated process suggesting ANT_OPS and "Attach Debugger" outlined by Jaroslav Tulach .
== Hints and techniques for developing annotations
Things that generally bite you when writing an annotation processor:
* Handling unexpected types - i.e. someone writes an annotation and a parameter that's supposed to be an int is in source code as a string - best you can do is catch these and bail out, but if you don't, you'll see an exception dialog pop up in NetBeans when your processor hits code like that
* Dealing with things that explode on contact - i.e. annotation parameters of type Class will throw an exception if you try to read their value via the Annotation instances javac gives you (the Class objects referenced are not necessarily on the classpath, or even valid) - you have to instead find the right AnnotationMirror and get the value as a string - example here, see validatorsForParam() link:https://github.com/timboudreau/numble/blob/master/src/main/java/com/mastfrog/parameters/processor/Processor.java[https://github.com/timboudreau/numble/blob/master/src/main/java/com/mastfrog/parameters/processor/Processor.java]
* Opening or trying to write a file more than once (annotation processing happens in multiple rounds - until the last round you should just collect data) - but LayerGeneratingProcessor should solve this for you if you're using it - but if not, have a look at the source code for it
Anything you do regarding analyzing or using classes when processing annotations you want to do using javac's API - you *do not ever* want to load a user-defined class into an annotation processor. Imagine what
[source,java]
----
static {
for (;;) { EventQueue.invokeLater(new Runnable(){ throw new Error(); })}
}
----
would do if you actually loaded something like that during a compilation.
== Examples
Checking for a subtype, can't use _instanceof_ since should *not* load user classes.
[source,java]
----
public void isSubtypeOf(Element e, String qualifiedClassName) {
Types types = processingEnv.getTypeUtils();
Elements elements = processingEnv.getElementUtils();
TypeElement pageType = elements.getTypeElement(qualifiedClassName);
if (pageType == null) { //not on the classpath javac can see
return false;
}
return types.isSubtype(e.asType(), pageType.asType());
}
----
Getting the elements of an enum, with lots of checking
[source,java]
----
private List<String> getEnumConstants(String enumQalifiedClassName) {
if(enumQalifiedClassName.isEmpty())
return Collections.emptyList();
Element e = processingEnv.getElementUtils()
.getTypeElement(enumQalifiedClassName);
if(e == null) {
processingEnv.getMessager().printMessage(
Diagnostic.Kind.ERROR, "enumQalifiedClassName '" + enumQalifiedClassName
+ "' does not exist");
return null;
}
if(e.getKind() != ElementKind.ENUM) {
processingEnv.getMessager().printMessage(
Diagnostic.Kind.ERROR, "enumQalifiedClassName '" + enumQalifiedClassName
+ "' is not an Enum");
return null;
}
----
[source,java]
----
Types types = processingEnv.getTypeUtils();
List<? extends Element> elems = e.getEnclosedElements();
List<String> enumConstantsNames = new ArrayList<String>(elems.size());
for(Element e01 : elems) {
if(e01.getKind() == ElementKind.ENUM_CONSTANT)
enumConstantsNames.add(e01.getSimpleName().toString());
}
return enumConstantsNames;
}
----
=== Apache Migration Information
The content in this page was kindly donated by Oracle Corp. to the
Apache Software Foundation.
This page was exported from link:http://wiki.netbeans.org/DevFaqAnnotationDevelopDebug[http://wiki.netbeans.org/DevFaqAnnotationDevelopDebug] ,
that was last modified by NetBeans user Err
on 2015-06-07T22:28:27Z.
*NOTE:* This document was automatically converted to the AsciiDoc format on 2018-02-07, and needs to be reviewed.