All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.sonar.java.checks.spring.StaticFieldInjectionNotSupportedCheck Maven / Gradle / Ivy

The newest version!
/*
 * SonarQube Java
 * Copyright (C) 2012-2025 SonarSource SA
 * mailto:info AT sonarsource DOT com
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the Sonar Source-Available License Version 1, as published by SonarSource SA.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the Sonar Source-Available License for more details.
 *
 * You should have received a copy of the Sonar Source-Available License
 * along with this program; if not, see https://sonarsource.com/license/ssal/
 */
package org.sonar.java.checks.spring;

import java.util.List;
import java.util.Set;
import java.util.stream.Stream;
import org.sonar.check.Rule;
import org.sonar.java.checks.helpers.ExpressionsHelper;
import org.sonar.plugins.java.api.IssuableSubscriptionVisitor;
import org.sonar.plugins.java.api.JavaFileScannerContext;
import org.sonar.plugins.java.api.tree.AnnotationTree;
import org.sonar.plugins.java.api.tree.ClassTree;
import org.sonar.plugins.java.api.tree.CompilationUnitTree;
import org.sonar.plugins.java.api.tree.ExpressionTree;
import org.sonar.plugins.java.api.tree.ImportTree;
import org.sonar.plugins.java.api.tree.MethodTree;
import org.sonar.plugins.java.api.tree.ModifiersTree;
import org.sonar.plugins.java.api.tree.Tree;
import org.sonar.plugins.java.api.tree.VariableTree;

@Rule(key = "S7178")
public class StaticFieldInjectionNotSupportedCheck extends IssuableSubscriptionVisitor {
  private static final Set INJECTIONS_ANNOTATIONS = Set.of(
    "javax.inject.Inject",
    "org.springframework.beans.factory.annotation.Autowired",
    "jakarta.inject.Inject",
    "org.springframework.beans.factory.annotation.Value");

  private static final String STATIC_FIELD_MESSAGE = "Remove this injection annotation targeting the static field.";
  private static final String STATIC_METHOD_MESSAGE = "Remove this injection annotation targeting the static method.";
  private static final String STATIC_PARAMETER_MESSAGE = "Remove this injection annotation targeting the parameter.";
  private static final String SPRING_PREFIX = "org.springframework";

  private boolean analyzingSpringProject = false;

  @Override
  public void setContext(JavaFileScannerContext context) {
    super.setContext(context);
    // by default, it is not a spring context
    analyzingSpringProject = false;
  }

  @Override
  public List nodesToVisit() {
    return List.of(Tree.Kind.METHOD, Tree.Kind.CLASS, Tree.Kind.COMPILATION_UNIT);
  }

  @Override
  public void visitNode(Tree tree) {
    if (tree instanceof CompilationUnitTree compilationUnit) {
      analyzingSpringProject = compilationUnit.imports().stream()
        .filter(ImportTree.class::isInstance)
        .map(ImportTree.class::cast)
        .anyMatch(i -> ExpressionsHelper.concatenate((ExpressionTree) i.qualifiedIdentifier()).startsWith(SPRING_PREFIX));
    }

    if (!analyzingSpringProject) {
      return;
    }

    if (tree instanceof MethodTree method && method.symbol().isStatic()) {
      // report on method annotations
      selectInjectionAnnotations(method.modifiers())
        .forEach(ann -> reportIssue(ann, STATIC_METHOD_MESSAGE));

      // report on parameters
      method.parameters().stream()
        .map(p -> selectInjectionAnnotations(p.modifiers()))
        .forEach(anns -> anns.forEach(ann -> reportIssue(ann, STATIC_PARAMETER_MESSAGE)));
    } else if (tree instanceof ClassTree clazz) {
      Stream staticFields = clazz.members().stream()
        .filter(child -> child instanceof VariableTree v && v.symbol().isStatic())
        .map(VariableTree.class::cast);

      staticFields
        .map(v -> selectInjectionAnnotations(v.modifiers()))
        .forEach(anns -> anns.forEach(ann -> reportIssue(ann, STATIC_FIELD_MESSAGE)));
    }
  }

  private static List selectInjectionAnnotations(ModifiersTree m) {
    return m.annotations().stream()
      .filter(ann -> INJECTIONS_ANNOTATIONS.contains(ann.annotationType().symbolType().fullyQualifiedName()))
      .toList();
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy