Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Deprecated]Improve the standalone java file support #843

Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
/*******************************************************************************
* Copyright (c) 2018 Microsoft Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Microsoft Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.ls.core.internal;

import java.net.URI;
import java.nio.file.Paths;
import java.util.List;
import java.util.stream.Collectors;

import org.codehaus.plexus.util.StringUtils;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;

public class JDTStandaloneFileUtils {
public static final String PATH_SEPARATOR = "/";
public static final String PERIOD = ".";
public static final String SRC = "src";

public static ICompilationUnit getFakeCompilationUnit(URI uri, IProgressMonitor monitor) {
if (uri == null || !"file".equals(uri.getScheme()) || !uri.getPath().endsWith(".java")) {
return null;
}
java.nio.file.Path path = Paths.get(uri);
//Only support existing standalone java files
if (!java.nio.file.Files.isReadable(path)) {
return null;
}

IPath workspaceRoot = ProjectUtils.findBelongedWorkspaceRoot(ResourceUtils.filePathFromURI(uri.toString()));
if (workspaceRoot != null) {
return getFakeCompilationUnitForInsideStandaloneFile(uri, workspaceRoot, monitor);
} else {
return getFakeCompilationUnitForExternalStandaloneFile(uri, monitor);
}
}

private static ICompilationUnit getFakeCompilationUnitForExternalStandaloneFile(URI uri, IProgressMonitor monitor) {
IProject project = JavaLanguageServerPlugin.getProjectsManager().getDefaultProject();
if (project == null || !project.isAccessible()) {
return null;
}

IJavaProject javaProject = JavaCore.create(project);
String packageName = JDTUtils.getPackageName(javaProject, uri);
java.nio.file.Path path = Paths.get(uri);
String fileName = path.getName(path.getNameCount() - 1).toString();
String packagePath = packageName.replace(PERIOD, PATH_SEPARATOR);
IPath filePath = new Path(SRC).append(packagePath).append(fileName);
final IFile file = project.getFile(filePath);
if (!file.isLinked()) {
try {
JDTUtils.createFolders(file.getParent(), monitor);
file.createLink(uri, IResource.REPLACE, monitor);
} catch (CoreException e) {
String errMsg = "Failed to create linked resource from " + uri + " to " + project.getName();
JavaLanguageServerPlugin.logException(errMsg, e);
}
}

if (file.isLinked()) {
return (ICompilationUnit) JavaCore.create(file, javaProject);
}

return null;
}

private static ICompilationUnit getFakeCompilationUnitForInsideStandaloneFile(URI uri, IPath workspaceRoot, IProgressMonitor monitor) {
java.nio.file.Path path = Paths.get(uri);
if (!ProjectUtils.getVisibleProjects(workspaceRoot).isEmpty()) {
return null;
}

// Try to resolve the CompilationUnit from the workspace root associated invisible project.
String invisibleProjectName = ProjectUtils.getWorkspaceInvisibleProjectName(workspaceRoot);
IProject invisibleProject = ResourcesPlugin.getWorkspace().getRoot().getProject(invisibleProjectName);
if (!invisibleProject.exists()) {
try {
invisibleProject = ProjectUtils.createInvisibleProjectIfNotExist(workspaceRoot);
IJavaProject javaProject = JavaCore.create(invisibleProject);
IFolder workspaceLinkFolder = invisibleProject.getFolder(ProjectUtils.WORKSPACE_LINK);
try {
// Mark the containing folder of the opened file as Source Root of the invisible project.
String packageName = JDTUtils.getPackageName(javaProject, uri);
IPath containerPath = getContainingFolderPath(path, packageName);
IPath containerRelativePath = new Path("");
if (workspaceRoot.isPrefixOf(containerPath)) {
containerRelativePath = containerPath.makeRelativeTo(workspaceRoot);
}
IPath sourcePath = containerRelativePath.isEmpty() ? workspaceLinkFolder.getFullPath() : workspaceLinkFolder.getFolder(containerRelativePath).getFullPath();
List<IProject> subProjects = ProjectUtils.getVisibleProjects(workspaceRoot);
List<IPath> subProjectPaths = subProjects.stream().map(project -> {
IPath relativePath = project.getLocation().makeRelativeTo(workspaceRoot);
return workspaceLinkFolder.getFolder(relativePath).getFullPath();
}).collect(Collectors.toList());
ProjectUtils.addSourcePath(sourcePath, subProjectPaths.toArray(new IPath[0]), javaProject);
} catch (JavaModelException e) {
String errMsg = "Failed to update classpath to the invisible project " + invisibleProject.getName() + " .";
JavaLanguageServerPlugin.logException(errMsg, e);
return null;
}

IPath fileRelativePath = ResourceUtils.filePathFromURI(uri.toString()).makeRelativeTo(workspaceRoot);
final IFile file = workspaceLinkFolder.getFile(fileRelativePath);
return (ICompilationUnit) JavaCore.create(file, javaProject);
} catch (CoreException e) {
JavaLanguageServerPlugin.logException("Failed to create the invisible project.", e);
return null;
}
}

return null;
}

private static IPath getContainingFolderPath(java.nio.file.Path filePath, String packageName) {
String packagePath = packageName.replace(PERIOD, PATH_SEPARATOR);
java.nio.file.Path sourcePath = filePath.getParent();
if (StringUtils.isNotBlank(packagePath) && sourcePath.endsWith(Paths.get(packagePath))) {
int packageCount = packageName.split("\\" + PERIOD).length;
while (packageCount > 0) {
sourcePath = sourcePath.getParent();
packageCount--;
}
}

return ResourceUtils.filePathFromURI(sourcePath.toUri().toString());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import java.net.URISyntaxException;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Set;
Expand All @@ -27,14 +28,12 @@
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.URIUtil;
import org.eclipse.jdt.core.IAnnotatable;
Expand Down Expand Up @@ -73,7 +72,6 @@
import org.eclipse.jdt.launching.environments.IExecutionEnvironmentsManager;
import org.eclipse.jdt.ls.core.internal.handlers.JsonRpcHelpers;
import org.eclipse.jdt.ls.core.internal.managers.ContentProviderManager;
import org.eclipse.jdt.ls.core.internal.managers.ProjectsManager;
import org.eclipse.jdt.ls.core.internal.preferences.PreferenceManager;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.Document;
Expand All @@ -96,6 +94,7 @@ public final class JDTUtils {
public static final String PERIOD = ".";
public static final String SRC = "src";
private static final String JDT_SCHEME = "jdt";
private static final String[][] SRC_PREFIXES = new String[][] { { "src", "main", "java" }, { "src", "test", "java" }, { "src" } };
//Code generators known to cause problems
private static Set<String> SILENCED_CODEGENS = Collections.singleton("lombok");

Expand Down Expand Up @@ -139,7 +138,7 @@ public static ICompilationUnit resolveCompilationUnit(URI uri) {
}
}
if (resource == null) {
return getFakeCompilationUnit(uri, new NullProgressMonitor());
return JDTStandaloneFileUtils.getFakeCompilationUnit(uri, new NullProgressMonitor());
}
//the resource is not null but no compilation unit could be created (eg. project not ready yet)
return null;
Expand Down Expand Up @@ -181,43 +180,6 @@ public static IPackageFragment resolvePackage(URI uri) {
return null;
}

static ICompilationUnit getFakeCompilationUnit(URI uri, IProgressMonitor monitor) {
if (uri == null || !"file".equals(uri.getScheme()) || !uri.getPath().endsWith(".java")) {
return null;
}
java.nio.file.Path path = Paths.get(uri);
//Only support existing standalone java files
if (!java.nio.file.Files.isReadable(path)) {
return null;
}

IProject project = JavaLanguageServerPlugin.getProjectsManager().getDefaultProject();
if (project == null || !project.isAccessible()) {
return null;
}
IJavaProject javaProject = JavaCore.create(project);

String packageName = getPackageName(javaProject, uri);
String fileName = path.getName(path.getNameCount() - 1).toString();
String packagePath = packageName.replace(PERIOD, PATH_SEPARATOR);

IPath filePath = new Path(SRC).append(packagePath).append(fileName);
final IFile file = project.getFile(filePath);
if (!file.isLinked()) {
try {
createFolders(file.getParent(), monitor);
file.createLink(uri, IResource.REPLACE, monitor);
} catch (CoreException e) {
String errMsg = "Failed to create linked resource from " + uri + " to " + project.getName();
JavaLanguageServerPlugin.logException(errMsg, e);
}
}
if (file.isLinked()) {
return (ICompilationUnit) JavaCore.create(file, javaProject);
}
return null;
}

public static void createFolders(IContainer folder, IProgressMonitor monitor) throws CoreException {
if (!folder.exists() && folder instanceof IFolder) {
IContainer parent = folder.getParent();
Expand All @@ -234,30 +196,46 @@ public static String getPackageName(IJavaProject javaProject, URI uri) {
File file = ResourceUtils.toFile(uri);
//FIXME need to determine actual charset from file
String content = Files.toString(file, Charsets.UTF_8);
if (content.isEmpty() && javaProject != null && ProjectsManager.DEFAULT_PROJECT_NAME.equals(javaProject.getProject().getName())) {
java.nio.file.Path path = Paths.get(uri);
java.nio.file.Path parent = path;
while (parent.getParent() != null && parent.getParent().getNameCount() > 0) {
parent = parent.getParent();
String name = parent.getName(parent.getNameCount() - 1).toString();
if (SRC.equals(name)) {
String pathStr = path.getParent().toString();
if (pathStr.length() > parent.toString().length()) {
pathStr = pathStr.substring(parent.toString().length() + 1);
pathStr = pathStr.replace(PATH_SEPARATOR, PERIOD);
return pathStr;
}
}
}
if (content.isEmpty() && javaProject != null && !ProjectUtils.isVisibleProject(javaProject.getProject())) {
return guessPackageNameFromPath(uri);
} else {
return getPackageName(javaProject, content);
}
} catch (IOException e) {
JavaLanguageServerPlugin.logException("Failed to read package name from "+uri, e);
JavaLanguageServerPlugin.logException("Failed to read package name from " + uri, e);
}

return "";
}

private static String guessPackageNameFromPath(URI uri) {
java.nio.file.Path javaPath = Paths.get(uri);
IPath containerPath = ResourceUtils.filePathFromURI(javaPath.getParent().toUri().toString());
IPath workspaceRoot = ProjectUtils.findBelongedWorkspaceRoot(containerPath);
if (workspaceRoot == null) {
List<String> segments = Arrays.asList(containerPath.segments());
for (int i = 0; i < SRC_PREFIXES.length; i++) {
int index = Collections.lastIndexOfSubList(segments, Arrays.asList(SRC_PREFIXES[i]));
if (index > -1) {
return String.join(PERIOD, segments.subList(index + SRC_PREFIXES[i].length, segments.size()));
}
}

return "";
} else {
IPath relativePath = containerPath.makeRelativeTo(workspaceRoot);
List<String> segments = Arrays.asList(relativePath.segments());
for (int i = 0; i < SRC_PREFIXES.length; i++) {
int index = Collections.indexOfSubList(segments, Arrays.asList(SRC_PREFIXES[i]));
if (index > -1) {
return String.join(PERIOD, segments.subList(index + SRC_PREFIXES[i].length, segments.size()));
}
}

return String.join(PERIOD, segments);
}
}

public static String getPackageName(IJavaProject javaProject, String fileContent) {
if (fileContent == null) {
return "";
Expand All @@ -270,10 +248,9 @@ public static String getPackageName(IJavaProject javaProject, String fileContent
parser.setSource(source);
CompilationUnit ast = (CompilationUnit) parser.createAST(null);
PackageDeclaration pkg = ast.getPackage();
return (pkg == null || pkg.getName() == null)?"":pkg.getName().getFullyQualifiedName();
return (pkg == null || pkg.getName() == null) ? "" : pkg.getName().getFullyQualifiedName();
}


/**
* Given the uri returns a {@link IClassFile}.
* May return null if it can not resolve the uri to a
Expand Down Expand Up @@ -595,7 +572,7 @@ public static String toURI(ICompilationUnit cu) {
* @return
*/
public static String getFileURI(IResource resource) {
return ResourceUtils.fixURI(resource.getRawLocationURI());
return ResourceUtils.fixURI(resource.getRawLocationURI() != null ? resource.getRawLocationURI() : resource.getLocationURI());
}

public static IJavaElement findElementAtSelection(ITypeRoot unit, int line, int column, PreferenceManager preferenceManager, IProgressMonitor monitor) throws JavaModelException {
Expand Down
Loading