Skip to content

Patch for user input validation when using commands 'Java: New Project...' and 'Java: New File from Template...'. #405

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

Merged
merged 1 commit into from
Apr 24, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions build.xml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
patches/8260.diff
patches/8280.diff
patches/8289.diff
patches/7893-draft.diff
patches/disable-error-notification.diff
patches/mvn-sh.diff
patches/project-marker-jdk.diff
Expand Down
139 changes: 139 additions & 0 deletions patches/7893-draft.diff
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/LspTemplateUI.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/LspTemplateUI.java
index 891bfa328d..ed80b903a5 100644
--- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/LspTemplateUI.java
+++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/LspTemplateUI.java
@@ -27,6 +27,7 @@ import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
+import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -39,6 +40,7 @@ import java.util.function.Function;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
+import javax.lang.model.SourceVersion;
import org.eclipse.lsp4j.ExecuteCommandParams;
import org.eclipse.lsp4j.MessageParams;
import org.eclipse.lsp4j.MessageType;
@@ -73,14 +75,21 @@ import org.openide.util.Utilities;
"CTL_TemplateUI_SelectGroup=Select Template Type",
"CTL_TemplateUI_SelectTemplate=Select Template",
"CTL_TemplateUI_SelectTarget=Where to put the object?",
- "CTL_TemplateUI_SelectProjectTarget=Specify the project directory",
+ "CTL_TemplateUI_SelectProjectTarget=Specify the new project directory",
"CTL_TemplateUI_SelectPackageName=Package name of your project?",
"CTL_TemplateUI_SelectPackageNameSuggestion=org.yourcompany.yourproject",
"CTL_TemplateUI_SelectName=Name of the object?",
"# {0} - path",
- "ERR_InvalidPath={0} isn't valid folder",
+ "ERR_InvalidPath={0} isn't a valid folder or is read-only",
"# {0} - path",
"ERR_ExistingPath={0} already exists",
+ "# {0} - packageName",
+ "ERR_InvalidPackageName={0} isn't valid package name",
+ "# {0} - path",
+ "ERR_InvalidNewPath={0} isn't a valid path or is read-only",
+ "# {0} - ObjectName",
+ "ERR_InvalidObjectName={0} isn't valid object name"
+
})
final class LspTemplateUI {
/**
@@ -165,8 +174,20 @@ final class LspTemplateUI {
}

private static CompletionStage<String> findPackage(CompletionStage<?> uiBefore, NbCodeLanguageClient client) {
- return uiBefore.thenCompose((__) ->
- client.showInputBox(new ShowInputBoxParams(Bundle.CTL_TemplateUI_SelectPackageName(), Bundle.CTL_TemplateUI_SelectPackageNameSuggestion()))
+ return uiBefore.thenCompose((__) -> {
+ class ValidatePackageName implements Function<String, CompletionStage<String>> {
+
+ @Override
+ public CompletionStage<String> apply(String packageName) {
+ if (!SourceVersion.isName(packageName)) {
+ client.showMessage(new MessageParams(MessageType.Error, Bundle.ERR_InvalidPackageName(packageName)));
+ return client.showInputBox(new ShowInputBoxParams(Bundle.CTL_TemplateUI_SelectPackageName(), Bundle.CTL_TemplateUI_SelectPackageNameSuggestion())).thenCompose(this);
+ }
+ return CompletableFuture.completedFuture(packageName);
+ }
+ }
+ return client.showInputBox(new ShowInputBoxParams(Bundle.CTL_TemplateUI_SelectPackageName(), Bundle.CTL_TemplateUI_SelectPackageNameSuggestion())).thenCompose(new ValidatePackageName());
+ }
);
}

@@ -188,8 +209,9 @@ final class LspTemplateUI {
if (path == null) {
throw raise(RuntimeException.class, new UserCancelException(path));
}
- FileObject fo = FileUtil.toFileObject(new File(path));
- if (fo == null || !fo.isFolder()) {
+ File target = new File(path);
+ FileObject fo = FileUtil.toFileObject(target);
+ if (!target.canWrite() || fo == null || !fo.isFolder()) {
client.showMessage(new MessageParams(MessageType.Error, Bundle.ERR_InvalidPath(path)));
return client.showInputBox(new ShowInputBoxParams(Bundle.CTL_TemplateUI_SelectTarget(), suggestion.getPrimaryFile().getPath())).thenCompose(this);
}
@@ -202,7 +224,7 @@ final class LspTemplateUI {

private static CompletionStage<Pair<DataFolder, String>> findTargetAndNameForProject(CompletionStage<DataObject> findTemplate, NbCodeLanguageClient client) {
return findTemplate.thenCompose(__ -> client.workspaceFolders()).thenCompose(folders -> {
- class VerifyNonExistingFolder implements Function<String, CompletionStage<Pair<DataFolder,String>>> {
+ class VerifyNewFolderCreation implements Function<String, CompletionStage<Pair<DataFolder,String>>> {
@Override
public CompletionStage<Pair<DataFolder,String>> apply(String path) {
if (path == null) {
@@ -215,12 +237,14 @@ final class LspTemplateUI {
}
targetPath.getParentFile().mkdirs();
FileObject fo = FileUtil.toFileObject(targetPath.getParentFile());
- if (fo == null || !fo.isFolder()) {
+ if (fo == null || !fo.isFolder() || !targetPath.getParentFile().canWrite() || !SourceVersion.isName(targetPath.getName())) {
+ client.showMessage(new MessageParams(MessageType.Error, Bundle.ERR_InvalidNewPath(path)));
+ return client.showInputBox(new ShowInputBoxParams(Bundle.CTL_TemplateUI_SelectProjectTarget(), suggestWorkspaceRoot(folders))).thenCompose(this);
}
return CompletableFuture.completedFuture(Pair.of(DataFolder.findFolder(fo), targetPath.getName()));
}
}
- return client.showInputBox(new ShowInputBoxParams(Bundle.CTL_TemplateUI_SelectProjectTarget(), suggestWorkspaceRoot(folders))).thenCompose(new VerifyNonExistingFolder());
+ return client.showInputBox(new ShowInputBoxParams(Bundle.CTL_TemplateUI_SelectProjectTarget(), suggestWorkspaceRoot(folders))).thenCompose(new VerifyNewFolderCreation());
});
}

@@ -229,9 +253,21 @@ final class LspTemplateUI {
FileObject template = desc.getTemplate();
Object handler = template.getAttribute(FileBuilder.ATTR_TEMPLATE_HANDLER);
if (handler == null) {
- return client.showInputBox(new ShowInputBoxParams(Bundle.CTL_TemplateUI_SelectName(), desc.getProposedName())).thenApply(name -> {
- return name != null ? builder.name(name) : null;
- });
+ class ValidateJavaObjectName implements Function<String, CompletionStage<String>> {
+
+ @Override
+ public CompletionStage<String> apply(String name) {
+ if (!SourceVersion.isName(name)) {
+ client.showMessage(new MessageParams(MessageType.Error, Bundle.ERR_InvalidObjectName(name)));
+ return client.showInputBox(new ShowInputBoxParams(Bundle.CTL_TemplateUI_SelectName(), desc.getProposedName())).thenCompose(this);
+ }
+ return CompletableFuture.completedFuture(name);
+ }
+ }
+ boolean isJavaTemplate = "text/x-java".equals(FileUtil.getMIMEType(template));
+ CompletionStage<String> userInput = client.showInputBox(new ShowInputBoxParams(Bundle.CTL_TemplateUI_SelectName(), desc.getProposedName()));
+ if(isJavaTemplate) userInput = userInput.thenCompose(new ValidateJavaObjectName());
+ return userInput.thenApply(name -> {return name != null ? builder.name(name) : null;});
}
return CompletableFuture.completedFuture(builder);
}
@@ -242,7 +278,7 @@ final class LspTemplateUI {
suggestion = Utilities.toFile(new URI(folders.get(0).getUri())).getParent();
} catch (URISyntaxException ex) {
}
- return suggestion;
+ return Paths.get(suggestion,"ProjectName").toString();
}

private static CompletionStage<DataObject> findTemplate(DataFolder templates, NbCodeLanguageClient client, ExecuteCommandParams params) {