Skip to content

Commit e87ae32

Browse files
For different project types, use the corresponding class provider to resolve the runtime classpath (#281)
Signed-off-by: Jinbo Wang <[email protected]>
1 parent b31fd4c commit e87ae32

File tree

1 file changed

+111
-35
lines changed

1 file changed

+111
-35
lines changed

com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/ResolveClasspathsHandler.java

Lines changed: 111 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2017 Microsoft Corporation and others.
2+
* Copyright (c) 2017-2019 Microsoft Corporation and others.
33
* All rights reserved. This program and the accompanying materials
44
* are made available under the terms of the Eclipse Public License v1.0
55
* which accompanies this distribution, and is available at
@@ -11,19 +11,30 @@
1111

1212
package com.microsoft.java.debug.plugin.internal;
1313

14+
import java.io.IOException;
15+
import java.io.StringReader;
1416
import java.util.ArrayList;
17+
import java.util.Date;
1518
import java.util.LinkedHashSet;
1619
import java.util.List;
1720
import java.util.Set;
1821
import java.util.logging.Level;
1922
import java.util.logging.Logger;
2023
import java.util.stream.Collectors;
2124

25+
import javax.xml.parsers.DocumentBuilder;
26+
import javax.xml.parsers.DocumentBuilderFactory;
27+
import javax.xml.parsers.ParserConfigurationException;
28+
2229
import org.apache.commons.lang3.StringUtils;
30+
import org.eclipse.core.resources.IProject;
2331
import org.eclipse.core.resources.ResourcesPlugin;
2432
import org.eclipse.core.runtime.CoreException;
2533
import org.eclipse.core.runtime.IStatus;
2634
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;
2738
import org.eclipse.jdt.core.IJavaElement;
2839
import org.eclipse.jdt.core.IJavaProject;
2940
import org.eclipse.jdt.core.IType;
@@ -34,15 +45,20 @@
3445
import org.eclipse.jdt.core.search.SearchParticipant;
3546
import org.eclipse.jdt.core.search.SearchPattern;
3647
import org.eclipse.jdt.core.search.SearchRequestor;
48+
import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants;
3749
import org.eclipse.jdt.launching.IRuntimeClasspathEntry;
3850
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;
3956

4057
import com.microsoft.java.debug.core.Configuration;
4158

4259
public class ResolveClasspathsHandler {
4360
private static final Logger logger = Logger.getLogger(Configuration.LOGGER_NAME);
4461

45-
4662
/**
4763
* Resolves class path for a java project.
4864
* @param arguments a list contains the main class name and project name
@@ -160,59 +176,47 @@ private static String[][] computeClassPath(String mainClass, String projectName)
160176
project = projects.get(0);
161177
}
162178

163-
return computeClassPath(project, isMainClassInTestFolder(project, mainClass));
179+
return computeClassPath(project, !isMainClassInTestFolder(project, mainClass));
164180
}
165181

166182
/**
167183
* Compute runtime classpath of a java project.
168184
*
169185
* @param javaProject
170186
* java project
187+
* @param excludeTestCode whether to exclude the test code and test dependencies.
171188
* @return class path
172189
* @throws CoreException
173190
* CoreException
174191
*/
175-
private static String[][] computeClassPath(IJavaProject javaProject, boolean includeTestScope)
192+
private static String[][] computeClassPath(IJavaProject javaProject, boolean excludeTestCode)
176193
throws CoreException {
177194
if (javaProject == null) {
178195
throw new IllegalArgumentException("javaProject is null");
179196
}
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++) {
201197

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);
210211
}
211212
}
212213
}
213-
return resolved.toArray(new String[resolved.size()]);
214-
}
215214

215+
return new String[][] {
216+
modulepaths.toArray(new String[modulepaths.size()]),
217+
classpaths.toArray(new String[classpaths.size()])
218+
};
219+
}
216220

217221
/**
218222
* Test whether the main class is located in test folders.
@@ -254,4 +258,76 @@ public void acceptSearchMatch(SearchMatch match) {
254258
}
255259
return false;
256260
}
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+
}
257333
}

0 commit comments

Comments
 (0)