diff --git a/.azure-pipelines/signjars-nightly.yml b/.azure-pipelines/signjars-nightly.yml
index bdaeea871..0e53a4219 100644
--- a/.azure-pipelines/signjars-nightly.yml
+++ b/.azure-pipelines/signjars-nightly.yml
@@ -73,7 +73,7 @@ extends:
- task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@2
displayName: Sign core.jar
inputs:
- ConnectedServiceName: vscjavaci_codesign
+ ConnectedServiceName: vscjavaci_esrp_codesign
FolderPath: jars
Pattern: com.microsoft.java.debug.core*.jar
signConfigType: inlineSignParams
@@ -105,6 +105,7 @@ extends:
displayName: Build plugin.jar
inputs:
script: |-
+ ./mvnw clean install -N -f pom.xml -Dmaven.repo.local=./.repository
./mvnw clean install -f com.microsoft.java.debug.target/pom.xml -Dmaven.repo.local=./.repository
./mvnw clean install -f com.microsoft.java.debug.plugin/pom.xml -Dmaven.repo.local=./.repository
@@ -113,7 +114,7 @@ extends:
- task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@2
displayName: Sign plugin.jar
inputs:
- ConnectedServiceName: vscjavaci_codesign
+ ConnectedServiceName: vscjavaci_esrp_codesign
FolderPath: jars
Pattern: com.microsoft.java.debug.plugin*.jar
signConfigType: inlineSignParams
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 41c85cb62..1ace44224 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -28,7 +28,7 @@ jobs:
${{ runner.os }}-maven-
- name: Verify
- run: ./mvnw clean verify
+ run: ./mvnw clean verify -U
- name: Checkstyle
run: ./mvnw checkstyle:check
@@ -85,7 +85,7 @@ jobs:
${{ runner.os }}-maven-
- name: Verify
- run: ./mvnw clean verify
+ run: ./mvnw clean verify -U
- name: Checkstyle
run: ./mvnw checkstyle:check
diff --git a/com.microsoft.java.debug.core/pom.xml b/com.microsoft.java.debug.core/pom.xml
index a7c2ca8ce..3b42e40cb 100644
--- a/com.microsoft.java.debug.core/pom.xml
+++ b/com.microsoft.java.debug.core/pom.xml
@@ -5,7 +5,7 @@
com.microsoft.java
java-debug-parent
- 0.51.1
+ 0.52.0
com.microsoft.java.debug.core
jar
diff --git a/com.microsoft.java.debug.plugin/.classpath b/com.microsoft.java.debug.plugin/.classpath
index b4fb64d7d..6de8860a5 100644
--- a/com.microsoft.java.debug.plugin/.classpath
+++ b/com.microsoft.java.debug.plugin/.classpath
@@ -11,6 +11,6 @@
-
+
diff --git a/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF b/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF
index 73af47a6d..b45c99f7a 100644
--- a/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF
+++ b/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Java Debug Server Plugin
Bundle-SymbolicName: com.microsoft.java.debug.plugin;singleton:=true
-Bundle-Version: 0.51.1
+Bundle-Version: 0.52.0
Bundle-RequiredExecutionEnvironment: JavaSE-11
Bundle-ActivationPolicy: lazy
Bundle-Activator: com.microsoft.java.debug.plugin.internal.JavaDebuggerServerPlugin
@@ -25,4 +25,4 @@ Bundle-ClassPath: lib/commons-io-2.11.0.jar,
.,
lib/rxjava-2.2.21.jar,
lib/reactive-streams-1.0.4.jar,
- lib/com.microsoft.java.debug.core-0.51.1.jar
+ lib/com.microsoft.java.debug.core-0.52.0.jar
diff --git a/com.microsoft.java.debug.plugin/pom.xml b/com.microsoft.java.debug.plugin/pom.xml
index 4657ab08b..6d58947b0 100644
--- a/com.microsoft.java.debug.plugin/pom.xml
+++ b/com.microsoft.java.debug.plugin/pom.xml
@@ -5,7 +5,7 @@
com.microsoft.java
java-debug-parent
- 0.51.1
+ 0.52.0
com.microsoft.java.debug.plugin
eclipse-plugin
@@ -56,7 +56,7 @@
com.microsoft.java
com.microsoft.java.debug.core
- 0.51.1
+ 0.52.0
diff --git a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/JdtSourceLookUpProvider.java b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/JdtSourceLookUpProvider.java
index 1ebf4c7c3..5652b922e 100644
--- a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/JdtSourceLookUpProvider.java
+++ b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/JdtSourceLookUpProvider.java
@@ -20,11 +20,14 @@
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.Set;
import java.util.jar.Attributes;
import java.util.jar.Manifest;
import java.util.logging.Level;
@@ -32,6 +35,7 @@
import java.util.stream.Collectors;
import java.util.stream.Stream;
+import org.apache.commons.lang3.StringUtils;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
@@ -85,6 +89,9 @@ public class JdtSourceLookUpProvider implements ISourceLookUpProvider {
private static final Logger logger = Logger.getLogger(Configuration.LOGGER_NAME);
private static final String JDT_SCHEME = "jdt";
private static final String PATH_SEPARATOR = "/";
+ private static final Set IMPLICITLY_DECLARED_CLASSES = new HashSet<>(
+ Arrays.asList("org.eclipse.jdt.core.dom.UnnamedClass",
+ "org.eclipse.jdt.core.dom.ImplicitTypeDeclaration"));
private ISourceContainer[] sourceContainers = null;
private HashMap options = new HashMap();
@@ -172,6 +179,14 @@ public JavaBreakpointLocation[] getBreakpointLocations(String sourceUri, SourceB
.map(sourceBreakpoint -> new JavaBreakpointLocation(sourceBreakpoint.line, sourceBreakpoint.column))
.toArray(JavaBreakpointLocation[]::new);
if (astUnit != null) {
+ List> types = astUnit.types();
+ String unnamedClass = null;
+ // See https://github.com/eclipse-jdt/eclipse.jdt.core/pull/2220
+ // Given that the JDT plans to rename UnamedClass to ImplicitTypeDeclaration, we will check
+ // the class name of the ASTNode to prevent the potential breaking in the future.
+ if (types.size() == 1 && IMPLICITLY_DECLARED_CLASSES.contains(types.get(0).getClass().getName())) {
+ unnamedClass = inferPrimaryTypeName(sourceUri, astUnit);
+ }
Map resolvedLocations = new HashMap<>();
for (JavaBreakpointLocation sourceLocation : sourceLocations) {
int sourceLine = sourceLocation.lineNumber();
@@ -222,7 +237,7 @@ public JavaBreakpointLocation[] getBreakpointLocations(String sourceUri, SourceB
// be hit in current implementation.
if (sourceLine == locator.getLineLocation()
&& locator.getLocationType() == BreakpointLocationLocator.LOCATION_LINE) {
- sourceLocation.setClassName(locator.getFullyQualifiedTypeName());
+ sourceLocation.setClassName(StringUtils.isBlank(unnamedClass) ? locator.getFullyQualifiedTypeName() : unnamedClass);
if (resolvedLocations.containsKey(sourceLine)) {
sourceLocation.setAvailableBreakpointLocations(resolvedLocations.get(sourceLine));
} else {
@@ -231,7 +246,7 @@ public JavaBreakpointLocation[] getBreakpointLocations(String sourceUri, SourceB
resolvedLocations.put(sourceLine, inlineLocations);
}
} else if (locator.getLocationType() == BreakpointLocationLocator.LOCATION_METHOD) {
- sourceLocation.setClassName(locator.getFullyQualifiedTypeName());
+ sourceLocation.setClassName(StringUtils.isBlank(unnamedClass) ? locator.getFullyQualifiedTypeName() : unnamedClass);
sourceLocation.setMethodName(locator.getMethodName());
sourceLocation.setMethodSignature(locator.getMethodSignature());
}
@@ -241,6 +256,27 @@ public JavaBreakpointLocation[] getBreakpointLocations(String sourceUri, SourceB
return sourceLocations;
}
+ private String inferPrimaryTypeName(String uri, CompilationUnit astUnit) {
+ String fileName = "";
+ String filePath = AdapterUtils.toPath(uri);
+ if (filePath != null && Files.isRegularFile(Paths.get(filePath))) {
+ fileName = Paths.get(filePath).getFileName().toString();
+ } else if (astUnit.getTypeRoot() != null) {
+ fileName = astUnit.getTypeRoot().getElementName();
+ }
+
+ if (StringUtils.isNotBlank(fileName)) {
+ String[] extensions = JavaCore.getJavaLikeExtensions();
+ for (String extension : extensions) {
+ if (fileName.endsWith("." + extension)) {
+ return fileName.substring(0, fileName.length() - 1 - extension.length());
+ }
+ }
+ }
+
+ return fileName;
+ }
+
private BreakpointLocation[] getInlineBreakpointLocations(final CompilationUnit astUnit, int sourceLine) {
List locations = new ArrayList<>();
// The starting position of each line is the default breakpoint location for
diff --git a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/ResolveMainClassHandler.java b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/ResolveMainClassHandler.java
index f70d0c044..38ad1532b 100644
--- a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/ResolveMainClassHandler.java
+++ b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/ResolveMainClassHandler.java
@@ -43,6 +43,7 @@
import org.eclipse.jdt.core.search.SearchParticipant;
import org.eclipse.jdt.core.search.SearchPattern;
import org.eclipse.jdt.core.search.SearchRequestor;
+import org.eclipse.jdt.internal.core.SourceMethod;
import org.eclipse.jdt.ls.core.internal.ProjectUtils;
import org.eclipse.jdt.ls.core.internal.ResourceUtils;
import org.eclipse.jdt.ls.core.internal.managers.ProjectsManager;
@@ -101,8 +102,7 @@ private List resolveMainClassUnderPaths(List parentPaths)
// Limit to search main method from source code only.
IJavaSearchScope searchScope = SearchEngine.createJavaSearchScope(ProjectUtils.getJavaProjects(),
IJavaSearchScope.REFERENCED_PROJECTS | IJavaSearchScope.SOURCES);
- SearchPattern pattern = SearchPattern.createPattern("main(String[]) void", IJavaSearchConstants.METHOD,
- IJavaSearchConstants.DECLARATIONS, SearchPattern.R_CASE_SENSITIVE | SearchPattern.R_EXACT_MATCH);
+ SearchPattern pattern = createMainMethodSearchPattern();
final List res = new ArrayList<>();
SearchRequestor requestor = new SearchRequestor() {
@Override
@@ -110,40 +110,36 @@ public void acceptSearchMatch(SearchMatch match) {
Object element = match.getElement();
if (element instanceof IMethod) {
IMethod method = (IMethod) element;
- try {
- if (method.isMainMethod()) {
- IResource resource = method.getResource();
- if (resource != null) {
- IProject project = resource.getProject();
- if (project != null) {
- String mainClass = method.getDeclaringType().getFullyQualifiedName();
- IJavaProject javaProject = JdtUtils.getJavaProject(project);
- if (javaProject != null) {
- String moduleName = JdtUtils.getModuleName(javaProject);
- if (moduleName != null) {
- mainClass = moduleName + "/" + mainClass;
- }
+ if (isMainMethod(method)) {
+ IResource resource = method.getResource();
+ if (resource != null) {
+ IProject project = resource.getProject();
+ if (project != null) {
+ String mainClass = method.getDeclaringType().getFullyQualifiedName();
+ IJavaProject javaProject = JdtUtils.getJavaProject(project);
+ if (javaProject != null) {
+ String moduleName = JdtUtils.getModuleName(javaProject);
+ if (moduleName != null) {
+ mainClass = moduleName + "/" + mainClass;
}
- String projectName = ProjectsManager.DEFAULT_PROJECT_NAME.equals(project.getName()) ? null : project.getName();
- if (parentPaths.isEmpty()
- || ResourceUtils.isContainedIn(project.getLocation(), parentPaths)
- || isContainedInInvisibleProject(project, parentPaths)) {
- String filePath = null;
-
- if (match.getResource() instanceof IFile) {
- try {
- filePath = match.getResource().getLocation().toOSString();
- } catch (Exception ex) {
- // ignore
- }
+ }
+ String projectName = ProjectsManager.DEFAULT_PROJECT_NAME.equals(project.getName()) ? null : project.getName();
+ if (parentPaths.isEmpty()
+ || ResourceUtils.isContainedIn(project.getLocation(), parentPaths)
+ || isContainedInInvisibleProject(project, parentPaths)) {
+ String filePath = null;
+
+ if (match.getResource() instanceof IFile) {
+ try {
+ filePath = match.getResource().getLocation().toOSString();
+ } catch (Exception ex) {
+ // ignore
}
- res.add(new ResolutionItem(mainClass, projectName, filePath));
}
+ res.add(new ResolutionItem(mainClass, projectName, filePath));
}
}
}
- } catch (JavaModelException e) {
- // ignore
}
}
}
@@ -166,8 +162,7 @@ private List resolveMainClassUnderProject(final String projectNa
IJavaProject javaProject = ProjectUtils.getJavaProject(projectName);
IJavaSearchScope searchScope = SearchEngine.createJavaSearchScope(javaProject == null ? new IJavaProject[0] : new IJavaProject[] {javaProject},
IJavaSearchScope.REFERENCED_PROJECTS | IJavaSearchScope.SOURCES);
- SearchPattern pattern = SearchPattern.createPattern("main(String[]) void", IJavaSearchConstants.METHOD,
- IJavaSearchConstants.DECLARATIONS, SearchPattern.R_CASE_SENSITIVE | SearchPattern.R_EXACT_MATCH);
+ SearchPattern pattern = createMainMethodSearchPattern();
final List res = new ArrayList<>();
SearchRequestor requestor = new SearchRequestor() {
@Override
@@ -175,35 +170,31 @@ public void acceptSearchMatch(SearchMatch match) {
Object element = match.getElement();
if (element instanceof IMethod) {
IMethod method = (IMethod) element;
- try {
- if (method.isMainMethod()) {
- IResource resource = method.getResource();
- if (resource != null) {
- IProject project = resource.getProject();
- if (project != null) {
- String mainClass = method.getDeclaringType().getFullyQualifiedName();
- IJavaProject javaProject = JdtUtils.getJavaProject(project);
- if (javaProject != null) {
- String moduleName = JdtUtils.getModuleName(javaProject);
- if (moduleName != null) {
- mainClass = moduleName + "/" + mainClass;
- }
+ if (isMainMethod(method)) {
+ IResource resource = method.getResource();
+ if (resource != null) {
+ IProject project = resource.getProject();
+ if (project != null) {
+ String mainClass = method.getDeclaringType().getFullyQualifiedName();
+ IJavaProject javaProject = JdtUtils.getJavaProject(project);
+ if (javaProject != null) {
+ String moduleName = JdtUtils.getModuleName(javaProject);
+ if (moduleName != null) {
+ mainClass = moduleName + "/" + mainClass;
}
+ }
- String filePath = null;
- if (match.getResource() instanceof IFile) {
- try {
- filePath = match.getResource().getLocation().toOSString();
- } catch (Exception ex) {
- // ignore
- }
+ String filePath = null;
+ if (match.getResource() instanceof IFile) {
+ try {
+ filePath = match.getResource().getLocation().toOSString();
+ } catch (Exception ex) {
+ // ignore
}
- res.add(new ResolutionItem(mainClass, projectName, filePath));
}
+ res.add(new ResolutionItem(mainClass, projectName, filePath));
}
}
- } catch (JavaModelException e) {
- // ignore
}
}
}
@@ -221,6 +212,29 @@ public void acceptSearchMatch(SearchMatch match) {
return resolutions;
}
+ private SearchPattern createMainMethodSearchPattern() {
+ SearchPattern pattern1 = SearchPattern.createPattern("main(String[]) void", IJavaSearchConstants.METHOD,
+ IJavaSearchConstants.DECLARATIONS, SearchPattern.R_CASE_SENSITIVE | SearchPattern.R_EXACT_MATCH);
+ SearchPattern pattern2 = SearchPattern.createPattern("main() void", IJavaSearchConstants.METHOD,
+ IJavaSearchConstants.DECLARATIONS, SearchPattern.R_CASE_SENSITIVE | SearchPattern.R_EXACT_MATCH);
+ return SearchPattern.createOrPattern(pattern1, pattern2);
+ }
+
+ private boolean isMainMethod(IMethod method) {
+ try {
+ if (method instanceof SourceMethod
+ && ((SourceMethod) method).isMainMethodCandidate()) {
+ return true;
+ }
+
+ return method.isMainMethod();
+ } catch (JavaModelException e) {
+ // do nothing
+ }
+
+ return false;
+ }
+
private boolean isContainedInInvisibleProject(IProject project, Collection rootPaths) {
if (project == null) {
return false;
diff --git a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/ResolveMainMethodHandler.java b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/ResolveMainMethodHandler.java
index a3c61e814..fb8dfc33e 100644
--- a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/ResolveMainMethodHandler.java
+++ b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/ResolveMainMethodHandler.java
@@ -15,6 +15,7 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import java.util.Map;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
@@ -30,7 +31,11 @@
import org.eclipse.jdt.core.ISourceRange;
import org.eclipse.jdt.core.ISourceReference;
import org.eclipse.jdt.core.IType;
+import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
+import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
+import org.eclipse.jdt.internal.core.SourceMethod;
import org.eclipse.jdt.ls.core.internal.JDTUtils;
import org.eclipse.jdt.ls.core.internal.handlers.DocumentLifeCycleHandler;
import org.eclipse.jdt.ls.core.internal.managers.ProjectsManager;
@@ -104,16 +109,58 @@ private static List searchMainMethods(ICompilationUnit compilationUnit)
* Returns the main method defined in the type.
*/
public static IMethod getMainMethod(IType type) throws JavaModelException {
+ boolean allowInstanceMethod = isInstanceMainMethodSupported(type);
+ List methods = new ArrayList<>();
for (IMethod method : type.getMethods()) {
- // Have at most one main method in the member methods of the type.
+ if (method instanceof SourceMethod
+ && ((SourceMethod) method).isMainMethodCandidate()) {
+ methods.add(method);
+ }
+
if (method.isMainMethod()) {
- return method;
+ methods.add(method);
+ }
+
+ if (!allowInstanceMethod && !methods.isEmpty()) {
+ return methods.get(0);
}
}
+ if (!methods.isEmpty()) {
+ methods.sort((method1, method2) -> {
+ return getMainMethodPriority(method1) - getMainMethodPriority(method2);
+ });
+
+ return methods.get(0);
+ }
+
return null;
}
+ private static boolean isInstanceMainMethodSupported(IType type) {
+ Map options = type.getJavaProject().getOptions(true);
+ return CompilerOptions.versionToJdkLevel(options.get(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM)) >= ClassFileConstants.JDK21;
+ }
+
+ private static int getMainMethodPriority(IMethod method) {
+ int flags = 0;
+ try {
+ flags = method.getFlags();
+ } catch (JavaModelException e) {
+ // do nothing
+ }
+ String[] params = method.getParameterTypes();
+ if (Flags.isStatic(flags) && params.length == 1) {
+ return 1;
+ } else if (Flags.isStatic(flags)) {
+ return 2;
+ } else if (params.length == 1) {
+ return 3;
+ }
+
+ return 4;
+ }
+
private static List getPotentialMainClassTypes(ICompilationUnit compilationUnit) throws JavaModelException {
List result = new ArrayList<>();
IType[] topLevelTypes = compilationUnit.getTypes();
diff --git a/com.microsoft.java.debug.repository/category.xml b/com.microsoft.java.debug.repository/category.xml
index 53e8bf963..fc6ff6a62 100644
--- a/com.microsoft.java.debug.repository/category.xml
+++ b/com.microsoft.java.debug.repository/category.xml
@@ -1,6 +1,6 @@
-
+
diff --git a/com.microsoft.java.debug.repository/pom.xml b/com.microsoft.java.debug.repository/pom.xml
index 68ff9fc42..3d5537f13 100644
--- a/com.microsoft.java.debug.repository/pom.xml
+++ b/com.microsoft.java.debug.repository/pom.xml
@@ -4,7 +4,7 @@
com.microsoft.java
java-debug-parent
- 0.51.1
+ 0.52.0
com.microsoft.java.debug.repository
eclipse-repository
diff --git a/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target b/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target
index 828da98a2..a52901d01 100644
--- a/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target
+++ b/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target
@@ -14,13 +14,18 @@
-
-
+
+
+
+
+
+
+
-
+
@@ -31,7 +36,7 @@
-
+
diff --git a/com.microsoft.java.debug.target/pom.xml b/com.microsoft.java.debug.target/pom.xml
index 6977f1831..e4ee29b92 100644
--- a/com.microsoft.java.debug.target/pom.xml
+++ b/com.microsoft.java.debug.target/pom.xml
@@ -4,7 +4,7 @@
com.microsoft.java
java-debug-parent
- 0.51.1
+ 0.52.0
com.microsoft.java.debug.tp
${base.name} :: Target Platform
diff --git a/pom.xml b/pom.xml
index b039fe1c1..f2e4d0eef 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,12 +6,12 @@
${base.name} :: Parent
The Java Debug Server is an implementation of Visual Studio Code (VSCode) Debug Protocol. It can be used in Visual Studio Code to debug Java programs.
https://github.com/Microsoft/java-debug
- 0.51.1
+ 0.52.0
pom
Java Debug Server for Visual Studio Code
UTF-8
- 4.0.5
+ 4.0.6
${basedir}