|
1 | 1 | /******************************************************************************* |
2 | | - * Copyright (c) 2017 Microsoft Corporation and others. |
| 2 | + * Copyright (c) 2017-2019 Microsoft Corporation and others. |
3 | 3 | * All rights reserved. This program and the accompanying materials |
4 | 4 | * are made available under the terms of the Eclipse Public License v1.0 |
5 | 5 | * which accompanies this distribution, and is available at |
|
11 | 11 |
|
12 | 12 | package com.microsoft.java.debug.plugin.internal; |
13 | 13 |
|
| 14 | +import java.io.IOException; |
| 15 | +import java.io.StringReader; |
14 | 16 | import java.util.ArrayList; |
| 17 | +import java.util.Date; |
15 | 18 | import java.util.LinkedHashSet; |
16 | 19 | import java.util.List; |
17 | 20 | import java.util.Set; |
18 | 21 | import java.util.logging.Level; |
19 | 22 | import java.util.logging.Logger; |
20 | 23 | import java.util.stream.Collectors; |
21 | 24 |
|
| 25 | +import javax.xml.parsers.DocumentBuilder; |
| 26 | +import javax.xml.parsers.DocumentBuilderFactory; |
| 27 | +import javax.xml.parsers.ParserConfigurationException; |
| 28 | + |
22 | 29 | import org.apache.commons.lang3.StringUtils; |
| 30 | +import org.eclipse.core.resources.IProject; |
23 | 31 | import org.eclipse.core.resources.ResourcesPlugin; |
24 | 32 | import org.eclipse.core.runtime.CoreException; |
25 | 33 | import org.eclipse.core.runtime.IStatus; |
26 | 34 | import org.eclipse.core.runtime.Status; |
| 35 | +import org.eclipse.debug.core.ILaunchConfiguration; |
| 36 | +import org.eclipse.debug.internal.core.LaunchConfiguration; |
| 37 | +import org.eclipse.debug.internal.core.LaunchConfigurationInfo; |
27 | 38 | import org.eclipse.jdt.core.IJavaElement; |
28 | 39 | import org.eclipse.jdt.core.IJavaProject; |
29 | 40 | import org.eclipse.jdt.core.IType; |
|
34 | 45 | import org.eclipse.jdt.core.search.SearchParticipant; |
35 | 46 | import org.eclipse.jdt.core.search.SearchPattern; |
36 | 47 | import org.eclipse.jdt.core.search.SearchRequestor; |
| 48 | +import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants; |
37 | 49 | import org.eclipse.jdt.launching.IRuntimeClasspathEntry; |
38 | 50 | import org.eclipse.jdt.launching.JavaRuntime; |
| 51 | +import org.eclipse.jdt.ls.core.internal.ProjectUtils; |
| 52 | +import org.w3c.dom.Element; |
| 53 | +import org.xml.sax.InputSource; |
| 54 | +import org.xml.sax.SAXException; |
| 55 | +import org.xml.sax.helpers.DefaultHandler; |
39 | 56 |
|
40 | 57 | import com.microsoft.java.debug.core.Configuration; |
41 | 58 |
|
42 | 59 | public class ResolveClasspathsHandler { |
43 | 60 | private static final Logger logger = Logger.getLogger(Configuration.LOGGER_NAME); |
44 | 61 |
|
45 | | - |
46 | 62 | /** |
47 | 63 | * Resolves class path for a java project. |
48 | 64 | * @param arguments a list contains the main class name and project name |
@@ -160,59 +176,47 @@ private static String[][] computeClassPath(String mainClass, String projectName) |
160 | 176 | project = projects.get(0); |
161 | 177 | } |
162 | 178 |
|
163 | | - return computeClassPath(project, isMainClassInTestFolder(project, mainClass)); |
| 179 | + return computeClassPath(project, !isMainClassInTestFolder(project, mainClass)); |
164 | 180 | } |
165 | 181 |
|
166 | 182 | /** |
167 | 183 | * Compute runtime classpath of a java project. |
168 | 184 | * |
169 | 185 | * @param javaProject |
170 | 186 | * java project |
| 187 | + * @param excludeTestCode whether to exclude the test code and test dependencies. |
171 | 188 | * @return class path |
172 | 189 | * @throws CoreException |
173 | 190 | * CoreException |
174 | 191 | */ |
175 | | - private static String[][] computeClassPath(IJavaProject javaProject, boolean includeTestScope) |
| 192 | + private static String[][] computeClassPath(IJavaProject javaProject, boolean excludeTestCode) |
176 | 193 | throws CoreException { |
177 | 194 | if (javaProject == null) { |
178 | 195 | throw new IllegalArgumentException("javaProject is null"); |
179 | 196 | } |
180 | | - String[][] result = new String[2][]; |
181 | | - if (JavaRuntime.isModularProject(javaProject)) { |
182 | | - result[0] = computeDefaultRuntimeClassPath(javaProject, includeTestScope); |
183 | | - result[1] = new String[0]; |
184 | | - } else { |
185 | | - result[0] = new String[0]; |
186 | | - result[1] = computeDefaultRuntimeClassPath(javaProject, includeTestScope); |
187 | | - } |
188 | | - return result; |
189 | | - } |
190 | | - |
191 | | - private static String[] computeDefaultRuntimeClassPath(IJavaProject jproject, boolean includeTestScope) |
192 | | - throws CoreException { |
193 | | - IRuntimeClasspathEntry[] unresolved = JavaRuntime.computeUnresolvedRuntimeClasspath(jproject); |
194 | | - Set<String> resolved = new LinkedHashSet<String>(); |
195 | | - for (int i = 0; i < unresolved.length; i++) { |
196 | | - IRuntimeClasspathEntry entry = unresolved[i]; |
197 | | - if (entry.getClasspathProperty() == IRuntimeClasspathEntry.USER_CLASSES) { |
198 | | - IRuntimeClasspathEntry[] entries = JavaRuntime.resolveRuntimeClasspathEntry(entry, jproject, |
199 | | - !includeTestScope); |
200 | | - for (int j = 0; j < entries.length; j++) { |
201 | 197 |
|
202 | | - if (!includeTestScope && JdtUtils.isTest(entries[j].getClasspathEntry())) { |
203 | | - continue; |
204 | | - } |
205 | | - String location = entries[j].getLocation(); |
206 | | - if (location != null) { |
207 | | - // remove duplicate classpath |
208 | | - resolved.add(location); |
209 | | - } |
| 198 | + ILaunchConfiguration launchConfig = new JavaApplicationLaunchConfiguration(javaProject.getProject(), excludeTestCode); |
| 199 | + IRuntimeClasspathEntry[] unresolved = JavaRuntime.computeUnresolvedRuntimeClasspath(launchConfig); |
| 200 | + IRuntimeClasspathEntry[] resolved = JavaRuntime.resolveRuntimeClasspath(unresolved, launchConfig); |
| 201 | + Set<String> classpaths = new LinkedHashSet<>(); |
| 202 | + Set<String> modulepaths = new LinkedHashSet<>(); |
| 203 | + for (IRuntimeClasspathEntry entry : resolved) { |
| 204 | + String location = entry.getLocation(); |
| 205 | + if (location != null) { |
| 206 | + if (entry.getClasspathProperty() == IRuntimeClasspathEntry.USER_CLASSES |
| 207 | + || entry.getClasspathProperty() == IRuntimeClasspathEntry.CLASS_PATH) { |
| 208 | + classpaths.add(location); |
| 209 | + } else if (entry.getClasspathProperty() == IRuntimeClasspathEntry.MODULE_PATH) { |
| 210 | + modulepaths.add(location); |
210 | 211 | } |
211 | 212 | } |
212 | 213 | } |
213 | | - return resolved.toArray(new String[resolved.size()]); |
214 | | - } |
215 | 214 |
|
| 215 | + return new String[][] { |
| 216 | + modulepaths.toArray(new String[modulepaths.size()]), |
| 217 | + classpaths.toArray(new String[classpaths.size()]) |
| 218 | + }; |
| 219 | + } |
216 | 220 |
|
217 | 221 | /** |
218 | 222 | * Test whether the main class is located in test folders. |
@@ -254,4 +258,76 @@ public void acceptSearchMatch(SearchMatch match) { |
254 | 258 | } |
255 | 259 | return false; |
256 | 260 | } |
| 261 | + |
| 262 | + private static class JavaApplicationLaunchConfiguration extends LaunchConfiguration { |
| 263 | + public static final String JAVA_APPLICATION_LAUNCH = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n" |
| 264 | + + "<launchConfiguration type=\"org.eclipse.jdt.launching.localJavaApplication\">\n" |
| 265 | + + "<listAttribute key=\"org.eclipse.debug.core.MAPPED_RESOURCE_PATHS\">\n" |
| 266 | + + "</listAttribute>\n" |
| 267 | + + "<listAttribute key=\"org.eclipse.debug.core.MAPPED_RESOURCE_TYPES\">\n" |
| 268 | + + "<listEntry value=\"1\"/>\n" |
| 269 | + + "</listAttribute>\n" |
| 270 | + + "</launchConfiguration>"; |
| 271 | + private IProject project; |
| 272 | + private boolean excludeTestCode; |
| 273 | + private String classpathProvider; |
| 274 | + private String sourcepathProvider; |
| 275 | + private LaunchConfigurationInfo launchInfo; |
| 276 | + |
| 277 | + protected JavaApplicationLaunchConfiguration(IProject project, boolean excludeTestCode) throws CoreException { |
| 278 | + super(String.valueOf(new Date().getTime()), null, false); |
| 279 | + this.project = project; |
| 280 | + this.excludeTestCode = excludeTestCode; |
| 281 | + if (ProjectUtils.isMavenProject(project)) { |
| 282 | + classpathProvider = "org.eclipse.m2e.launchconfig.classpathProvider"; |
| 283 | + sourcepathProvider = "org.eclipse.m2e.launchconfig.sourcepathProvider"; |
| 284 | + } else if (ProjectUtils.isGradleProject(project)) { |
| 285 | + classpathProvider = "org.eclipse.buildship.core.classpathprovider"; |
| 286 | + } |
| 287 | + this.launchInfo = new JavaLaunchConfigurationInfo(JAVA_APPLICATION_LAUNCH); |
| 288 | + } |
| 289 | + |
| 290 | + @Override |
| 291 | + public boolean getAttribute(String attributeName, boolean defaultValue) throws CoreException { |
| 292 | + if (IJavaLaunchConfigurationConstants.ATTR_EXCLUDE_TEST_CODE.equalsIgnoreCase(attributeName)) { |
| 293 | + return excludeTestCode; |
| 294 | + } |
| 295 | + |
| 296 | + return super.getAttribute(attributeName, defaultValue); |
| 297 | + } |
| 298 | + |
| 299 | + @Override |
| 300 | + public String getAttribute(String attributeName, String defaultValue) throws CoreException { |
| 301 | + if (IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME.equalsIgnoreCase(attributeName)) { |
| 302 | + return project.getName(); |
| 303 | + } else if (IJavaLaunchConfigurationConstants.ATTR_CLASSPATH_PROVIDER.equalsIgnoreCase(attributeName)) { |
| 304 | + return classpathProvider; |
| 305 | + } else if (IJavaLaunchConfigurationConstants.ATTR_SOURCE_PATH_PROVIDER.equalsIgnoreCase(attributeName)) { |
| 306 | + return sourcepathProvider; |
| 307 | + } |
| 308 | + |
| 309 | + return super.getAttribute(attributeName, defaultValue); |
| 310 | + } |
| 311 | + |
| 312 | + @Override |
| 313 | + protected LaunchConfigurationInfo getInfo() throws CoreException { |
| 314 | + return this.launchInfo; |
| 315 | + } |
| 316 | + } |
| 317 | + |
| 318 | + private static class JavaLaunchConfigurationInfo extends LaunchConfigurationInfo { |
| 319 | + public JavaLaunchConfigurationInfo(String launchXml) { |
| 320 | + super(); |
| 321 | + try { |
| 322 | + DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder(); |
| 323 | + parser.setErrorHandler(new DefaultHandler()); |
| 324 | + StringReader reader = new StringReader(launchXml); |
| 325 | + InputSource source = new InputSource(reader); |
| 326 | + Element root = parser.parse(source).getDocumentElement(); |
| 327 | + initializeFromXML(root); |
| 328 | + } catch (ParserConfigurationException | SAXException | IOException | CoreException e) { |
| 329 | + // do nothing |
| 330 | + } |
| 331 | + } |
| 332 | + } |
257 | 333 | } |
0 commit comments