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

tech.picnic.errorprone.bugpatterns.RequestMappingAnnotation Maven / Gradle / Ivy

There is a newer version: 0.19.1
Show newest version
package tech.picnic.errorprone.bugpatterns;

import static com.google.errorprone.BugPattern.LinkType.CUSTOM;
import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
import static com.google.errorprone.BugPattern.StandardTags.LIKELY_ERROR;
import static com.google.errorprone.matchers.ChildMultiMatcher.MatchType.ALL;
import static com.google.errorprone.matchers.ChildMultiMatcher.MatchType.AT_LEAST_ONE;
import static com.google.errorprone.matchers.Matchers.annotations;
import static com.google.errorprone.matchers.Matchers.anyOf;
import static com.google.errorprone.matchers.Matchers.isSameType;
import static com.google.errorprone.matchers.Matchers.isType;
import static com.google.errorprone.matchers.Matchers.methodHasParameters;
import static com.google.errorprone.matchers.Matchers.not;
import static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL;

import com.google.auto.service.AutoService;
import com.google.errorprone.BugPattern;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker;
import com.google.errorprone.bugpatterns.BugChecker.MethodTreeMatcher;
import com.google.errorprone.matchers.Description;
import com.google.errorprone.matchers.Matcher;
import com.sun.source.tree.MethodTree;
import com.sun.source.tree.Tree;
import java.io.InputStream;
import java.time.ZoneId;
import java.util.Locale;
import java.util.TimeZone;

/**
 * A {@link BugChecker} that flags {@code @RequestMapping} methods that have one or more parameters
 * that appear to lack a relevant annotation.
 *
 * 

Matched mappings are {@code @{Delete,Get,Patch,Post,Put,Request}Mapping}. */ @AutoService(BugChecker.class) @BugPattern( summary = "Make sure all `@RequestMapping` method parameters are annotated", link = BUG_PATTERNS_BASE_URL + "RequestMappingAnnotation", linkType = CUSTOM, severity = WARNING, tags = LIKELY_ERROR) public final class RequestMappingAnnotation extends BugChecker implements MethodTreeMatcher { private static final long serialVersionUID = 1L; private static final String ANN_PACKAGE_PREFIX = "org.springframework.web.bind.annotation."; // XXX: Generalize this logic to fully support Spring meta-annotations, then update the class // documentation. private static final Matcher HAS_MAPPING_ANNOTATION = annotations( AT_LEAST_ONE, anyOf( isType(ANN_PACKAGE_PREFIX + "DeleteMapping"), isType(ANN_PACKAGE_PREFIX + "GetMapping"), isType(ANN_PACKAGE_PREFIX + "PatchMapping"), isType(ANN_PACKAGE_PREFIX + "PostMapping"), isType(ANN_PACKAGE_PREFIX + "PutMapping"), isType(ANN_PACKAGE_PREFIX + "RequestMapping"))); // XXX: Add other parameters as necessary. Also consider whether it makes sense to have WebMVC- // and WebFlux-specific logic. See // https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc-ann-arguments // and // https://docs.spring.io/spring-framework/docs/current/reference/html/web-reactive.html#webflux-ann-arguments. private static final Matcher LACKS_PARAMETER_ANNOTATION = not( methodHasParameters( ALL, anyOf( annotations( AT_LEAST_ONE, anyOf( isType(ANN_PACKAGE_PREFIX + "PathVariable"), isType(ANN_PACKAGE_PREFIX + "RequestAttribute"), isType(ANN_PACKAGE_PREFIX + "RequestBody"), isType(ANN_PACKAGE_PREFIX + "RequestHeader"), isType(ANN_PACKAGE_PREFIX + "RequestParam"), isType(ANN_PACKAGE_PREFIX + "RequestPart"), isType( "org.springframework.security.core.annotation.CurrentSecurityContext"))), isSameType(InputStream.class.getCanonicalName()), isSameType(Locale.class.getCanonicalName()), isSameType(TimeZone.class.getCanonicalName()), isSameType(ZoneId.class.getCanonicalName()), isSameType("jakarta.servlet.http.HttpServletRequest"), isSameType("jakarta.servlet.http.HttpServletResponse"), isSameType("javax.servlet.http.HttpServletRequest"), isSameType("javax.servlet.http.HttpServletResponse"), isSameType("org.springframework.http.HttpMethod"), isSameType("org.springframework.ui.Model"), isSameType("org.springframework.validation.BindingResult"), isSameType("org.springframework.web.context.request.NativeWebRequest"), isSameType("org.springframework.web.context.request.WebRequest"), isSameType("org.springframework.web.server.ServerWebExchange"), isSameType("org.springframework.web.util.UriBuilder"), isSameType("org.springframework.web.util.UriComponentsBuilder")))); /** Instantiates a new {@link RequestMappingAnnotation} instance. */ public RequestMappingAnnotation() {} @Override public Description matchMethod(MethodTree tree, VisitorState state) { // XXX: Auto-add `@RequestParam` where applicable. // XXX: What about the `PurchasingProposerRequestParams` in POM? Implies `@RequestBody`? // (Documentation doesn't mention this, IIUC.) return HAS_MAPPING_ANNOTATION.matches(tree, state) && LACKS_PARAMETER_ANNOTATION.matches(tree, state) ? buildDescription(tree) .setMessage( """ Not all parameters of this request mapping method are annotated; this may be a \ mistake. If the unannotated parameters represent query string parameters, annotate \ them with `@RequestParam`.""") .build() : Description.NO_MATCH; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy