This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

View | Details | Raw Unified | Return to bug 185457
Collapse All | Expand All

(-)a/java.freeform/apichanges.xml (+12 lines)
Lines 48-53 Link Here
48
    </apidefs>
48
    </apidefs>
49
    <changes>
49
    <changes>
50
50
51
        <change id="annotation-processing">
52
            <summary>Support for annotation processing</summary>
53
            <version major="1" minor="21"/>
54
            <date day="12" month="5" year="2010"/>
55
            <author login="tzezula"/>
56
            <compatibility binary="compatible" source="compatible" semantic="compatible"/>
57
            <description>
58
                Added complete support for annotation processing into freeform-project-java/3 schema which now supports all metadata for
59
                AnnotationProcessingQuery.
60
            </description>
61
            <issue number="185457"/>
62
        </change>
51
        <change id="source-16">
63
        <change id="source-16">
52
            <summary>Added freeform-project-java/3 schema to support annotation processors and source levels 1.6 and 1.7</summary>
64
            <summary>Added freeform-project-java/3 schema to support annotation processors and source levels 1.6 and 1.7</summary>
53
            <version major="1" minor="16"/>
65
            <version major="1" minor="16"/>
(-)a/java.freeform/manifest.mf (-1 / +1 lines)
Lines 1-6 Link Here
1
Manifest-Version: 1.0
1
Manifest-Version: 1.0
2
OpenIDE-Module: org.netbeans.modules.java.freeform/1
2
OpenIDE-Module: org.netbeans.modules.java.freeform/1
3
OpenIDE-Module-Specification-Version: 1.20
3
OpenIDE-Module-Specification-Version: 1.21
4
OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/java/freeform/Bundle.properties
4
OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/java/freeform/Bundle.properties
5
OpenIDE-Module-Layer: org/netbeans/modules/java/freeform/resources/layer.xml
5
OpenIDE-Module-Layer: org/netbeans/modules/java/freeform/resources/layer.xml
6
AutoUpdate-Show-In-Client: false
6
AutoUpdate-Show-In-Client: false
(-)a/java.freeform/src/org/netbeans/modules/java/freeform/AnnotationProcessingQueryImpl.java (-17 / +248 lines)
Lines 39-80 Link Here
39
39
40
package org.netbeans.modules.java.freeform;
40
package org.netbeans.modules.java.freeform;
41
41
42
import java.net.MalformedURLException;
42
import java.net.URL;
43
import java.net.URL;
43
import java.util.Collections;
44
import java.util.ArrayList;
45
import java.util.Collection;
44
import java.util.EnumSet;
46
import java.util.EnumSet;
47
import java.util.HashMap;
48
import java.util.List;
45
import java.util.Map;
49
import java.util.Map;
46
import java.util.Set;
50
import java.util.Set;
47
import javax.swing.event.ChangeListener;
51
import javax.swing.event.ChangeListener;
52
import org.netbeans.api.java.queries.AnnotationProcessingQuery;
48
import org.netbeans.api.java.queries.AnnotationProcessingQuery.Result;
53
import org.netbeans.api.java.queries.AnnotationProcessingQuery.Result;
49
import org.netbeans.api.java.queries.AnnotationProcessingQuery.Trigger;
54
import org.netbeans.api.java.queries.AnnotationProcessingQuery.Trigger;
55
import org.netbeans.api.project.ProjectManager;
50
import org.netbeans.spi.java.queries.AnnotationProcessingQueryImplementation;
56
import org.netbeans.spi.java.queries.AnnotationProcessingQueryImplementation;
57
import org.netbeans.spi.project.AuxiliaryConfiguration;
58
import org.netbeans.spi.project.support.ant.AntProjectEvent;
59
import org.netbeans.spi.project.support.ant.AntProjectHelper;
60
import org.netbeans.spi.project.support.ant.AntProjectListener;
61
import org.netbeans.spi.project.support.ant.PropertyEvaluator;
51
import org.openide.filesystems.FileObject;
62
import org.openide.filesystems.FileObject;
63
import org.openide.filesystems.FileUtil;
64
import org.openide.util.ChangeSupport;
65
import org.openide.util.Exceptions;
66
import org.openide.util.Mutex;
67
import org.openide.xml.XMLUtil;
68
import org.w3c.dom.Element;
52
69
53
/**
70
/**
54
 * Currently there is no special control over AP other than {@code <classpath mode="processorpath"/>}.
71
 * Freeform implementation of  AnnotationProcessingQueryImplementation
55
 */
72
 */
56
class AnnotationProcessingQueryImpl implements AnnotationProcessingQueryImplementation {
73
class AnnotationProcessingQueryImpl implements AnnotationProcessingQueryImplementation, AntProjectListener {
57
74
58
    public AnnotationProcessingQueryImpl() {}
75
    static final String EL_ANNOTATION_PROCESSING = "annotation-processing"; //NOI18N
76
    static final String EL_PROCESSOR_PATH = "processor-path"; //NOI18N
77
    private static final String EL_SCAN_TRIGGER = "scan-trigger";   //NOI18N
78
    private static final String EL_EDITOR_TRIGGER = "editor-trigger"; //NOI18N
79
    private static final String EL_PROCESSOR = "processor"; //NOI18N
80
    private static final String EL_PROCESSOR_OPTION = "processor-option";  //NOI18N
81
    private static final String EL_SOURCE_OUTPUT ="source-output"; //NOI18N
59
82
60
    public @Override Result getAnnotationProcessingOptions(FileObject file) {
83
    private final Object LCK = new Object();
61
        return new Result() {
84
62
            public @Override Set<? extends Trigger> annotationProcessingEnabled() {
85
    private final AntProjectHelper helper;
63
                return EnumSet.allOf(Trigger.class);
86
    private final PropertyEvaluator eval;
87
    private final AuxiliaryConfiguration aux;
88
    private Map<FileObject, R> results;
89
90
    @SuppressWarnings("LeakingThisInConstructor")
91
    public AnnotationProcessingQueryImpl(AntProjectHelper helper, PropertyEvaluator eval, final AuxiliaryConfiguration aux) {
92
        assert helper != null;
93
        assert eval != null;
94
        assert aux != null;
95
        this.helper = helper;
96
        this.eval = eval;
97
        this.aux = aux;
98
        this.helper.addAntProjectListener(this);
99
    }
100
101
    public @Override Result getAnnotationProcessingOptions(final FileObject file) {
102
        assert file != null;
103
        return ProjectManager.mutex().readAccess(new Mutex.Action<Result>() {
104
            public Result run() {
105
                synchronized (LCK) {
106
                    init(true);
107
                    assert results != null;
108
                    for (Map.Entry<FileObject,R> entry : results.entrySet()) {
109
                        FileObject fo = entry.getKey();
110
                        if (fo.equals(file) || FileUtil.isParentOf(fo, file)) {
111
                            return entry.getValue();
112
                        }
113
                    }
114
                    return null;
115
                }
64
            }
116
            }
65
            public @Override Iterable<? extends String> annotationProcessorsToRun() {
117
        });
66
                return null;
118
    }
119
120
    @Override
121
    public void configurationXmlChanged(AntProjectEvent ev) {
122
        init (false);
123
    }
124
125
    @Override
126
    public void propertiesChanged(AntProjectEvent ev) {
127
        //pass
128
    }
129
130
    private void init(final boolean force) {
131
        synchronized (LCK) {
132
            if (results == null) {
133
                if (force) {
134
                    results = new HashMap<FileObject, R>();
135
                } else {
136
                    return;
137
                }
67
            }
138
            }
68
            public @Override URL sourceOutputDirectory() {
139
            final Map<FileObject,R> added = new HashMap<FileObject, R>();
69
                return null;
140
            final Map<FileObject,R> retained = new HashMap<FileObject, R>();
141
142
            final Element java = aux.getConfigurationFragment(JavaProjectNature.EL_JAVA, JavaProjectNature.NS_JAVA_3, true);
143
            if (java != null) {
144
                for (Element compilationUnit : XMLUtil.findSubElements(java)) {
145
                    assert compilationUnit.getLocalName().equals("compilation-unit") : compilationUnit;
146
                    final List<FileObject> packageRoots = Classpaths.findPackageRoots(helper, eval, compilationUnit);
147
                    for (FileObject source : packageRoots) {
148
                        final R r = results.remove(source);
149
                        if (r == null) {
150
                            // Create a new result
151
                            added.put(source, new R(compilationUnit));
152
                        } else {
153
                            //Recalculate and fire
154
                            retained.put(source,r);
155
                            r.update(compilationUnit);
156
                        }
157
                    }
158
                }
70
            }
159
            }
71
            public @Override Map<? extends String, ? extends String> processorOptions() {
160
72
                return Collections.emptyMap();
161
            //Invalidate results for remvoed roots
162
            for (R r : results.values()) {
163
                r.update(null);
73
            }
164
            }
74
            public @Override void addChangeListener(ChangeListener l) {}
165
            results.putAll(added);
75
            public @Override void removeChangeListener(ChangeListener l) {}
166
            results.putAll(retained);
167
        }
168
    }
76
169
77
        };
170
171
172
    private class R implements AnnotationProcessingQuery.Result {
173
174
        private final ChangeSupport changeSupport = new ChangeSupport(this);
175
        private volatile Element ap;
176
        private volatile Set<Trigger> triggerCache;
177
        private volatile Map<String,String> optionsCache;
178
        private volatile Collection<String> processorsCache;
179
        private volatile List<URL> sourceOutputCache;
180
181
        private R(final Element cu) {
182
            assert cu != null;
183
            this.ap = findAP(cu);
184
        }
185
186
        public @Override Set<? extends Trigger> annotationProcessingEnabled() {
187
            Set<Trigger> result = triggerCache;
188
            if (result != null) {
189
                return result;
190
            }
191
            result = EnumSet.noneOf(Trigger.class);
192
            if (ap != null) {
193
                for (Element e : XMLUtil.findSubElements(ap)) {
194
                    if (e.getLocalName().equals(EL_SCAN_TRIGGER)) {
195
                        result.add(Trigger.ON_SCAN);
196
                    } else if (e.getLocalName().equals(EL_EDITOR_TRIGGER)) {
197
                        result.add(Trigger.IN_EDITOR);
198
                    }
199
                }
200
            }
201
            synchronized (LCK) {
202
                if (triggerCache == null) {
203
                    triggerCache = result;
204
                }
205
            }
206
            return result;
207
        }
208
209
        public @Override Iterable<? extends String> annotationProcessorsToRun() {
210
            Collection<String> result = processorsCache;
211
            if (result != null) {
212
                return result.isEmpty() ? null : result;
213
            }
214
            result = new ArrayList<String>();
215
            if (ap != null) {
216
                for (Element e : XMLUtil.findSubElements(ap)) {
217
                    if (e.getLocalName().equals(EL_PROCESSOR)) {
218
                        result.add(eval.evaluate(XMLUtil.findText(e)));
219
                    }
220
                }
221
            }
222
            synchronized (LCK) {
223
                if (processorsCache == null) {
224
                    processorsCache = result;
225
                }
226
            }
227
            return result.isEmpty() ? null : result;
228
        }
229
230
231
        public @Override URL sourceOutputDirectory() {
232
            List<URL> result = sourceOutputCache;
233
            if (result != null) {
234
                return result.get(0);
235
            }
236
            result = new ArrayList<URL>(1);
237
            if (ap != null) {
238
                for (Element e : XMLUtil.findSubElements(ap)) {
239
                    if (e.getLocalName().equals(EL_SOURCE_OUTPUT)) {
240
                        try {
241
                            final String path = eval.evaluate(XMLUtil.findText(e));
242
                            result.add(helper.resolveFile(path).toURI().toURL());
243
                        } catch (MalformedURLException ex) {
244
                            Exceptions.printStackTrace(ex);
245
                        }
246
                        break;
247
                    }
248
                }
249
            }
250
            synchronized (LCK) {
251
                if (sourceOutputCache == null) {
252
                    sourceOutputCache = result;
253
                }
254
            }
255
            return result.get(0);
256
        }
257
258
        public @Override Map<? extends String, ? extends String> processorOptions() {
259
            Map<String,String> result = optionsCache;
260
            if (result != null) {
261
                return result;
262
            }
263
            result = new HashMap<String, String>();
264
            if (ap != null) {
265
                for (Element e : XMLUtil.findSubElements(ap)) {
266
                    if (e.getLocalName().equals(EL_PROCESSOR_OPTION)) {
267
                        final Element keyElement = XMLUtil.findElement(e, "key", JavaProjectNature.NS_JAVA_3);  //NOI18N
268
                        final Element valueElement = XMLUtil.findElement(e, "value", JavaProjectNature.NS_JAVA_3);  //NOI18N
269
                        if (keyElement == null || valueElement == null) {
270
                            continue;
271
                        }
272
                        final String key = XMLUtil.findText(keyElement);
273
                        final String value = XMLUtil.findText(valueElement);
274
                        result.put(key, eval.evaluate(value));
275
                    }
276
                }
277
            }
278
            synchronized (LCK) {
279
                if (optionsCache == null) {
280
                    optionsCache = result;
281
                }
282
            }
283
            return result;
284
        }
285
286
        public @Override void addChangeListener(ChangeListener l) {
287
            changeSupport.addChangeListener(l);
288
        }
289
290
        public @Override void removeChangeListener(ChangeListener l) {
291
            changeSupport.removeChangeListener(l);
292
        }
293
294
        private void update (final Element cu) {
295
            synchronized(LCK) {
296
                triggerCache = null;
297
                optionsCache = null;
298
                processorsCache = null;
299
                sourceOutputCache = null;
300
                ap = findAP(cu);
301
            }
302
            this.changeSupport.fireChange();
303
        }
304
305
        private Element findAP(final Element cu) {
306
            return cu == null ? null : XMLUtil.findElement(cu, AnnotationProcessingQueryImpl.EL_ANNOTATION_PROCESSING, JavaProjectNature.NS_JAVA_3);
307
        }
308
78
    }
309
    }
79
310
80
}
311
}
(-)a/java.freeform/src/org/netbeans/modules/java/freeform/Classpaths.java (-4 / +6 lines)
Lines 485-495 Link Here
485
        }
485
        }
486
        return urls;
486
        return urls;
487
    }
487
    }
488
    
488
489
    private List<URL> createProcessorClasspath(Element compilationUnitEl) {
489
    private List<URL> createProcessorClasspath(Element compilationUnitEl) {
490
        for (Element e : XMLUtil.findSubElements(compilationUnitEl)) {
490
        final Element ap = XMLUtil.findElement(compilationUnitEl, AnnotationProcessingQueryImpl.EL_ANNOTATION_PROCESSING, JavaProjectNature.NS_JAVA_3);
491
            if (e.getLocalName().equals("classpath") && e.getAttribute("mode").equals("processor")) { // NOI18N
491
        if (ap != null) {
492
                return createClasspath(e);
492
            final Element path = XMLUtil.findElement(ap, AnnotationProcessingQueryImpl.EL_PROCESSOR_PATH, JavaProjectNature.NS_JAVA_3);
493
            if (path != null) {
494
                return createClasspath(path);
493
            }
495
            }
494
        }
496
        }
495
        // None specified; assume it is the same as the compile classpath.
497
        // None specified; assume it is the same as the compile classpath.
(-)a/java.freeform/src/org/netbeans/modules/java/freeform/LookupProviderImpl.java (-1 / +1 lines)
Lines 87-93 Link Here
87
            cp, // ClassPathProvider
87
            cp, // ClassPathProvider
88
            new SourceLevelQueryImpl(projectHelper, projectEvaluator, aux), // SourceLevelQueryImplementation
88
            new SourceLevelQueryImpl(projectHelper, projectEvaluator, aux), // SourceLevelQueryImplementation
89
            new SourceForBinaryQueryImpl(projectHelper, projectEvaluator, aux), // SourceForBinaryQueryImplementation
89
            new SourceForBinaryQueryImpl(projectHelper, projectEvaluator, aux), // SourceForBinaryQueryImplementation
90
            new AnnotationProcessingQueryImpl(),
90
            new AnnotationProcessingQueryImpl(projectHelper, projectEvaluator, aux),
91
            new OpenHook(project, cp), // ProjectOpenedHook
91
            new OpenHook(project, cp), // ProjectOpenedHook
92
            new TestQuery(projectHelper, projectEvaluator, aux), // MultipleRootsUnitTestForSourceQueryImplementation
92
            new TestQuery(projectHelper, projectEvaluator, aux), // MultipleRootsUnitTestForSourceQueryImplementation
93
            new JavadocQuery(projectHelper, projectEvaluator, aux), // JavadocForBinaryQueryImplementation
93
            new JavadocQuery(projectHelper, projectEvaluator, aux), // JavadocForBinaryQueryImplementation
(-)a/java.freeform/src/org/netbeans/modules/java/freeform/resources/freeform-project-java-3.xsd (-1 / +21 lines)
Lines 74-80 Link Here
74
                                        <xsd:enumeration value="boot"/>
74
                                        <xsd:enumeration value="boot"/>
75
                                        <xsd:enumeration value="compile"/>
75
                                        <xsd:enumeration value="compile"/>
76
                                        <xsd:enumeration value="execute"/>
76
                                        <xsd:enumeration value="execute"/>
77
                                        <xsd:enumeration value="processor"/>
78
                                    </xsd:restriction>
77
                                    </xsd:restriction>
79
                                </xsd:simpleType>
78
                                </xsd:simpleType>
80
                            </xsd:attribute>
79
                            </xsd:attribute>
Lines 95-100 Link Here
95
                    </xsd:restriction>
94
                    </xsd:restriction>
96
                </xsd:simpleType>
95
                </xsd:simpleType>
97
            </xsd:element>
96
            </xsd:element>
97
            <xsd:element name="annotation-processing" minOccurs="0">
98
                <xsd:complexType>
99
                    <xsd:sequence>
100
                        <xsd:element name="scan-trigger" minOccurs="0"><xsd:complexType/></xsd:element>
101
                        <xsd:element name="editor-trigger" minOccurs="0"><xsd:complexType/></xsd:element>
102
                        <xsd:element name="source-output" minOccurs="0" type="substitutable-text"/>
103
                        <xsd:element name="processor-path" minOccurs="0" type="substitutable-text"/>
104
                        <xsd:element name="processor" minOccurs="0" maxOccurs="unbounded" type="substitutable-text"/>
105
                        <xsd:element name="processor-option" minOccurs="0" maxOccurs="unbounded" type="processor-option"/>
106
                    </xsd:sequence>
107
                </xsd:complexType>
108
            </xsd:element>
98
        </xsd:sequence>
109
        </xsd:sequence>
99
    </xsd:complexType>
110
    </xsd:complexType>
100
111
Lines 105-108 Link Here
105
            <!-- XXX limit by regexp, perhaps -->
116
            <!-- XXX limit by regexp, perhaps -->
106
        </xsd:restriction>
117
        </xsd:restriction>
107
    </xsd:simpleType>
118
    </xsd:simpleType>
119
120
    <xsd:complexType name="processor-option">
121
        <xsd:sequence>
122
            <xsd:element name="key" type="xsd:string"/>     <!-- xsd:token???? -->
123
            <xsd:element name="value" type="substitutable-text"/>
124
        </xsd:sequence>
125
    </xsd:complexType>
126
127
108
</xsd:schema>
128
</xsd:schema>

Return to bug 185457