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 270094
Collapse All | Expand All

(-)a/java.api.common/nbproject/project.xml (-1 / +1 lines)
Lines 163-169 Link Here
163
                    <compile-dependency/>
163
                    <compile-dependency/>
164
                    <run-dependency>
164
                    <run-dependency>
165
                        <release-version>1</release-version>
165
                        <release-version>1</release-version>
166
                        <specification-version>1.66</specification-version>
166
                        <specification-version>1.70</specification-version>
167
                    </run-dependency>
167
                    </run-dependency>
168
                </dependency>
168
                </dependency>
169
                <dependency>
169
                <dependency>
(-)a/java.api.common/src/org/netbeans/modules/java/api/common/classpath/ClassPathModifier.java (+1 lines)
Lines 117-122 Link Here
117
            ClassPathSupport.ENDORSED,
117
            ClassPathSupport.ENDORSED,
118
            JavaClassPathConstants.PROCESSOR_PATH,
118
            JavaClassPathConstants.PROCESSOR_PATH,
119
            JavaClassPathConstants.MODULE_COMPILE_PATH,
119
            JavaClassPathConstants.MODULE_COMPILE_PATH,
120
            JavaClassPathConstants.MODULE_EXECUTE_PATH,
120
        };
121
        };
121
    }
122
    }
122
123
(-)a/java.api.common/src/org/netbeans/modules/java/api/common/classpath/ClassPathProviderImpl.java (-28 / +26 lines)
Lines 1324-1363 Link Here
1324
        FileObject[] path = getPrimarySrcPath();
1324
        FileObject[] path = getPrimarySrcPath();
1325
        for (int i=0; i<path.length; i++) {
1325
        for (int i=0; i<path.length; i++) {
1326
            if (root.equals(path[i])) {
1326
            if (root.equals(path[i])) {
1327
                if (ClassPath.COMPILE.equals(type)) {
1327
                switch (type) {
1328
                    return javacClasspath;
1328
                    case ClassPath.COMPILE:
1329
                }
1329
                        return javacClasspath;
1330
                else if (ClassPath.EXECUTE.equals(type)) {
1330
                    case ClassPath.EXECUTE:
1331
                    return runClasspath;
1331
                        return runClasspath;
1332
                }
1332
                    case JavaClassPathConstants.PROCESSOR_PATH:
1333
                else if (JavaClassPathConstants.PROCESSOR_PATH.equals(type)) {
1333
                        return processorClasspath;
1334
                    return processorClasspath;
1334
                    case JavaClassPathConstants.MODULE_COMPILE_PATH:
1335
                }
1335
                        return modulePath;
1336
                else if (JavaClassPathConstants.MODULE_COMPILE_PATH.equals(type)) {
1336
                    case JavaClassPathConstants.MODULE_EXECUTE_PATH:
1337
                    return modulePath;
1337
                        return moduleExecutePath;
1338
                }
1338
                    default:
1339
                else {
1339
                        return null;
1340
                    return null;
1341
                }
1340
                }
1342
            }
1341
            }
1343
        }
1342
        }
1344
        path = getTestSrcDir();
1343
        path = getTestSrcDir();
1345
        for (int i=0; i<path.length; i++) {
1344
        for (int i=0; i<path.length; i++) {
1346
            if (root.equals(path[i])) {
1345
            if (root.equals(path[i])) {
1347
                if (ClassPath.COMPILE.equals(type)) {
1346
                switch (type) {
1348
                    return javacTestClasspath;
1347
                    case ClassPath.COMPILE:
1349
                }
1348
                        return javacTestClasspath;
1350
                else if (ClassPath.EXECUTE.equals(type)) {
1349
                    case ClassPath.EXECUTE:
1351
                    return runTestClasspath;
1350
                        return runTestClasspath;
1352
                }
1351
                    case JavaClassPathConstants.PROCESSOR_PATH:
1353
                else if (JavaClassPathConstants.PROCESSOR_PATH.equals(type)) {
1352
                        return processorTestClasspath;
1354
                    return processorTestClasspath;
1353
                    case JavaClassPathConstants.MODULE_COMPILE_PATH:
1355
                }
1354
                        return testModulePath;
1356
                else if (JavaClassPathConstants.MODULE_COMPILE_PATH.equals(type)) {
1355
                    case JavaClassPathConstants.MODULE_EXECUTE_PATH:
1357
                    return testModulePath;
1356
                        return moduleExecutePath;
1358
                }
1357
                    default:
1359
                else {
1358
                        return null;
1360
                    return null;
1361
                }
1359
                }
1362
            }
1360
            }
1363
        }
1361
        }
(-)a/java.api.common/src/org/netbeans/modules/java/api/common/impl/DefaultProjectModulesModifier.java (+314 lines)
Line 0 Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright (c) 2017 Oracle and/or its affiliates. All rights reserved.
5
 *
6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7
 * Other names may be trademarks of their respective owners.
8
 *
9
 * The contents of this file are subject to the terms of either the GNU
10
 * General Public License Version 2 only ("GPL") or the Common
11
 * Development and Distribution License("CDDL") (collectively, the
12
 * "License"). You may not use this file except in compliance with the
13
 * License. You can obtain a copy of the License at
14
 * http://www.netbeans.org/cddl-gplv2.html
15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
16
 * specific language governing permissions and limitations under the
17
 * License.  When distributing the software, include this License Header
18
 * Notice in each file and include the License file at
19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
20
 * particular file as subject to the "Classpath" exception as provided
21
 * by Oracle in the GPL Version 2 section of the License file that
22
 * accompanied this code. If applicable, add the following below the
23
 * License Header, with the fields enclosed by brackets [] replaced by
24
 * your own identifying information:
25
 * "Portions Copyrighted [year] [name of copyright owner]"
26
 *
27
 * If you wish your version of this file to be governed by only the CDDL
28
 * or only the GPL Version 2, indicate your decision by adding
29
 * "[Contributor] elects to include this software in this distribution
30
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
31
 * single choice of license, a recipient has the option to distribute
32
 * your version of this file under either the CDDL, the GPL Version 2 or
33
 * to extend the choice of license to its licensees as provided above.
34
 * However, if you add GPL Version 2 code and therefore, elected the GPL
35
 * Version 2 license, then the option applies only if the new code is
36
 * made subject to such option by the copyright holder.
37
 *
38
 * Contributor(s):
39
 */
40
package org.netbeans.modules.java.api.common.impl;
41
42
import com.sun.source.tree.CompilationUnitTree;
43
import com.sun.source.tree.DirectiveTree;
44
import com.sun.source.tree.ModuleTree;
45
import com.sun.source.tree.RequiresTree;
46
import com.sun.source.util.TreeScanner;
47
import java.io.IOException;
48
import java.net.URL;
49
import java.util.ArrayList;
50
import java.util.Collection;
51
import java.util.HashSet;
52
import java.util.List;
53
import java.util.Set;
54
import java.util.stream.Collectors;
55
import org.netbeans.api.actions.Savable;
56
import org.netbeans.api.annotations.common.CheckForNull;
57
import org.netbeans.api.annotations.common.NonNull;
58
import org.netbeans.api.java.classpath.ClassPath;
59
import org.netbeans.api.java.classpath.JavaClassPathConstants;
60
import org.netbeans.api.java.queries.SourceLevelQuery;
61
import org.netbeans.api.java.source.JavaSource;
62
import org.netbeans.api.java.source.SourceUtils;
63
import org.netbeans.api.java.source.TreeMaker;
64
import org.netbeans.api.project.FileOwnerQuery;
65
import org.netbeans.api.project.Project;
66
import org.netbeans.spi.java.project.classpath.ProjectModulesModifier;
67
import org.openide.filesystems.FileObject;
68
import org.openide.modules.SpecificationVersion;
69
import org.openide.util.Exceptions;
70
import org.openide.util.lookup.ServiceProvider;
71
72
/**
73
 *
74
 * @author sdedic
75
 */
76
@ServiceProvider(service = ProjectModulesModifier.class)
77
public class DefaultProjectModulesModifier implements ProjectModulesModifier {
78
    @Override
79
    public String provideModularClasspath(FileObject projectArtifact, String classPathType) {
80
        assert projectArtifact != null;
81
        assert classPathType != null;
82
        
83
        Project p = FileOwnerQuery.getOwner(projectArtifact);
84
        if (p == null) {
85
            return null;
86
        }
87
        ProjectModulesModifier delegate = p.getLookup().lookup(ProjectModulesModifier.class);
88
        if (delegate != null) {
89
            return delegate.provideModularClasspath(projectArtifact, classPathType);
90
        }
91
        if (findModuleInfo(projectArtifact) == null) {
92
            return null;
93
        }
94
        switch (classPathType) {
95
            case ClassPath.COMPILE:
96
                return JavaClassPathConstants.MODULE_COMPILE_PATH;
97
            case ClassPath.EXECUTE:
98
                return JavaClassPathConstants.MODULE_EXECUTE_PATH;
99
                
100
            default:
101
                return null;
102
        }
103
    }
104
105
    @Override
106
    public boolean addRequiredModules(String originalPathType, FileObject projectArtifact, Collection<URL> moduleNames) throws IOException {
107
        assert projectArtifact != null;
108
        assert originalPathType != null;
109
        
110
        Project p = FileOwnerQuery.getOwner(projectArtifact);
111
        if (p == null) {
112
            return false;
113
        }
114
        FileObject modInfo = findModuleInfo(projectArtifact);
115
        if (modInfo == null) {
116
            return false;
117
        }
118
        ProjectModulesModifier delegate = p.getLookup().lookup(ProjectModulesModifier.class);
119
        if (delegate != null) {
120
            return delegate.addRequiredModules(originalPathType, projectArtifact, moduleNames);
121
        }
122
123
        switch (originalPathType) {
124
            case ClassPath.COMPILE:
125
            case ClassPath.EXECUTE:
126
            case JavaClassPathConstants.MODULE_COMPILE_PATH:
127
            case JavaClassPathConstants.MODULE_EXECUTE_PATH:
128
                return extendModuleInfo(modInfo, moduleNames);
129
                
130
            default:
131
                return false;
132
        }
133
    }
134
135
    @Override
136
    public boolean removeRequiredModules(String originalPathType, FileObject projectArtifact, Collection<URL> moduleNames) throws IOException {
137
        assert projectArtifact != null;
138
        assert originalPathType != null;
139
        
140
        Project p = FileOwnerQuery.getOwner(projectArtifact);
141
        if (p == null) {
142
            return false;
143
        }
144
        FileObject modInfo = findModuleInfo(projectArtifact);
145
        if (modInfo == null) {
146
            return false;
147
        }
148
        ProjectModulesModifier delegate = p.getLookup().lookup(ProjectModulesModifier.class);
149
        if (delegate != null) {
150
            return delegate.removeRequiredModules(originalPathType, projectArtifact, moduleNames);
151
        }
152
        switch (originalPathType) {
153
            case ClassPath.COMPILE:
154
            case ClassPath.EXECUTE:
155
            case JavaClassPathConstants.MODULE_COMPILE_PATH:
156
            case JavaClassPathConstants.MODULE_EXECUTE_PATH:
157
                return removeRequiredModuleArtifacts(modInfo, moduleNames);
158
                
159
            default:
160
                return false;
161
        }
162
    }
163
    
164
    private static final SpecificationVersion JDK9_SPEC = new SpecificationVersion("9");
165
166
    @CheckForNull
167
    private static FileObject findModuleInfo(@NonNull final FileObject artifact) {
168
        if (JDK9_SPEC.compareTo(new SpecificationVersion(SourceLevelQuery.getSourceLevel(artifact))) < 0) {
169
            return null;
170
        }
171
        ClassPath cp = ClassPath.getClassPath(artifact, ClassPath.SOURCE);
172
        return cp == null ? null : cp.findResource("module-info.java");   //NOI18N
173
    }
174
    
175
    public static boolean extendModuleInfo(
176
            @NonNull final FileObject info,
177
            @NonNull final  Collection<URL> modules) throws IOException {
178
        if (info == null || modules.isEmpty()) {
179
            return false;
180
        }
181
        final Collection<String> moduleNames = modules.stream()
182
                .map((url) -> SourceUtils.getModuleName(url, true))
183
                .filter((name) -> name != null)
184
                .collect(Collectors.toList());
185
        if (moduleNames.isEmpty()) {
186
            return false;
187
        }
188
        final JavaSource js = JavaSource.forFileObject(info);
189
        if (js == null) {
190
            return false;
191
        }
192
        boolean[] modified = new boolean[1];
193
        js.runModificationTask((wc) -> {
194
            wc.toPhase(JavaSource.Phase.RESOLVED);
195
            final CompilationUnitTree cu = wc.getCompilationUnit();
196
            final Set<String> knownModules = new HashSet<>();
197
            final ModuleTree[] module = new ModuleTree[1];
198
            final RequiresTree[] lastRequires = new RequiresTree[1];
199
            cu.accept(new TreeScanner<Void, Void>() {
200
                        @Override
201
                        public Void visitModule(ModuleTree m, Void p) {
202
                            module[0] = m;
203
                            return super.visitModule(m, p);
204
                        }
205
                        @Override
206
                        public Void visitRequires(RequiresTree r, Void p) {
207
                            lastRequires[0] = r;
208
                            knownModules.add(r.getModuleName().toString());
209
                            return super.visitRequires(r, p);
210
                        }
211
                    },
212
                    null);
213
            if (module[0] != null) {
214
                moduleNames.removeAll(knownModules);
215
                modified[0] = !moduleNames.isEmpty();
216
                final TreeMaker tm = wc.getTreeMaker();
217
                final List<RequiresTree> newRequires = moduleNames.stream()
218
                        .map((name) -> tm.Requires(false, false, tm.QualIdent(name)))
219
                        .collect(Collectors.toList());
220
221
                final List<DirectiveTree> newDirectives = new ArrayList<>(
222
                        module[0].getDirectives().size() + newRequires.size());
223
                if (lastRequires[0] == null) {
224
                    newDirectives.addAll(newRequires);
225
                }
226
                for (DirectiveTree dt : module[0].getDirectives()) {
227
                    newDirectives.add(dt);
228
                    if (dt == lastRequires[0]) {
229
                        newDirectives.addAll(newRequires);
230
                    }
231
                }
232
                final ModuleTree newModule = tm.Module(
233
                        tm.Modifiers(0, module[0].getAnnotations()),
234
                        module[0].getModuleType(),
235
                        module[0].getName(),
236
                        newDirectives);
237
                wc.rewrite(module[0], newModule);
238
            }                    
239
        })
240
        .commit();
241
        save(info);
242
        return modified[0];
243
    }
244
    
245
    public static boolean removeRequiredModuleArtifacts(FileObject moduleInfo, Collection<URL> modules) {
246
        return removeRequiredModules(moduleInfo, 
247
            modules.stream()
248
                .map((url) -> SourceUtils.getModuleName(url, true))
249
                .filter((name) -> name != null)
250
                .collect(Collectors.toSet()
251
        ));
252
    }
253
    
254
    public static boolean removeRequiredModules(FileObject moduleInfo, Collection<String> modules) {
255
        if (moduleInfo == null || modules.isEmpty()) {
256
            return false;
257
        }
258
        final boolean[] modified = new boolean[1];
259
        try {
260
            final JavaSource js = JavaSource.forFileObject(moduleInfo);
261
            if (js != null) {
262
                js.runModificationTask((wc) -> {
263
                    wc.toPhase(JavaSource.Phase.PARSED);
264
                    final CompilationUnitTree cu = wc.getCompilationUnit();
265
                    final Set<DirectiveTree> toRemove = new HashSet<>();
266
                    final ModuleTree[] module = new ModuleTree[1];
267
                    cu.accept(
268
                            new TreeScanner<Void, Set<DirectiveTree>>() {
269
                                @Override
270
                                public Void visitModule(final ModuleTree node, Set<DirectiveTree> param) {
271
                                    module[0] = node;
272
                                    return super.visitModule(node, param);
273
                                }
274
                                @Override
275
                                public Void visitRequires(final RequiresTree node, final Set<DirectiveTree> param) {
276
                                    final String fqn = node.getModuleName().toString();
277
                                    if (modules.contains(fqn)) {
278
                                        param.add(node);
279
                                    }
280
                                    return super.visitRequires(node, param);
281
                                }
282
                            },
283
                            toRemove);
284
                    if (!toRemove.isEmpty()) {
285
                        modified[0] = true;
286
                        final List<DirectiveTree> newDirectives = new ArrayList<>(module[0].getDirectives().size());
287
                        for (DirectiveTree dt : module[0].getDirectives()) {
288
                            if (!toRemove.contains(dt)) {
289
                                newDirectives.add(dt);
290
                            }
291
                        }
292
                        final ModuleTree newModule = wc.getTreeMaker().Module(
293
                                wc.getTreeMaker().Modifiers(0, module[0].getAnnotations()),
294
                                module[0].getModuleType(),
295
                                module[0].getName(),
296
                                newDirectives);
297
                        wc.rewrite(module[0], newModule);
298
                    }
299
                }).commit();
300
                save(moduleInfo);
301
            }
302
        } catch (IOException ioe) {
303
            Exceptions.printStackTrace(ioe);
304
        }
305
        return modified[0];
306
    }
307
    
308
    private static void save(@NonNull final FileObject file) throws IOException {
309
        final Savable save = file.getLookup().lookup(Savable.class);
310
        if (save != null) {
311
            save.save();
312
        }
313
    }
314
}
(-)a/java.api.common/src/org/netbeans/modules/java/api/common/project/ui/LibrariesNode.java (-127 / +6 lines)
Lines 128-133 Link Here
128
import org.netbeans.modules.java.api.common.classpath.ClassPathModifier;
128
import org.netbeans.modules.java.api.common.classpath.ClassPathModifier;
129
import org.netbeans.modules.java.api.common.classpath.ClassPathSupport;
129
import org.netbeans.modules.java.api.common.classpath.ClassPathSupport;
130
import org.netbeans.modules.java.api.common.SourceRoots;
130
import org.netbeans.modules.java.api.common.SourceRoots;
131
import org.netbeans.modules.java.api.common.impl.DefaultProjectModulesModifier;
131
import org.netbeans.modules.java.api.common.util.CommonModuleUtils;
132
import org.netbeans.modules.java.api.common.util.CommonModuleUtils;
132
import org.netbeans.modules.java.api.common.project.ui.customizer.AntArtifactItem;
133
import org.netbeans.modules.java.api.common.project.ui.customizer.AntArtifactItem;
133
import org.netbeans.modules.java.api.common.project.ui.customizer.EditMediator;
134
import org.netbeans.modules.java.api.common.project.ui.customizer.EditMediator;
Lines 1187-1239 Link Here
1187
                                    .map((url) -> SourceUtils.getModuleName(url, true))
1188
                                    .map((url) -> SourceUtils.getModuleName(url, true))
1188
                                    .filter((name) -> name != null)
1189
                                    .filter((name) -> name != null)
1189
                                    .collect(Collectors.toSet());
1190
                                    .collect(Collectors.toSet());
1190
                            if (!modules.isEmpty()) {
1191
                            DefaultProjectModulesModifier.removeRequiredModules(moduleInfo, modules);
1191
                                try {
1192
                                    final JavaSource js = JavaSource.forFileObject(moduleInfo);
1193
                                    if (js != null) {
1194
                                        js.runModificationTask((wc) -> {
1195
                                            wc.toPhase(JavaSource.Phase.PARSED);
1196
                                            final CompilationUnitTree cu = wc.getCompilationUnit();
1197
                                            final Set<DirectiveTree> toRemove = new HashSet<>();
1198
                                            final ModuleTree[] module = new ModuleTree[1];
1199
                                            cu.accept(
1200
                                                    new TreeScanner<Void, Set<DirectiveTree>>() {
1201
                                                        @Override
1202
                                                        public Void visitModule(final ModuleTree node, Set<DirectiveTree> param) {
1203
                                                            module[0] = node;
1204
                                                            return super.visitModule(node, param);
1205
                                                        }
1206
                                                        @Override
1207
                                                        public Void visitRequires(final RequiresTree node, final Set<DirectiveTree> param) {
1208
                                                            final String fqn = node.getModuleName().toString();
1209
                                                            if (modules.contains(fqn)) {
1210
                                                                param.add(node);
1211
                                                            }
1212
                                                            return super.visitRequires(node, param);
1213
                                                        }
1214
                                                    },
1215
                                                    toRemove);
1216
                                            if (!toRemove.isEmpty()) {
1217
                                                final List<DirectiveTree> newDirectives = new ArrayList<>(module[0].getDirectives().size());
1218
                                                for (DirectiveTree dt : module[0].getDirectives()) {
1219
                                                    if (!toRemove.contains(dt)) {
1220
                                                        newDirectives.add(dt);
1221
                                                    }
1222
                                                }
1223
                                                final ModuleTree newModule = wc.getTreeMaker().Module(
1224
                                                        wc.getTreeMaker().Modifiers(0, module[0].getAnnotations()),
1225
                                                        module[0].getModuleType(),
1226
                                                        module[0].getName(),
1227
                                                        newDirectives);
1228
                                                wc.rewrite(module[0], newModule);
1229
                                            }
1230
                                        }).commit();
1231
                                        save(moduleInfo);
1232
                                    }
1233
                                } catch (IOException ioe) {
1234
                                    Exceptions.printStackTrace(ioe);
1235
                                }
1236
                            }
1237
                        }
1192
                        }
1238
                    }
1193
                    }
1239
                }
1194
                }
Lines 1483-1489 Link Here
1483
            }
1438
            }
1484
        }
1439
        }
1485
    }
1440
    }
1486
1441
    
1487
    private static class AddProjectAction extends AbstractAction {
1442
    private static class AddProjectAction extends AbstractAction {
1488
1443
1489
        private final Project project;
1444
        private final Project project;
Lines 1529-1537 Link Here
1529
                        ClassPath.COMPILE;
1484
                        ClassPath.COMPILE;
1530
                ProjectClassPathModifier.addAntArtifacts(artifacts, artifactURIs,
1485
                ProjectClassPathModifier.addAntArtifacts(artifacts, artifactURIs,
1531
                        projectSourcesArtifact, cpType);
1486
                        projectSourcesArtifact, cpType);
1532
                if (moduleInfo != null) {
1487
                DefaultProjectModulesModifier.extendModuleInfo(moduleInfo, Arrays.asList(toURLs(artifactItems)));
1533
                    extendModuleInfo(moduleInfo, toURLs(artifactItems));
1534
                }
1535
            } catch (IOException ioe) {
1488
            } catch (IOException ioe) {
1536
                Exceptions.printStackTrace(ioe);
1489
                Exceptions.printStackTrace(ioe);
1537
            } catch (UnsupportedOperationException e) {
1490
            } catch (UnsupportedOperationException e) {
Lines 1582-1590 Link Here
1582
                        ClassPath.COMPILE;
1535
                        ClassPath.COMPILE;
1583
                ProjectClassPathModifier.addLibraries(libraries,
1536
                ProjectClassPathModifier.addLibraries(libraries,
1584
                        projectSourcesArtifact, cpType);
1537
                        projectSourcesArtifact, cpType);
1585
                if (moduleInfo != null) {
1538
                DefaultProjectModulesModifier.extendModuleInfo(moduleInfo, Arrays.asList(toURLs(libraries)));
1586
                    extendModuleInfo(moduleInfo, toURLs(libraries));
1587
                }
1588
            } catch (IOException ioe) {
1539
            } catch (IOException ioe) {
1589
                Exceptions.printStackTrace(ioe);
1540
                Exceptions.printStackTrace(ioe);
1590
            } catch (UnsupportedOperationException e) {
1541
            } catch (UnsupportedOperationException e) {
Lines 1731-1739 Link Here
1731
                        findSourceGroup(projectSourcesArtifact, modifierImpl),
1682
                        findSourceGroup(projectSourcesArtifact, modifierImpl),
1732
                        cpType,
1683
                        cpType,
1733
                        ClassPathModifier.ADD_NO_HEURISTICS);
1684
                        ClassPathModifier.ADD_NO_HEURISTICS);
1734
                    if (moduleInfo != null) {
1685
                    DefaultProjectModulesModifier.extendModuleInfo(moduleInfo, toAddURLs);
1735
                        extendModuleInfo(moduleInfo, toAddURLs.toArray(new URL[toAddURLs.size()]));
1736
                    }
1737
                }
1686
                }
1738
            } catch (IOException ioe) {
1687
            } catch (IOException ioe) {
1739
                Exceptions.printStackTrace(ioe);
1688
                Exceptions.printStackTrace(ioe);
Lines 1783-1858 Link Here
1783
        return res.toArray(new URL[res.size()]);
1732
        return res.toArray(new URL[res.size()]);
1784
    }
1733
    }
1785
    
1734
    
1786
    private static void extendModuleInfo(
1787
            @NonNull final FileObject info,
1788
            @NonNull final  URL... modules) throws IOException {
1789
        final Collection<String> moduleNames = Arrays.stream(modules)
1790
                .map((url) -> SourceUtils.getModuleName(url, true))
1791
                .filter((name) -> name != null)
1792
                .collect(Collectors.toList());
1793
        if (!moduleNames.isEmpty()) {
1794
            final JavaSource js = JavaSource.forFileObject(info);
1795
            if (js != null) {
1796
                js.runModificationTask((wc) -> {
1797
                    wc.toPhase(JavaSource.Phase.RESOLVED);
1798
                    final CompilationUnitTree cu = wc.getCompilationUnit();
1799
                    final Set<String> knownModules = new HashSet<>();
1800
                    final ModuleTree[] module = new ModuleTree[1];
1801
                    final RequiresTree[] lastRequires = new RequiresTree[1];
1802
                    cu.accept(new TreeScanner<Void, Void>() {
1803
                                @Override
1804
                                public Void visitModule(ModuleTree m, Void p) {
1805
                                    module[0] = m;
1806
                                    return super.visitModule(m, p);
1807
                                }
1808
                                @Override
1809
                                public Void visitRequires(RequiresTree r, Void p) {
1810
                                    lastRequires[0] = r;
1811
                                    knownModules.add(r.getModuleName().toString());
1812
                                    return super.visitRequires(r, p);
1813
                                }
1814
                            },
1815
                            null);
1816
                    if (module[0] != null) {
1817
                        moduleNames.removeAll(knownModules);
1818
                        final TreeMaker tm = wc.getTreeMaker();
1819
                        final List<RequiresTree> newRequires = moduleNames.stream()
1820
                                .map((name) -> tm.Requires(false, false, tm.QualIdent(name)))
1821
                                .collect(Collectors.toList());
1822
1823
                        final List<DirectiveTree> newDirectives = new ArrayList<>(
1824
                                module[0].getDirectives().size() + newRequires.size());
1825
                        if (lastRequires[0] == null) {
1826
                            newDirectives.addAll(newRequires);
1827
                        }
1828
                        for (DirectiveTree dt : module[0].getDirectives()) {
1829
                            newDirectives.add(dt);
1830
                            if (dt == lastRequires[0]) {
1831
                                newDirectives.addAll(newRequires);
1832
                            }
1833
                        }
1834
                        final ModuleTree newModule = tm.Module(
1835
                                tm.Modifiers(0, module[0].getAnnotations()),
1836
                                module[0].getModuleType(),
1837
                                module[0].getName(),
1838
                                newDirectives);
1839
                        wc.rewrite(module[0], newModule);
1840
                    }                    
1841
                })
1842
                .commit();
1843
                save(info);
1844
            }
1845
        }
1846
    }
1847
    
1848
    private static void save(@NonNull final FileObject file) throws IOException {
1849
        final DataObject dobj = DataObject.find(file);
1850
        final Savable save = dobj.getLookup().lookup(Savable.class);
1851
        if (save != null) {
1852
            save.save();
1853
        }
1854
    }
1855
    
1856
    private static SourceGroup findSourceGroup(FileObject fo, ClassPathModifier modifierImpl) {
1735
    private static SourceGroup findSourceGroup(FileObject fo, ClassPathModifier modifierImpl) {
1857
        SourceGroup[]sgs = modifierImpl.getExtensibleSourceGroups();
1736
        SourceGroup[]sgs = modifierImpl.getExtensibleSourceGroups();
1858
        for (SourceGroup sg : sgs) {
1737
        for (SourceGroup sg : sgs) {
(-)a/java.project/apichanges.xml (+13 lines)
Lines 109-114 Link Here
109
    <!-- ACTUAL CHANGES BEGIN HERE: -->
109
    <!-- ACTUAL CHANGES BEGIN HERE: -->
110
110
111
    <changes>
111
    <changes>
112
        <change id="ProjectModulesModifier">
113
            <api name="java_project"/>
114
            <summary>Added a SPI to manipulate with project's <code>module-info.java</code> declarations</summary>
115
            <version major="1" minor="70"/>
116
            <date day="16" month="3" year="2017"/>
117
            <author login="sdedic"/>
118
            <compatibility addition="yes"/>
119
            <description>
120
                Added a SPI interface, which should be implemented on project to provide backwards compatibility for
121
                <code>ProjectClassPathModifier</code> for modular projects. 
122
            </description>
123
            <class package="org.netbeans.spi.java.project.classpath" name="ProjectModulesModifier"/>
124
        </change>
112
        <change id="CompilerOptionsQueryMerger">
125
        <change id="CompilerOptionsQueryMerger">
113
            <api name="java_project"/>
126
            <api name="java_project"/>
114
            <summary>Added a <code>LookupMerger</code> for <code>CompilerOptionsQueryImplementation</code>s</summary>
127
            <summary>Added a <code>LookupMerger</code> for <code>CompilerOptionsQueryImplementation</code>s</summary>
(-)a/java.project/manifest.mf (-1 / +1 lines)
Lines 2-7 Link Here
2
OpenIDE-Module: org.netbeans.modules.java.project/1
2
OpenIDE-Module: org.netbeans.modules.java.project/1
3
OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/java/project/Bundle.properties
3
OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/java/project/Bundle.properties
4
OpenIDE-Module-Needs: javax.script.ScriptEngine.freemarker
4
OpenIDE-Module-Needs: javax.script.ScriptEngine.freemarker
5
OpenIDE-Module-Specification-Version: 1.69
5
OpenIDE-Module-Specification-Version: 1.70
6
AutoUpdate-Show-In-Client: false
6
AutoUpdate-Show-In-Client: false
7
7
(-)a/java.project/src/org/netbeans/api/java/project/classpath/ProjectClassPathModifier.java (-14 / +117 lines)
Lines 46-61 Link Here
46
46
47
import java.io.File;
47
import java.io.File;
48
import java.io.IOException;
48
import java.io.IOException;
49
import java.net.MalformedURLException;
49
import java.net.URI;
50
import java.net.URI;
50
import java.net.URL;
51
import java.net.URL;
52
import java.util.Arrays;
53
import java.util.Collection;
54
import java.util.Collections;
55
import java.util.logging.Level;
56
import java.util.logging.Logger;
57
import java.util.stream.Collectors;
51
import org.netbeans.api.java.classpath.ClassPath;
58
import org.netbeans.api.java.classpath.ClassPath;
59
import org.netbeans.api.java.project.JavaProjectConstants;
52
import org.netbeans.api.project.FileOwnerQuery;
60
import org.netbeans.api.project.FileOwnerQuery;
53
import org.netbeans.api.project.Project;
61
import org.netbeans.api.project.Project;
54
import org.netbeans.api.project.SourceGroup;
62
import org.netbeans.api.project.SourceGroup;
55
import org.netbeans.api.project.ant.AntArtifact;
63
import org.netbeans.api.project.ant.AntArtifact;
64
import org.netbeans.api.project.ant.AntArtifactQuery;
56
import org.netbeans.api.project.libraries.Library;
65
import org.netbeans.api.project.libraries.Library;
57
import org.netbeans.modules.java.project.classpath.ProjectClassPathModifierAccessor;
66
import org.netbeans.modules.java.project.classpath.ProjectClassPathModifierAccessor;
58
import org.netbeans.spi.java.project.classpath.ProjectClassPathModifierImplementation;
67
import org.netbeans.spi.java.project.classpath.ProjectClassPathModifierImplementation;
68
import org.netbeans.spi.java.project.classpath.ProjectModulesModifier;
59
import org.netbeans.spi.java.project.support.LookupMergerSupport;
69
import org.netbeans.spi.java.project.support.LookupMergerSupport;
60
import org.netbeans.spi.project.libraries.support.LibrariesSupport;
70
import org.netbeans.spi.project.libraries.support.LibrariesSupport;
61
import org.netbeans.spi.project.support.ant.PropertyUtils;
71
import org.netbeans.spi.project.support.ant.PropertyUtils;
Lines 63-68 Link Here
63
import org.openide.filesystems.FileUtil;
73
import org.openide.filesystems.FileUtil;
64
import org.openide.filesystems.URLMapper;
74
import org.openide.filesystems.URLMapper;
65
import org.openide.util.BaseUtilities;
75
import org.openide.util.BaseUtilities;
76
import org.openide.util.Lookup;
66
import org.openide.util.Parameters;
77
import org.openide.util.Parameters;
67
78
68
/**
79
/**
Lines 73-78 Link Here
73
 * @since org.netbeans.modules.java.project/1 1.10
84
 * @since org.netbeans.modules.java.project/1 1.10
74
 */
85
 */
75
public class ProjectClassPathModifier {
86
public class ProjectClassPathModifier {
87
    private static final Logger LOG = Logger.getLogger(ProjectClassPathModifier.class.getName());
76
    
88
    
77
    private ProjectClassPathModifier() {}
89
    private ProjectClassPathModifier() {}
78
    
90
    
Lines 94-100 Link Here
94
        if (extensible.pcmi != null) {
106
        if (extensible.pcmi != null) {
95
            assert extensible.sg != null;
107
            assert extensible.sg != null;
96
            assert extensible.classPathType != null;
108
            assert extensible.classPathType != null;
97
            return ProjectClassPathModifierAccessor.INSTANCE.addLibraries (libraries, extensible.pcmi, extensible.sg, extensible.classPathType);
109
            boolean r1 = ProjectClassPathModifierAccessor.INSTANCE.addLibraries (libraries, extensible.pcmi, extensible.sg, extensible.classPathType);
110
            boolean r2 = !extensible.classPathType.equals(classPathType) && 
111
                    addRootsToModinfo(classPathType, projectArtifact, toURLs(libraries));
112
            return r1 || r2;
98
        } else {
113
        } else {
99
            boolean result = false;
114
            boolean result = false;
100
            for (Library library : libraries) {
115
            for (Library library : libraries) {
Lines 121-127 Link Here
121
        if (extensible.pcmi != null) {
136
        if (extensible.pcmi != null) {
122
            assert extensible.sg != null;
137
            assert extensible.sg != null;
123
            assert extensible.classPathType != null;
138
            assert extensible.classPathType != null;
124
            return ProjectClassPathModifierAccessor.INSTANCE.removeLibraries (libraries, extensible.pcmi, extensible.sg, extensible.classPathType);
139
            boolean r1 = ProjectClassPathModifierAccessor.INSTANCE.removeLibraries (libraries, extensible.pcmi, extensible.sg, extensible.classPathType);
140
            boolean r2 = !extensible.classPathType.equals(classPathType) && 
141
                    removeRootsFromModinfo(classPathType, projectArtifact, toURLs(libraries));
142
            return r1 || r2;
125
        } else {
143
        } else {
126
            throw new UnsupportedOperationException("Cannot remove libraries using " + extensible); // NOI18N
144
            throw new UnsupportedOperationException("Cannot remove libraries using " + extensible); // NOI18N
127
        }
145
        }
Lines 146-152 Link Here
146
        if (extensible.pcmi != null) {
164
        if (extensible.pcmi != null) {
147
            assert extensible.sg != null;
165
            assert extensible.sg != null;
148
            assert extensible.classPathType != null;
166
            assert extensible.classPathType != null;
149
            return ProjectClassPathModifierAccessor.INSTANCE.addRoots (classPathRoots, extensible.pcmi, extensible.sg, extensible.classPathType);
167
            boolean r1 = ProjectClassPathModifierAccessor.INSTANCE.addRoots (classPathRoots, extensible.pcmi, extensible.sg, extensible.classPathType);
168
            boolean r2 = !extensible.classPathType.equals(classPathType) && addRootsToModinfo(classPathType, projectArtifact, Arrays.asList(classPathRoots));
169
            return r1 || r2;
150
        } else {
170
        } else {
151
            boolean result = false;
171
            boolean result = false;
152
            for (URL urlToAdd : classPathRoots) {
172
            for (URL urlToAdd : classPathRoots) {
Lines 183-189 Link Here
183
        if (extensible.pcmi != null) {
203
        if (extensible.pcmi != null) {
184
            assert extensible.sg != null;
204
            assert extensible.sg != null;
185
            assert extensible.classPathType != null;
205
            assert extensible.classPathType != null;
186
            return ProjectClassPathModifierAccessor.INSTANCE.addRoots (classPathRoots, extensible.pcmi, extensible.sg, extensible.classPathType);
206
            boolean r1 = ProjectClassPathModifierAccessor.INSTANCE.addRoots (classPathRoots, extensible.pcmi, extensible.sg, extensible.classPathType);
207
            boolean r2 = !extensible.classPathType.equals(classPathType) && 
208
                            addRootsToModinfo(classPathType, projectArtifact, toURLs(Arrays.asList(classPathRoots)));
209
            return r1 || r2;
187
        } else {
210
        } else {
188
            boolean result = false;
211
            boolean result = false;
189
            final Project project = FileOwnerQuery.getOwner(projectArtifact);
212
            final Project project = FileOwnerQuery.getOwner(projectArtifact);
Lines 226-232 Link Here
226
        if (extensible.pcmi != null) {
249
        if (extensible.pcmi != null) {
227
            assert extensible.sg != null;
250
            assert extensible.sg != null;
228
            assert extensible.classPathType != null;
251
            assert extensible.classPathType != null;
229
            return ProjectClassPathModifierAccessor.INSTANCE.removeRoots (classPathRoots, extensible.pcmi, extensible.sg, extensible.classPathType);
252
            boolean r1 = ProjectClassPathModifierAccessor.INSTANCE.removeRoots (classPathRoots, extensible.pcmi, extensible.sg, extensible.classPathType);
253
            boolean r2 = !extensible.classPathType.equals(classPathType) && 
254
                    removeRootsFromModinfo(classPathType, projectArtifact, Arrays.asList(classPathRoots));
255
            return r1 || r2;
230
        } else {
256
        } else {
231
            throw new UnsupportedOperationException("Cannot remove roots from " + extensible); // NOI18N
257
            throw new UnsupportedOperationException("Cannot remove roots from " + extensible); // NOI18N
232
        }
258
        }
Lines 279-285 Link Here
279
        if (extensible.pcmi != null) {
305
        if (extensible.pcmi != null) {
280
            assert extensible.sg != null;
306
            assert extensible.sg != null;
281
            assert extensible.classPathType != null;
307
            assert extensible.classPathType != null;
282
            return ProjectClassPathModifierAccessor.INSTANCE.addAntArtifacts (artifacts, artifactElements, extensible.pcmi, extensible.sg, extensible.classPathType);
308
            boolean r1 = ProjectClassPathModifierAccessor.INSTANCE.addAntArtifacts (artifacts, artifactElements, extensible.pcmi, extensible.sg, extensible.classPathType);
309
            boolean r2 = !extensible.classPathType.equals(classPathType) && 
310
                            addRootsToModinfo(classPathType, projectArtifact, toURLs(Arrays.asList(artifactElements)));
311
            return r1 || r2;
283
        } else {
312
        } else {
284
            boolean result = false;
313
            boolean result = false;
285
            for (int i=0; i< artifacts.length; i++) {
314
            for (int i=0; i< artifacts.length; i++) {
Lines 312-318 Link Here
312
        if (extensible.pcmi != null) {
341
        if (extensible.pcmi != null) {
313
            assert extensible.sg != null;
342
            assert extensible.sg != null;
314
            assert extensible.classPathType != null;
343
            assert extensible.classPathType != null;
315
            return ProjectClassPathModifierAccessor.INSTANCE.addProjects (projects, extensible.pcmi, extensible.sg, extensible.classPathType);
344
            boolean r1 = ProjectClassPathModifierAccessor.INSTANCE.addProjects (projects, extensible.pcmi, extensible.sg, extensible.classPathType);
345
            boolean r2 = !extensible.classPathType.equals(classPathType) && 
346
                            addRootsToModinfo(classPathType, projectArtifact, toURLs(projects));
347
            return r1 || r2;
316
        } else {
348
        } else {
317
            throw new UnsupportedOperationException("Cannot add project as dependency. Missing ProjectClassPathModifierImplementation service in project type.");
349
            throw new UnsupportedOperationException("Cannot add project as dependency. Missing ProjectClassPathModifierImplementation service in project type.");
318
        }
350
        }
Lines 339-345 Link Here
339
        if (extensible.pcmi != null) {
371
        if (extensible.pcmi != null) {
340
            assert extensible.sg != null;
372
            assert extensible.sg != null;
341
            assert extensible.classPathType != null;
373
            assert extensible.classPathType != null;
342
            return ProjectClassPathModifierAccessor.INSTANCE.removeAntArtifacts (artifacts, artifactElements, extensible.pcmi, extensible.sg, extensible.classPathType);
374
            boolean r1 = ProjectClassPathModifierAccessor.INSTANCE.removeAntArtifacts (artifacts, artifactElements, extensible.pcmi, extensible.sg, extensible.classPathType);
375
            boolean r2 = !extensible.classPathType.equals(classPathType) && 
376
                            removeRootsFromModinfo(classPathType, projectArtifact, toURLs(Arrays.asList(artifactElements)));
377
            return r1 || r2;
343
        } else {
378
        } else {
344
            throw new UnsupportedOperationException("Cannot remove artifacts from " + extensible); // NOI18N
379
            throw new UnsupportedOperationException("Cannot remove artifacts from " + extensible); // NOI18N
345
        }
380
        }
Lines 368-373 Link Here
368
            throw new UnsupportedOperationException("No project found to correspond to " + FileUtil.getFileDisplayName(projectArtifact)); // NOI18N
403
            throw new UnsupportedOperationException("No project found to correspond to " + FileUtil.getFileDisplayName(projectArtifact)); // NOI18N
369
        }
404
        }
370
        final ProjectClassPathModifierImplementation pm = project.getLookup().lookup(ProjectClassPathModifierImplementation.class);
405
        final ProjectClassPathModifierImplementation pm = project.getLookup().lookup(ProjectClassPathModifierImplementation.class);
406
        final ProjectModulesModifier pmm = Lookup.getDefault().lookup(ProjectModulesModifier.class);
407
        
408
        String substModulePath = pmm == null ? null : pmm.provideModularClasspath(projectArtifact, classPathType);
409
        final String _classPathType = substModulePath == null ? classPathType : substModulePath;
371
        if (pm != null) {            
410
        if (pm != null) {            
372
            final SourceGroup[] sgs = ProjectClassPathModifierAccessor.INSTANCE.getExtensibleSourceGroups(pm);
411
            final SourceGroup[] sgs = ProjectClassPathModifierAccessor.INSTANCE.getExtensibleSourceGroups(pm);
373
            assert sgs != null   : "Class: " + pm.getClass() + " returned null as source groups.";    //NOI18N
412
            assert sgs != null   : "Class: " + pm.getClass() + " returned null as source groups.";    //NOI18N
Lines 375-400 Link Here
375
                if ((projectArtifact == sg.getRootFolder() || FileUtil.isParentOf(sg.getRootFolder(),projectArtifact)) && sg.contains(projectArtifact)) {
414
                if ((projectArtifact == sg.getRootFolder() || FileUtil.isParentOf(sg.getRootFolder(),projectArtifact)) && sg.contains(projectArtifact)) {
376
                    final String[] types = ProjectClassPathModifierAccessor.INSTANCE.getExtensibleClassPathTypes(pm,sg);
415
                    final String[] types = ProjectClassPathModifierAccessor.INSTANCE.getExtensibleClassPathTypes(pm,sg);
377
                    assert types != null : "Class: " + pm.getClass() + " returned null as classpath types.";    //NOI18N
416
                    assert types != null : "Class: " + pm.getClass() + " returned null as classpath types.";    //NOI18N
417
                    boolean originalFound = false;
378
                    for (String type : types) {
418
                    for (String type : types) {
379
                        if (classPathType.equals(type)) {
419
                        if (_classPathType.equals(type)) {
380
                            String label = "ProjectClassPathModifierImplementation for " + classPathType + " on " + FileUtil.getFileDisplayName(sg.getRootFolder()); // NOI18N
420
                            String label = "ProjectClassPathModifierImplementation for " + _classPathType + " on " + FileUtil.getFileDisplayName(sg.getRootFolder()); // NOI18N
381
                            return new Extensible(pm, sg, type,label);
421
                            return new Extensible(pm, sg, type,label);
422
                        } else if (classPathType.equals(type)) {
423
                            originalFound = true;
382
                        }
424
                        }
383
                    }
425
                    }
426
                    if (originalFound) {
427
                        String label = "ProjectClassPathModifierImplementation for " + classPathType + " on " + FileUtil.getFileDisplayName(sg.getRootFolder()); // NOI18N
428
                        return new Extensible(pm, sg, classPathType,label);
429
                    }
384
                }
430
                }
385
            }
431
            }
386
            throw new UnsupportedOperationException("Project in " + FileUtil.getFileDisplayName(project.getProjectDirectory()) + " of " + project.getClass() +
432
            throw new UnsupportedOperationException("Project in " + FileUtil.getFileDisplayName(project.getProjectDirectory()) + " of " + project.getClass() +
387
                    " has a ProjectClassPathModifierImplementation but it will not handle " + classPathType + " for " + FileUtil.getFileDisplayName(projectArtifact) +
433
                    " has a ProjectClassPathModifierImplementation but it will not handle " + _classPathType + " for " + FileUtil.getFileDisplayName(projectArtifact) +
388
                    " extensible source groups: " + sourceGroupsToString(sgs)); // NOI18N
434
                    " extensible source groups: " + sourceGroupsToString(sgs)); // NOI18N
389
        } else {
435
        } else {
390
            final org.netbeans.spi.java.project.classpath.ProjectClassPathExtender pe =
436
            final org.netbeans.spi.java.project.classpath.ProjectClassPathExtender pe =
391
                    project.getLookup().lookup(org.netbeans.spi.java.project.classpath.ProjectClassPathExtender.class);
437
                    project.getLookup().lookup(org.netbeans.spi.java.project.classpath.ProjectClassPathExtender.class);
392
            if (pe != null) {
438
            if (pe != null) {
393
                if (classPathType.equals(ClassPath.COMPILE)) {
439
                if (_classPathType.equals(ClassPath.COMPILE)) {
394
                    return new Extensible(pe, "ProjectClassPathExtender for " + FileUtil.getFileDisplayName(project.getProjectDirectory())); // NOI18N
440
                    return new Extensible(pe, "ProjectClassPathExtender for " + FileUtil.getFileDisplayName(project.getProjectDirectory())); // NOI18N
395
                } else {
441
                } else {
396
                    throw new UnsupportedOperationException("Project in " + FileUtil.getFileDisplayName(project.getProjectDirectory()) + " of " + project.getClass() +
442
                    throw new UnsupportedOperationException("Project in " + FileUtil.getFileDisplayName(project.getProjectDirectory()) + " of " + project.getClass() +
397
                            " has a ProjectClassPathExtender in its lookup but no ProjectClassPathModifierImplementation to handle " + classPathType); // NOI18N
443
                            " has a ProjectClassPathExtender in its lookup but no ProjectClassPathModifierImplementation to handle " + _classPathType); // NOI18N
398
                }
444
                }
399
            } else {
445
            } else {
400
                throw new UnsupportedOperationException("Project in " + FileUtil.getFileDisplayName(project.getProjectDirectory()) + " of " + project.getClass() +
446
                throw new UnsupportedOperationException("Project in " + FileUtil.getFileDisplayName(project.getProjectDirectory()) + " of " + project.getClass() +
Lines 550-554 Link Here
550
            }
596
            }
551
        };
597
        };
552
    }
598
    }
553
599
    
600
    private static Collection<URL> toURLs(Collection<URI> libs)  {
601
        URL[] urls = new URL[libs.size()];
602
        int index = 0;
603
        for (URI u : libs) {
604
            try {
605
                urls[index++] = u.toURL();
606
            } catch (MalformedURLException ex) {
607
                return Collections.emptyList();
608
            }
609
        }
610
        return Arrays.asList(urls);
611
    }
612
    
613
    private static Collection<URL> toURLs(Project[] prjs) {
614
        return
615
            toURLs(
616
            Arrays.asList(prjs).stream().flatMap(
617
                (prj) -> Arrays.asList(
618
                        AntArtifactQuery.findArtifactsByType(prj, JavaProjectConstants.ARTIFACT_TYPE_JAR)
619
                ).stream()).
620
                flatMap((a) -> Arrays.asList(a.getArtifactLocations()).stream()).
621
                collect(Collectors.toList())
622
            );
623
    }
624
    
625
    private static Collection<URL> toURLs(Library[] libraries) {
626
        return Arrays.stream(libraries).flatMap((l) -> l.getContent("classpath").stream()).
627
                collect(Collectors.toList());
628
    }
629
    
630
    private static boolean removeRootsFromModinfo(String originalPathType, FileObject artifact, Collection<URL> libs) {
631
        ProjectModulesModifier pmm = Lookup.getDefault().lookup(ProjectModulesModifier.class);
632
        if (pmm == null) {
633
            return false;
634
        } else {
635
            try {
636
                return pmm.removeRequiredModules(originalPathType, artifact, libs);
637
            } catch (IOException ex) {
638
                LOG.log(Level.WARNING, "Could not remove module requires", ex);
639
                return false;
640
            }
641
        }
642
    }
643
    
644
    private static boolean addRootsToModinfo(String originalPathType, FileObject artifact, Collection<URL> libs) {
645
        ProjectModulesModifier pmm = Lookup.getDefault().lookup(ProjectModulesModifier.class);
646
        if (pmm == null) {
647
            return false;
648
        } else {
649
            try {
650
                return pmm.addRequiredModules(originalPathType, artifact, libs);
651
            } catch (IOException ex) {
652
                LOG.log(Level.WARNING, "Could not declare module requires", ex);
653
                return false;
654
            }
655
        }
656
    }
554
}
657
}
(-)a/java.project/src/org/netbeans/modules/java/project/ProjectClassPathProvider.java (-1 / +1 lines)
Lines 76-82 Link Here
76
                if (LOG.isLoggable(Level.FINE)) {
76
                if (LOG.isLoggable(Level.FINE)) {
77
                    LOG.log(Level.FINE, "findClassPath({0}, {1}) -> {2} from {3}", new Object[] {file, type, result, cpp});
77
                    LOG.log(Level.FINE, "findClassPath({0}, {1}) -> {2} from {3}", new Object[] {file, type, result, cpp});
78
                }
78
                }
79
                return result;
79
                return result != null ? result : ClassPath.EMPTY;
80
            } else {
80
            } else {
81
                if (LOG.isLoggable(Level.FINE)) {
81
                if (LOG.isLoggable(Level.FINE)) {
82
                    LOG.log(Level.FINE, "cpp.findClassPath({0}, {1}) -> null", new Object[] {file, type});
82
                    LOG.log(Level.FINE, "cpp.findClassPath({0}, {1}) -> null", new Object[] {file, type});
(-)a/java.project/src/org/netbeans/spi/java/project/classpath/ProjectModulesModifier.java (+109 lines)
Line 0 Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright (c) 2017 Oracle and/or its affiliates. All rights reserved.
5
 *
6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7
 * Other names may be trademarks of their respective owners.
8
 *
9
 * The contents of this file are subject to the terms of either the GNU
10
 * General Public License Version 2 only ("GPL") or the Common
11
 * Development and Distribution License("CDDL") (collectively, the
12
 * "License"). You may not use this file except in compliance with the
13
 * License. You can obtain a copy of the License at
14
 * http://www.netbeans.org/cddl-gplv2.html
15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
16
 * specific language governing permissions and limitations under the
17
 * License.  When distributing the software, include this License Header
18
 * Notice in each file and include the License file at
19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
20
 * particular file as subject to the "Classpath" exception as provided
21
 * by Oracle in the GPL Version 2 section of the License file that
22
 * accompanied this code. If applicable, add the following below the
23
 * License Header, with the fields enclosed by brackets [] replaced by
24
 * your own identifying information:
25
 * "Portions Copyrighted [year] [name of copyright owner]"
26
 *
27
 * If you wish your version of this file to be governed by only the CDDL
28
 * or only the GPL Version 2, indicate your decision by adding
29
 * "[Contributor] elects to include this software in this distribution
30
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
31
 * single choice of license, a recipient has the option to distribute
32
 * your version of this file under either the CDDL, the GPL Version 2 or
33
 * to extend the choice of license to its licensees as provided above.
34
 * However, if you add GPL Version 2 code and therefore, elected the GPL
35
 * Version 2 license, then the option applies only if the new code is
36
 * made subject to such option by the copyright holder.
37
 *
38
 * Contributor(s):
39
 */
40
package org.netbeans.spi.java.project.classpath;
41
42
import java.io.IOException;
43
import java.net.URL;
44
import java.util.Collection;
45
import org.netbeans.api.java.classpath.ClassPath;
46
import org.netbeans.api.java.classpath.JavaClassPathConstants;
47
import org.openide.filesystems.FileObject;
48
49
/**
50
 * Allows to update the module declaration in projects which support JDK9. For modular projects,
51
 * it is not sufficient just to add artifacts on classpath - modular projects cannot access unnamed module,
52
 * so the project would not see such classes/resources during compilation. Even if added to the module path,
53
 * a directive needs to be added so that compiler and runtime honour the dependency.
54
 * <p/>
55
 * This SPI allows the project implementation for modular project to diverge additions to a more suitable classpath,
56
 * and to update the module information.
57
 * <p/>
58
 * Project-specific implementation should be placed in <b>project lookup</b>. If not present, default implementation
59
 * will handle the requests, so that artifacts, libraries and projects will land on {@link JavaClassPathConstants#MODULE_COMPILE_PATH}
60
 * or {@link JavaClassPathConstants#MODULE_EXECUTE_PATH} respectively. The default implementation does nothing for projects (sources), which do
61
 * not use {@code module-info} declaration, although they target JDK 9.
62
 * 
63
 * @author sdedic
64
 * @since 1.70
65
 */
66
public interface ProjectModulesModifier {
67
    /**
68
     * Translates the classpath type into a proper modular one, if necessary. If the project
69
     * is modular, artifacts added to {@link ClassPath#COMPILE} does not make sense, since it
70
     * is inaccessible (without specific startup parameters), so modular project may need to
71
     * diverge the request to some other classpath type.
72
     * If the project is not modular, or modular project can use artifacts from the original classpath
73
     * type, the value of {@code null} should be returned. If {@code null} is returned,
74
     * the {@link #addRequiredModules} or {@link #removeRequiredModuels} should not be called.
75
     * 
76
     * @param classPathType original classpath type
77
     * @param projectArtifact source, directory which will determine the proper {@code module-info.java}
78
     * @return modular replacement for the {@code classPathType}.
79
     */
80
    public String   provideModularClasspath(FileObject projectArtifact, String classPathType);
81
    
82
    /**
83
     * Adds "requires" clauses to module-info. "requires" directive will be created
84
     * for each of the module names in module-info which applies to the "source" file. 
85
     * The implementation may ignore requests for classpath types, which do not interact with the
86
     * module system.
87
     * 
88
     * @param projectArtifact source, directory which will determine the proper {@code module-info.java}
89
     * @param locations module names to add required directives for
90
     * @param pathType the original path type
91
     * @return true, if some modification has been made
92
     * @throws IOException on error
93
     */
94
    public boolean  addRequiredModules(String pathType, FileObject projectArtifact, Collection<URL> locations) throws IOException;
95
96
    /**
97
     * Removes "requires" clauses from module-info. Requires directives will be removed for all
98
     * modules in the "moduleNames".
99
     * The implementation may ignore requests for classpath types, which do not interact with the
100
     * module system.
101
     * 
102
     * @param projectArtifact source, directory which will determine the proper {@code module-info.java}
103
     * @param locations module names whose required directives should be removed
104
     * @param pathType the original path type
105
     * @return true, if some modification has been made
106
     * @throws IOException on error
107
     */
108
    public boolean  removeRequiredModules(String pathType, FileObject projectArtifact, Collection<URL> locations) throws IOException;
109
}
(-)a/jshell.support/src/org/netbeans/modules/jshell/project/REPLAction2.java (+2 lines)
Lines 46-51 Link Here
46
import org.netbeans.api.project.Project;
46
import org.netbeans.api.project.Project;
47
import org.netbeans.modules.jshell.env.JShellEnvironment;
47
import org.netbeans.modules.jshell.env.JShellEnvironment;
48
import org.netbeans.modules.jshell.env.ShellRegistry;
48
import org.netbeans.modules.jshell.env.ShellRegistry;
49
import org.netbeans.modules.projectapi.ProjectFileBuiltQuery;
49
import org.netbeans.spi.project.ui.support.ProjectActionPerformer;
50
import org.netbeans.spi.project.ui.support.ProjectActionPerformer;
50
import org.netbeans.spi.project.ui.support.ProjectSensitiveActions;
51
import org.netbeans.spi.project.ui.support.ProjectSensitiveActions;
51
import org.openide.awt.ActionID;
52
import org.openide.awt.ActionID;
Lines 81-86 Link Here
81
    public void perform(Project project) {
82
    public void perform(Project project) {
82
        JShellEnvironment env;
83
        JShellEnvironment env;
83
        try {
84
        try {
85
            
84
            env = ShellRegistry.get().openProjectSession(project);
86
            env = ShellRegistry.get().openProjectSession(project);
85
            env.open();
87
            env.open();
86
        } catch (IOException ex) {
88
        } catch (IOException ex) {
(-)a/maven/src/org/netbeans/modules/maven/classpath/CPExtender.java (-1 / +3 lines)
Lines 254-259 Link Here
254
            ClassPath.COMPILE,
254
            ClassPath.COMPILE,
255
            ClassPath.EXECUTE,
255
            ClassPath.EXECUTE,
256
            JavaClassPathConstants.COMPILE_ONLY,
256
            JavaClassPathConstants.COMPILE_ONLY,
257
            JavaClassPathConstants.MODULE_COMPILE_PATH,
258
            JavaClassPathConstants.MODULE_EXECUTE_PATH,
257
            JavaClassPathConstants.PROCESSOR_PATH
259
            JavaClassPathConstants.PROCESSOR_PATH
258
        };
260
        };
259
    }
261
    }
Lines 379-385 Link Here
379
    }
381
    }
380
    
382
    
381
    private static String findScope(SourceGroup grp, String type) {
383
    private static String findScope(SourceGroup grp, String type) {
382
        String scope = ClassPath.EXECUTE.equals(type) ? Artifact.SCOPE_RUNTIME : null; //NOI18N
384
        String scope = ClassPath.EXECUTE.equals(type) || JavaClassPathConstants.MODULE_EXECUTE_PATH.equals(type)? Artifact.SCOPE_RUNTIME : null; //NOI18N
383
        //figure if we deal with test or regular sources.
385
        //figure if we deal with test or regular sources.
384
        String name = grp.getName();
386
        String name = grp.getName();
385
        if (MavenSourcesImpl.NAME_TESTSOURCE.equals(name)) {
387
        if (MavenSourcesImpl.NAME_TESTSOURCE.equals(name)) {

Return to bug 270094