From d78752e747e5497fbe3ba40027ffdccf975bfda5 Mon Sep 17 00:00:00 2001 From: BoykoAlex Date: Wed, 4 May 2022 13:13:28 -0400 Subject: [PATCH] Check dependency versions for java diagnostics --- .../commons/java/SpringProjectUtil.java | 40 ++++++++++++++++- .../ide/vscode/commons/java/Version.java | 44 +++++++++++++++++++ .../handlers/AnnotationParamReconciler.java | 5 ++- .../java/handlers/AnnotationReconciler.java | 13 +++++- .../AutowiredConstructorReconciler.java | 34 ++++++++------ .../handlers/BootJavaReconcileEngine.java | 20 ++++----- 6 files changed, 126 insertions(+), 30 deletions(-) create mode 100644 headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/java/Version.java diff --git a/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/java/SpringProjectUtil.java b/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/java/SpringProjectUtil.java index a25f64b43..331e8a029 100644 --- a/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/java/SpringProjectUtil.java +++ b/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/java/SpringProjectUtil.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017, 2020 Pivotal, Inc. + * Copyright (c) 2017, 2022 Pivotal, Inc. * 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 @@ -21,12 +21,14 @@ import org.slf4j.LoggerFactory; public class SpringProjectUtil { + private static final String VERION_PATTERN_STR = "(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?"; + public static final Logger log = LoggerFactory.getLogger(SpringProjectUtil.class); private static final Pattern MAJOR_MINOR_VERSION = Pattern.compile("(0|[1-9]\\d*)\\.(0|[1-9]\\d*)"); // Pattern copied from https://semver.org/ - private static final Pattern VERSION = Pattern.compile("(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?"); + private static final Pattern VERSION = Pattern.compile(VERION_PATTERN_STR); private static final Pattern SPRING_NAME = Pattern.compile("([a-z]+)(-[a-z]+)*"); @@ -107,4 +109,38 @@ public class SpringProjectUtil { String name = cpe.getName(); return name.startsWith(libNamePrefix) && (!onlyLibs || name.endsWith(".jar")); } + + public static Version getDependencyVersion(IJavaProject jp, String dependency) { + try { + for (File f : IClasspathUtil.getBinaryRoots(jp.getClasspath(), (cpe) -> !cpe.isSystem())) { + String fileName = f.getName(); + if (fileName.startsWith(dependency)) { + StringBuilder sb = new StringBuilder(); + sb.append('^'); + sb.append(dependency); + sb.append('-'); + sb.append(VERION_PATTERN_STR); + sb.append(".jar$"); + Pattern pattern = Pattern.compile(sb.toString()); + + Matcher matcher = pattern.matcher(fileName); + if (matcher.find() && matcher.groupCount() == 5) { + String major = matcher.group(1); + String minor = matcher.group(2); + String patch = matcher.group(3); + String qualifier = matcher.group(4); + return new Version( + Integer.parseInt(major), + Integer.parseInt(minor), + Integer.parseInt(patch), + qualifier + ); + } + } + } + } catch (Exception e) { + log.error("", e); + } + return null; + } } diff --git a/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/java/Version.java b/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/java/Version.java new file mode 100644 index 000000000..810892bd2 --- /dev/null +++ b/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/java/Version.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright (c) 2022 VMware, Inc. + * 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 + * https://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VMware, Inc. - initial API and implementation + *******************************************************************************/ +package org.springframework.ide.vscode.commons.java; + +public final class Version { + + private int major; + private int minor; + private int patch; + private String qualifier; + + public Version(int major, int minor, int patch, String qualifier) { + super(); + this.major = major; + this.minor = minor; + this.patch = patch; + this.qualifier = qualifier; + } + + public int getMajor() { + return major; + } + + public int getMinor() { + return minor; + } + + public int getPatch() { + return patch; + } + + public String getQualifier() { + return qualifier; + } + +} diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/AnnotationParamReconciler.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/AnnotationParamReconciler.java index 5b5c95cfb..545c52ce4 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/AnnotationParamReconciler.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/AnnotationParamReconciler.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2020 Pivotal, Inc. + * Copyright (c) 2020, 2022 Pivotal, Inc. * 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 @@ -21,6 +21,7 @@ import org.eclipse.jdt.core.dom.NormalAnnotation; import org.eclipse.jdt.core.dom.SingleMemberAnnotation; import org.eclipse.jdt.core.dom.StringLiteral; import org.springframework.ide.vscode.boot.java.annotations.AnnotationHierarchies; +import org.springframework.ide.vscode.commons.java.IJavaProject; import org.springframework.ide.vscode.commons.languageserver.reconcile.IProblemCollector; import org.springframework.ide.vscode.commons.util.text.IDocument; @@ -44,7 +45,7 @@ public class AnnotationParamReconciler implements AnnotationReconciler { this.reconciler = reconciler; } - public void visit(IDocument doc, Annotation node, ITypeBinding typeBinding, IProblemCollector problemCollector) { + public void visit(IJavaProject project, IDocument doc, Annotation node, ITypeBinding typeBinding, IProblemCollector problemCollector) { if (node instanceof SingleMemberAnnotation) { visitSingleMemberAnnotation((SingleMemberAnnotation) node, typeBinding, problemCollector); } else if (node instanceof NormalAnnotation) { diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/AnnotationReconciler.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/AnnotationReconciler.java index e90c9b173..b627829c4 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/AnnotationReconciler.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/AnnotationReconciler.java @@ -1,12 +1,23 @@ +/******************************************************************************* + * Copyright (c) 2022 VMware, Inc. + * 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 + * https://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VMware, Inc. - initial API and implementation + *******************************************************************************/ package org.springframework.ide.vscode.boot.java.handlers; import org.eclipse.jdt.core.dom.Annotation; import org.eclipse.jdt.core.dom.ITypeBinding; +import org.springframework.ide.vscode.commons.java.IJavaProject; import org.springframework.ide.vscode.commons.languageserver.reconcile.IProblemCollector; import org.springframework.ide.vscode.commons.util.text.IDocument; public interface AnnotationReconciler { - void visit(IDocument doc, Annotation node, ITypeBinding typeBinding, IProblemCollector problemCollector); + void visit(IJavaProject project, IDocument doc, Annotation node, ITypeBinding typeBinding, IProblemCollector problemCollector); } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/AutowiredConstructorReconciler.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/AutowiredConstructorReconciler.java index 8b3be18fe..5892f92a2 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/AutowiredConstructorReconciler.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/AutowiredConstructorReconciler.java @@ -19,6 +19,9 @@ import org.eclipse.jdt.core.dom.ITypeBinding; import org.eclipse.jdt.core.dom.MethodDeclaration; import org.springframework.ide.vscode.boot.java.Annotations; import org.springframework.ide.vscode.boot.java.SpringJavaProblemType; +import org.springframework.ide.vscode.commons.java.IJavaProject; +import org.springframework.ide.vscode.commons.java.SpringProjectUtil; +import org.springframework.ide.vscode.commons.java.Version; import org.springframework.ide.vscode.commons.languageserver.quickfix.Quickfix.QuickfixData; import org.springframework.ide.vscode.commons.languageserver.quickfix.QuickfixRegistry; import org.springframework.ide.vscode.commons.languageserver.quickfix.QuickfixType; @@ -37,19 +40,24 @@ public class AutowiredConstructorReconciler implements AnnotationReconciler { } @Override - public void visit(IDocument doc, Annotation node, ITypeBinding typeBinding, IProblemCollector problemCollector) { - getSingleAutowiredConstructorDeclaringType(node, typeBinding).ifPresent(type -> { - ReconcileProblemImpl problem = new ReconcileProblemImpl(SpringJavaProblemType.JAVA_AUTOWIRED_CONSTRUCTOR, "Unnecesary @Autowired", node.getStartPosition(), node.getLength()); - QuickfixType quickfixType = quickfixRegistry.getQuickfixType(AutowiredConstructorReconciler.REMOVE_UNNECESSARY_AUTOWIRED_FROM_CONSTRUCTOR); - if (quickfixType != null) { - problem.addQuickfix(new QuickfixData<>( - quickfixType, - List.of(doc.getUri(), type.getQualifiedName()), - "Remove unnecessary @Autowired" - )); - } - problemCollector.accept(problem); - }); + public void visit(IJavaProject project, IDocument doc, Annotation node, ITypeBinding typeBinding, IProblemCollector problemCollector) { + Version version = SpringProjectUtil.getDependencyVersion(project, "spring-boot"); + + if (version.getMajor() >= 2) { + getSingleAutowiredConstructorDeclaringType(node, typeBinding).ifPresent(type -> { + ReconcileProblemImpl problem = new ReconcileProblemImpl(SpringJavaProblemType.JAVA_AUTOWIRED_CONSTRUCTOR, "Unnecesary @Autowired", node.getStartPosition(), node.getLength()); + QuickfixType quickfixType = quickfixRegistry.getQuickfixType(AutowiredConstructorReconciler.REMOVE_UNNECESSARY_AUTOWIRED_FROM_CONSTRUCTOR); + if (quickfixType != null) { + problem.addQuickfix(new QuickfixData<>( + quickfixType, + List.of(doc.getUri(), type.getQualifiedName()), + "Remove unnecessary @Autowired" + )); + } + problemCollector.accept(problem); + }); + } + } static Optional getSingleAutowiredConstructorDeclaringType(Annotation a, ITypeBinding type) { diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/BootJavaReconcileEngine.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/BootJavaReconcileEngine.java index be8ab09f6..a3a01770e 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/BootJavaReconcileEngine.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/BootJavaReconcileEngine.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2016, 2020 Pivotal, Inc. + * Copyright (c) 2016, 2022 Pivotal, Inc. * 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 @@ -20,8 +20,6 @@ import org.eclipse.jdt.core.dom.MarkerAnnotation; import org.eclipse.jdt.core.dom.NormalAnnotation; import org.eclipse.jdt.core.dom.SingleMemberAnnotation; import org.eclipse.lsp4j.TextDocumentIdentifier; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.ide.vscode.boot.java.utils.CompilationUnitCache; import org.springframework.ide.vscode.boot.java.value.Constants; import org.springframework.ide.vscode.commons.java.IJavaProject; @@ -50,8 +48,6 @@ public class BootJavaReconcileEngine implements IReconcileEngine { public static final String SPRING_CONDITIONAL_ON_EXPRESSION = "org.springframework.boot.autoconfigure.condition.ConditionalOnExpression"; - private static final Logger log = LoggerFactory.getLogger(BootJavaReconcileEngine.class); - private final JavaProjectFinder projectFinder; private final CompilationUnitCache compilationUnitCache; private final AnnotationReconciler[] reconcilers; @@ -111,7 +107,7 @@ public class BootJavaReconcileEngine implements IReconcileEngine { compilationUnitCache.withCompilationUnit(project, uri, cu -> { if (cu != null) { - reconcileAST(doc, cu, problemCollector); + reconcileAST(project, doc, cu, problemCollector); } return null; @@ -123,13 +119,13 @@ public class BootJavaReconcileEngine implements IReconcileEngine { } } - private void reconcileAST(IDocument doc, CompilationUnit cu, IProblemCollector problemCollector) { + private void reconcileAST(IJavaProject project, IDocument doc, CompilationUnit cu, IProblemCollector problemCollector) { cu.accept(new ASTVisitor() { @Override public boolean visit(SingleMemberAnnotation node) { try { - visitAnnotation(doc, node, problemCollector); + visitAnnotation(project, doc, node, problemCollector); } catch (Exception e) { } @@ -139,7 +135,7 @@ public class BootJavaReconcileEngine implements IReconcileEngine { @Override public boolean visit(NormalAnnotation node) { try { - visitAnnotation(doc, node, problemCollector); + visitAnnotation(project, doc, node, problemCollector); } catch (Exception e) { } @@ -149,7 +145,7 @@ public class BootJavaReconcileEngine implements IReconcileEngine { @Override public boolean visit(MarkerAnnotation node) { try { - visitAnnotation(doc, node, problemCollector); + visitAnnotation(project, doc, node, problemCollector); } catch (Exception e) { } @@ -159,12 +155,12 @@ public class BootJavaReconcileEngine implements IReconcileEngine { }); } - protected void visitAnnotation(IDocument doc, Annotation node, IProblemCollector problemCollector) { + protected void visitAnnotation(IJavaProject project, IDocument doc, Annotation node, IProblemCollector problemCollector) { ITypeBinding typeBinding = node.resolveTypeBinding(); if (typeBinding != null) { for (int i = 0; i < reconcilers.length; i++) { - reconcilers[i].visit(doc, node, typeBinding, problemCollector); + reconcilers[i].visit(project, doc, node, typeBinding, problemCollector); } } }