CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-com-google-auto-value--auto-value

Generated immutable value classes for Java 8+ using annotation processing

Pending
Overview
Eval results
Files

annotation-generation.mddocs/

Annotation Generation

AutoAnnotation generates proper implementations of annotation interfaces with correct equals(), hashCode(), and toString() methods that conform to the Java annotation specification.

Basic Annotation Generation

// Annotation interface
public @interface Named {
  String value();
}

// Factory method with @AutoAnnotation
public class Annotations {
  @AutoAnnotation
  public static Named named(String value) {
    return new AutoAnnotation_Annotations_named(value);
  }
}

Usage Example

Named annotation = Annotations.named("example");
System.out.println(annotation); // @Named(value="example")
System.out.println(annotation.value()); // "example"

// Proper equals() behavior
Named same = Annotations.named("example");
Named different = Annotations.named("other");
System.out.println(annotation.equals(same)); // true
System.out.println(annotation.equals(different)); // false

Multi-Parameter Annotations

// Complex annotation
public @interface ApiEndpoint {
  String path();
  String method() default "GET";
  boolean authenticated() default true;
  String[] produces() default {};
}

// Factory method
public class Annotations {
  @AutoAnnotation
  public static ApiEndpoint apiEndpoint(
      String path, 
      String method, 
      boolean authenticated, 
      String[] produces) {
    return new AutoAnnotation_Annotations_apiEndpoint(path, method, authenticated, produces);
  }
}

Usage:

ApiEndpoint endpoint = Annotations.apiEndpoint(
    "/api/users", 
    "POST", 
    true, 
    new String[]{"application/json"});

System.out.println(endpoint.path()); // "/api/users"
System.out.println(endpoint.method()); // "POST"
System.out.println(endpoint.authenticated()); // true
System.out.println(Arrays.toString(endpoint.produces())); // ["application/json"]

Annotations with Default Values

Factory methods can omit parameters that have default values:

public @interface RequestMapping {
  String path();
  String method() default "GET";
  int timeout() default 5000;
}

public class Annotations {
  // Full parameter version
  @AutoAnnotation
  public static RequestMapping requestMapping(String path, String method, int timeout) {
    return new AutoAnnotation_Annotations_requestMapping(path, method, timeout);
  }
  
  // Convenience method using defaults
  @AutoAnnotation
  public static RequestMapping requestMapping(String path) {
    return new AutoAnnotation_Annotations_requestMapping(path, "GET", 5000);
  }
  
  // Partial defaults
  @AutoAnnotation
  public static RequestMapping requestMapping(String path, String method) {
    return new AutoAnnotation_Annotations_requestMapping(path, method, 5000);
  }
}

Usage:

RequestMapping simple = Annotations.requestMapping("/api/data");
RequestMapping withMethod = Annotations.requestMapping("/api/data", "POST");
RequestMapping full = Annotations.requestMapping("/api/data", "POST", 10000);

Array-Valued Annotations

AutoAnnotation properly handles array-valued annotation elements:

public @interface Tags {
  String[] value();
  int[] priorities() default {};
}

public class Annotations {
  @AutoAnnotation
  public static Tags tags(String[] value, int[] priorities) {
    return new AutoAnnotation_Annotations_tags(value, priorities);
  }
  
  // Convenience method for single tag
  public static Tags tag(String tag) {
    return tags(new String[]{tag}, new int[]{});
  }
}

Usage:

Tags multipleTags = Annotations.tags(
    new String[]{"web", "api", "rest"}, 
    new int[]{1, 2, 3});

Tags singleTag = Annotations.tag("important");

// Arrays are properly cloned for immutability
String[] originalArray = {"test"};
Tags tagsFromArray = Annotations.tags(originalArray, new int[]{});
originalArray[0] = "modified"; // Doesn't affect the annotation
System.out.println(tagsFromArray.value()[0]); // Still "test"

Nested Annotation Types

AutoAnnotation works with annotations that contain other annotations:

public @interface Validation {
  String message();
  int code();
}

public @interface Field {
  String name();
  Validation[] validations() default {};
}

public class Annotations {
  @AutoAnnotation
  public static Validation validation(String message, int code) {
    return new AutoAnnotation_Annotations_validation(message, code);
  }
  
  @AutoAnnotation
  public static Field field(String name, Validation[] validations) {
    return new AutoAnnotation_Annotations_field(name, validations);
  }
}

Usage:

Validation required = Annotations.validation("Field is required", 1001);
Validation minLength = Annotations.validation("Minimum length is 3", 1002);

Field nameField = Annotations.field("username", new Validation[]{required, minLength});

Enum-Valued Annotations

AutoAnnotation handles enum values correctly:

public enum Priority {
  LOW, MEDIUM, HIGH, CRITICAL
}

public @interface Task {
  String description();
  Priority priority() default Priority.MEDIUM;
}

public class Annotations {
  @AutoAnnotation
  public static Task task(String description, Priority priority) {
    return new AutoAnnotation_Annotations_task(description, priority);
  }
  
  // Convenience method with default priority
  public static Task task(String description) {
    return task(description, Priority.MEDIUM);
  }
}

Usage:

Task normalTask = Annotations.task("Implement feature");
Task urgentTask = Annotations.task("Fix critical bug", Priority.CRITICAL);

Class-Valued Annotations

AutoAnnotation supports Class<?> annotation elements:

public @interface Converter {
  Class<?> from();
  Class<?> to();
  Class<? extends TypeConverter> converter();
}

public class Annotations {
  @AutoAnnotation
  public static Converter converter(Class<?> from, Class<?> to, Class<? extends TypeConverter> converter) {
    return new AutoAnnotation_Annotations_converter(from, to, converter);
  }
}

Usage:

Converter stringToInt = Annotations.converter(String.class, Integer.class, StringToIntConverter.class);

Generic Factory Methods

Factory methods can be generic for flexibility:

public @interface TypedAnnotation {
  Class<?> value();
}

public class Annotations {
  @AutoAnnotation
  public static TypedAnnotation typedAnnotation(Class<?> value) {
    return new AutoAnnotation_Annotations_typedAnnotation(value);
  }
  
  // Generic convenience method
  public static <T> TypedAnnotation typedAnnotation(Class<T> type) {
    return typedAnnotation((Class<?>) type);
  }
}

Private Factory Methods

AutoAnnotation methods can have any visibility:

public class InternalAnnotations {
  @AutoAnnotation
  private static Internal internal(String value) {
    return new AutoAnnotation_InternalAnnotations_internal(value);
  }
  
  // Public wrapper method
  public static Internal createInternal(String value) {
    validateInternalValue(value);
    return internal(value);
  }
  
  private static void validateInternalValue(String value) {
    if (value.isEmpty()) {
      throw new IllegalArgumentException("Internal value cannot be empty");
    }
  }
}

Integration with Builders

Combine AutoAnnotation with AutoBuilder for fluent annotation creation:

public @interface Configuration {
  String name();
  String value();
  boolean required() default false;
  String description() default "";
}

public class Annotations {
  @AutoAnnotation
  public static Configuration configuration(String name, String value, boolean required, String description) {
    return new AutoAnnotation_Annotations_configuration(name, value, required, description);
  }
}

@AutoBuilder(callMethod = "configuration", ofClass = Annotations.class)
public abstract class ConfigurationBuilder {
  public static ConfigurationBuilder builder() {
    return new AutoBuilder_ConfigurationBuilder()
        .setRequired(false)
        .setDescription("");
  }
  
  public abstract ConfigurationBuilder setName(String name);
  public abstract ConfigurationBuilder setValue(String value);
  public abstract ConfigurationBuilder setRequired(boolean required);
  public abstract ConfigurationBuilder setDescription(String description);
  public abstract Configuration build();
}

Usage:

Configuration config = ConfigurationBuilder.builder()
    .setName("database.url")
    .setValue("jdbc:postgresql://localhost:5432/mydb")
    .setRequired(true)
    .setDescription("Database connection URL")
    .build();

Null Handling

AutoAnnotation validates non-null parameters:

public @interface Description {
  String value();
  String author();
}

public class Annotations {
  @AutoAnnotation
  public static Description description(String value, String author) {
    return new AutoAnnotation_Annotations_description(value, author);
  }
}
// This will throw NullPointerException
Description desc = Annotations.description(null, "Alice"); // NPE: value cannot be null
Description desc2 = Annotations.description("text", null); // NPE: author cannot be null

Performance Characteristics

  • Generated annotation implementations use efficient equals() and hashCode()
  • Array parameters are cloned to ensure immutability
  • No reflection is used at runtime
  • toString() provides standard annotation string format
  • Generated classes are optimized for the specific annotation interface

Install with Tessl CLI

npx tessl i tessl/maven-com-google-auto-value--auto-value

docs

annotation-generation.md

builders.md

extensions.md

index.md

memoization.md

pretty-strings.md

serialization.md

standalone-builders.md

tagged-unions.md

value-classes.md

tile.json