CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-apache-avro--avro

Apache Avro core components for data serialization with rich data structures, compact binary format, and schema evolution support

Pending
Overview
Eval results
Files

reflection-operations.mddocs/

Reflection Operations

Avro's reflection support enables automatic schema generation and data handling for existing Java classes using reflection and annotations. This approach allows seamless integration with existing POJOs and domain objects without requiring code generation.

Capabilities

Reflect Data Utilities

Core utilities for reflection-based schema generation and data operations on existing Java classes.

public class ReflectData extends SpecificData {
    public static ReflectData get();
    public static ReflectData get(ClassLoader classLoader);
    
    // Schema generation from classes
    public Schema getSchema(Type type);
    public Schema getSchema(Class<?> type);
    
    // Allow null values (makes fields nullable by default)
    public ReflectData allowNull();
    public boolean getAllowNull();
    
    // String type configuration
    public ReflectData setStringType(StringType stringType);
    
    // Instance creation
    public Object newInstance(Class<?> c, Schema schema);
    public Object newRecord(Object old, Schema schema);
    
    // Field access
    public Object getField(Object record, String name, int position);
    public void setField(Object record, String name, int position, Object o);
    
    // Validation
    public boolean validate(Schema schema, Object datum);
}

Usage Examples:

// Basic reflection usage
ReflectData reflectData = ReflectData.get();

// Generate schema from existing POJO
public class Person {
    private String name;
    private int age;
    private List<String> hobbies;
    
    // Constructor, getters, setters
    public Person() {}
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
        this.hobbies = new ArrayList<>();
    }
    
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public int getAge() { return age; }
    public void setAge(int age) { this.age = age; }
    public List<String> getHobbies() { return hobbies; }
    public void setHobbies(List<String> hobbies) { this.hobbies = hobbies; }
}

// Generate schema automatically
Schema personSchema = reflectData.getSchema(Person.class);
System.out.println("Generated schema: " + personSchema.toString(true));

// Allow nullable fields
ReflectData nullableReflect = ReflectData.get().allowNull();
Schema nullableSchema = nullableReflect.getSchema(Person.class);

// Create instance from schema
Person person = (Person) reflectData.newInstance(Person.class, personSchema);
person.setName("Alice");
person.setAge(30);

// Validate instance against schema
boolean isValid = reflectData.validate(personSchema, person);
System.out.println("Person is valid: " + isValid);

Reflect Datum Reader

DatumReader that uses reflection to deserialize data into existing Java objects.

public class ReflectDatumReader<T> extends SpecificDatumReader<T> {
    public ReflectDatumReader();
    public ReflectDatumReader(Schema schema);
    public ReflectDatumReader(Schema writer, Schema reader);
    public ReflectDatumReader(Class<T> c);
    public ReflectDatumReader(Class<T> c, Schema writer, Schema reader);
    
    // Inherited methods
    public void setSchema(Schema schema);
    public void setExpected(Schema reader);
    public T read(T reuse, Decoder in) throws IOException;
}

Usage Examples:

// Read data into existing POJOs
ReflectDatumReader<Person> reader = new ReflectDatumReader<>(Person.class);

// Read from binary data
InputStream inputStream = new FileInputStream("persons.avro");
BinaryDecoder decoder = DecoderFactory.get().binaryDecoder(inputStream, null);

Person person = reader.read(null, decoder);
System.out.println("Name: " + person.getName());
System.out.println("Age: " + person.getAge());

// Schema evolution with reflection
Schema writerSchema = getOldPersonSchema();
Schema readerSchema = ReflectData.get().getSchema(Person.class);

ReflectDatumReader<Person> evolvingReader = 
    new ReflectDatumReader<>(Person.class, writerSchema, readerSchema);

Person evolvedPerson = evolvingReader.read(null, decoder);

// Read collection of objects
List<Person> persons = new ArrayList<>();
ReflectDatumReader<Person> personReader = new ReflectDatumReader<>(Person.class);

while (hasMoreData(decoder)) {
    Person p = personReader.read(null, decoder);
    persons.add(p);
}

Reflect Datum Writer

DatumWriter that uses reflection to serialize existing Java objects.

public class ReflectDatumWriter<T> extends SpecificDatumWriter<T> {
    public ReflectDatumWriter();
    public ReflectDatumWriter(Schema schema);
    public ReflectDatumWriter(Class<T> c);
    
    // Inherited methods
    public void setSchema(Schema schema);
    public void write(T datum, Encoder out) throws IOException;
}

Usage Examples:

// Write existing POJOs using reflection
Person person = new Person("Bob", 35);
person.getHobbies().addAll(Arrays.asList("reading", "hiking", "cooking"));

Schema personSchema = ReflectData.get().getSchema(Person.class);
ReflectDatumWriter<Person> writer = new ReflectDatumWriter<>(Person.class);

ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
BinaryEncoder encoder = EncoderFactory.get().binaryEncoder(outputStream, null);

writer.write(person, encoder);
encoder.flush();

// Write collection of objects
List<Person> persons = Arrays.asList(
    new Person("Alice", 25),
    new Person("Charlie", 40),
    new Person("Diana", 28)
);

for (Person p : persons) {
    writer.write(p, encoder);
}
encoder.flush();

byte[] serializedData = outputStream.toByteArray();

Reflection Annotations

Annotations for customizing reflection-based schema generation and field handling.

@Target({ElementType.FIELD, ElementType.TYPE, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface AvroName {
    String value();
}

@Target({ElementType.FIELD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface AvroDoc {
    String value();
}

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AvroDefault {
    String value();
}

@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface Nullable {
    // Makes field nullable in generated schema
}

@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface Union {
    Class<?>[] value();
}

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AvroIgnore {
    // Excludes field from schema generation
}

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AvroAlias {
    String[] value();
}

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AvroMeta {
    String key();
    String value();
}

Usage Examples:

// POJO with reflection annotations
public class AnnotatedPerson {
    @AvroName("full_name")
    @AvroDoc("The person's full name")
    private String name;
    
    @AvroDoc("Age in years")
    @AvroDefault("0")
    private int age;
    
    @Nullable
    @AvroDoc("Email address if available")
    private String email;
    
    @AvroIgnore
    private String internalId; // This field will be ignored
    
    @Union({String.class, Integer.class})
    private Object flexibleField;
    
    @AvroAlias({"old_phone", "phone_number"})
    private String phone;
    
    @AvroMeta(key = "format", value = "ISO-8601")
    private String timestamp;
    
    // Constructors, getters, setters...
    public AnnotatedPerson() {}
    
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    
    public int getAge() { return age; }
    public void setAge(int age) { this.age = age; }
    
    @Nullable
    public String getEmail() { return email; }
    public void setEmail(String email) { this.email = email; }
    
    // Other getters/setters...
}

// Generate schema with annotations
Schema annotatedSchema = ReflectData.get().getSchema(AnnotatedPerson.class);
System.out.println("Schema with annotations:\n" + annotatedSchema.toString(true));

// The generated schema will include:
// - "full_name" instead of "name" 
// - Documentation strings
// - Default values
// - Nullable email field
// - No internalId field
// - Union type for flexibleField
// - Aliases for phone field
// - Custom metadata

Enum Support

Reflection support for Java enums with custom naming and documentation.

// Enum annotations
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface AvroEnumDefault {
    String value();
}

Usage Examples:

// Enum with reflection support
@AvroDoc("Status enumeration for users")
public enum UserStatus {
    @AvroName("ACTIVE") ACTIVE,
    @AvroName("INACTIVE") INACTIVE,
    @AvroName("SUSPENDED") SUSPENDED,
    @AvroName("PENDING") PENDING
}

// POJO using enum
public class UserWithStatus {
    private String name;
    
    @AvroDefault("\"PENDING\"")
    private UserStatus status;
    
    public UserWithStatus() {}
    
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    
    public UserStatus getStatus() { return status; }
    public void setStatus(UserStatus status) { this.status = status; }
}

// Generate schema including enum
Schema userWithStatusSchema = ReflectData.get().getSchema(UserWithStatus.class);

// Use with reflection I/O
UserWithStatus user = new UserWithStatus();
user.setName("Alice");
user.setStatus(UserStatus.ACTIVE);

ReflectDatumWriter<UserWithStatus> writer = new ReflectDatumWriter<>(UserWithStatus.class);
ByteArrayOutputStream out = new ByteArrayOutputStream();
BinaryEncoder encoder = EncoderFactory.get().binaryEncoder(out, null);
writer.write(user, encoder);
encoder.flush();

Complex Type Support

Reflection handles complex nested types, collections, and custom objects.

// Complex type examples that work with reflection
public class ComplexPerson {
    private String name;
    private List<String> hobbies;
    private Map<String, Integer> scores;
    private Address address;          // Nested object
    private List<Phone> phoneNumbers; // List of objects
    
    // Constructors, getters, setters...
}

public class Address {
    private String street;
    private String city;
    private String zipCode;
    
    @Nullable
    private String country;
    
    // Constructors, getters, setters...
}

public class Phone {
    private String type; // "home", "work", "mobile"
    private String number;
    
    // Constructors, getters, setters...
}

Usage Examples:

// Work with complex nested objects
ComplexPerson person = new ComplexPerson();
person.setName("John Doe");
person.setHobbies(Arrays.asList("reading", "swimming"));
person.setScores(Map.of("math", 95, "science", 88));

Address address = new Address();
address.setStreet("123 Main St");
address.setCity("Anytown");
address.setZipCode("12345");
person.setAddress(address);

Phone workPhone = new Phone();
workPhone.setType("work");
workPhone.setNumber("555-1234");
person.setPhoneNumbers(Arrays.asList(workPhone));

// Generate schema for complex type
Schema complexSchema = ReflectData.get().getSchema(ComplexPerson.class);
System.out.println("Complex schema:\n" + complexSchema.toString(true));

// Serialize complex object
ReflectDatumWriter<ComplexPerson> writer = new ReflectDatumWriter<>(ComplexPerson.class);
ByteArrayOutputStream out = new ByteArrayOutputStream();
BinaryEncoder encoder = EncoderFactory.get().binaryEncoder(out, null);
writer.write(person, encoder);
encoder.flush();

// Deserialize complex object
ReflectDatumReader<ComplexPerson> reader = new ReflectDatumReader<>(ComplexPerson.class);
BinaryDecoder decoder = DecoderFactory.get().binaryDecoder(out.toByteArray(), null);
ComplexPerson deserializedPerson = reader.read(null, decoder);

System.out.println("Name: " + deserializedPerson.getName());
System.out.println("Address: " + deserializedPerson.getAddress().getCity());

Types

public class ReflectData extends SpecificData {
    // Reflection-based data operations
}

public class ReflectDatumReader<T> extends SpecificDatumReader<T> {
    // Reflection-based reader
}

public class ReflectDatumWriter<T> extends SpecificDatumWriter<T> {
    // Reflection-based writer
}

// Reflection annotations
@Target({ElementType.FIELD, ElementType.TYPE, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface AvroName {
    String value();
}

@Target({ElementType.FIELD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface AvroDoc {
    String value();
}

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AvroDefault {
    String value();
}

@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface Nullable {
    // Marker annotation for nullable fields
}

@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface Union {
    Class<?>[] value();
}

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AvroIgnore {
    // Marker annotation to ignore fields
}

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AvroAlias {
    String[] value();
}

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AvroMeta {
    String key();
    String value();
}

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface AvroEnumDefault {
    String value();
}

Install with Tessl CLI

npx tessl i tessl/maven-org-apache-avro--avro

docs

code-generation.md

encoding-decoding.md

file-operations.md

generic-data.md

index.md

message-operations.md

reflection-operations.md

schema-evolution.md

schema-system.md

tile.json