Skip to main content Link Search Menu Expand Document (external link)

LexicographicalAnnotationAttributeListing

SUGGESTION

Style

View source code on GitHub

Summary

Where possible, sort annotation array attributes lexicographically

Suppression

Suppress false positives by adding the suppression annotation @SuppressWarnings("LexicographicalAnnotationAttributeListing") to the enclosing element.

Disable this pattern completely by adding -Xep:LexicographicalAnnotationAttributeListing:OFF as compiler argument. Learn more.

Samples

Replacement

Shows the difference in example code before and after the bug pattern is applied.

 import static java.math.RoundingMode.DOWN;
 import static java.math.RoundingMode.UP;
 
 import java.math.RoundingMode;
 
 interface A {
   @interface Foo {
     String[] value() default {};
 
     Class<?>[] cls() default {};
 
     RoundingMode[] enums() default {};
 
     Bar[] anns() default {};
   }
 
   @interface Bar {
     String[] value() default {};
   }
 
-  @Foo({" ", "", "b", "a"})
+  @Foo({"", " ", "a", "b"})
   A unsortedString();
 
-  @Foo(cls = {long.class, int.class})
+  @Foo(cls = {int.class, long.class})
   A unsortedClasses();
 
-  @Foo(enums = {UP, DOWN})
+  @Foo(enums = {DOWN, UP})
   A unsortedEnums();
 
-  @Foo(anns = {@Bar("b"), @Bar("a")})
+  @Foo(anns = {@Bar("a"), @Bar("b")})
   A unsortedAnns();
 
-  @Foo(anns = {@Bar("a"), @Bar({"b", "a"})})
+  @Foo(anns = {@Bar("a"), @Bar({"a", "b"})})
   A unsortedInnderAnns();
 }

Identification

Shows code lines which will (not) be flagged by this bug pattern.
A //BUG: Diagnostic contains: comment is placed above any violating line.

import static java.math.RoundingMode.DOWN;
import static java.math.RoundingMode.UP;

import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import java.math.RoundingMode;
import javax.xml.bind.annotation.XmlType;
import org.springframework.context.annotation.PropertySource;
import org.springframework.test.context.TestPropertySource;

interface A {
  @interface Foo {
    String[] value() default {};

    int[] ints() default {};

    Class<?>[] cls() default {};

    RoundingMode[] enums() default {};

    Bar[] anns() default {};
  }

  @interface Bar {
    String[] value() default {};
  }

  @Foo({})
  A noString();

  @Foo({"a"})
  A oneString();

  @Foo({"a", "b"})
  A sortedStrings();
  // BUG: Diagnostic contains:
  @Foo({"b", "a"})
  A unsortedString();

  @Foo({"ab", "Ac"})
  A sortedStringCaseInsensitive();
  // BUG: Diagnostic contains:
  @Foo({"ac", "Ab"})
  A unsortedStringCaseInsensitive();

  @Foo({"A", "a"})
  A sortedStringCaseInsensitiveWithTotalOrderFallback();
  // BUG: Diagnostic contains:
  @Foo({"a", "A"})
  A unsortedStringCaseInsensitiveWithTotalOrderFallback();

  @Foo(ints = {})
  A noInts();

  @Foo(ints = {0})
  A oneInt();

  @Foo(ints = {0, 1})
  A sortedInts();

  @Foo(ints = {1, 0})
  A unsortedInts();

  @Foo(cls = {})
  A noClasses();

  @Foo(cls = {int.class})
  A oneClass();

  @Foo(cls = {int.class, long.class})
  A sortedClasses();
  // BUG: Diagnostic contains:
  @Foo(cls = {long.class, int.class})
  A unsortedClasses();

  @Foo(enums = {})
  A noEnums();

  @Foo(enums = {DOWN})
  A oneEnum();

  @Foo(enums = {DOWN, UP})
  A sortedEnums();
  // BUG: Diagnostic contains:
  @Foo(enums = {UP, DOWN})
  A unsortedEnums();

  @Foo(anns = {})
  A noAnns();

  @Foo(anns = {@Bar("a")})
  A oneAnn();

  @Foo(anns = {@Bar("a"), @Bar("b")})
  A sortedAnns();
  // BUG: Diagnostic contains:
  @Foo(anns = {@Bar("b"), @Bar("a")})
  A unsortedAnns();
  // BUG: Diagnostic contains:
  @Foo(anns = {@Bar("a"), @Bar({"b", "a"})})
  A unsortedInnderAnns();

  @Foo({"a=foo", "a.b=bar", "a.c=baz"})
  A hierarchicallySorted();
  // BUG: Diagnostic contains:
  @Foo({"a.b=bar", "a.c=baz", "a=foo"})
  A hierarchicallyUnsorted();

  @JsonPropertyOrder({"field2", "field1"})
  A dto();

  @ApiImplicitParams({@ApiImplicitParam("p2"), @ApiImplicitParam("p1")})
  A firstEndpoint();

  @Parameters({@Parameter(name = "p2"), @Parameter(name = "p1")})
  A secondEndpoint();

  @XmlType(propOrder = {"field2", "field1"})
  class XmlTypeDummy {}

  @PropertySource({"field2", "field1"})
  class PropertySourceDummy {}

  @TestPropertySource(locations = {"field2", "field1"})
  class FirstTestPropertySourceDummy {}

  @TestPropertySource({"field2", "field1"})
  class SecondTestPropertySourceDummy {}
}
package pkg;

interface A {
  @interface Foo {
    String[] value() default {};

    String[] value2() default {};
  }

  @interface Bar {
    String[] value() default {};

    String[] value2() default {};
  }

  @interface Baz {
    String[] value() default {};

    String[] value2() default {};
  }

  // BUG: Diagnostic contains:
  @Foo({"b", "a"})
  A fooValue();
  // BUG: Diagnostic contains:
  @Foo(value2 = {"b", "a"})
  A fooValue2();

  @Bar({"b", "a"})
  A barValue();
  // BUG: Diagnostic contains:
  @Bar(value2 = {"b", "a"})
  A barValue2();

  @Baz({"b", "a"})
  A bazValue();

  @Baz(value2 = {"b", "a"})
  A bazValue2();
}

Copyright © 2017-2023 Picnic Technologies BV