CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-com-fasterxml-jackson-core--jackson-annotations

Core annotations used for value types, used by Jackson data binding package.

Pending
Overview
Eval results
Files

object-creation.mddocs/

Object Creation and Injection

Control how objects are created during deserialization, including constructor/factory method selection and dependency injection.

Capabilities

JsonCreator

Mark constructor or factory method for object creation during deserialization.

/**
 * Mark constructor or factory method for deserialization
 * @param mode Creator binding mode controlling how parameters are bound
 */
@JsonCreator(JsonCreator.Mode mode = JsonCreator.Mode.DEFAULT)
public @interface JsonCreator {
    
    enum Mode {
        /** Default mode - auto-detect binding based on parameter annotations */
        DEFAULT,
        
        /** Delegating mode - single unnanotated parameter receives full JSON */
        DELEGATING,
        
        /** Properties mode - parameters bound to JSON properties by name */
        PROPERTIES,
        
        /** Disabled - do not use this creator */
        DISABLED
    }
}

Usage Examples:

public class Person {
    private final String name;
    private final int age;
    private final String email;
    
    // Properties-based creator (default mode)
    @JsonCreator
    public Person(@JsonProperty("name") String name,
                  @JsonProperty("age") int age,
                  @JsonProperty("email") String email) {
        this.name = name;
        this.age = age;
        this.email = email;
    }
}

// Delegating creator example
public class Wrapper {
    private final Map<String, Object> data;
    
    @JsonCreator(mode = JsonCreator.Mode.DELEGATING)
    public Wrapper(Map<String, Object> data) {
        this.data = new HashMap<>(data);
    }
}

// Factory method creator
public class Product {
    private final String name;
    private final BigDecimal price;
    
    private Product(String name, BigDecimal price) {
        this.name = name;
        this.price = price;
    }
    
    @JsonCreator
    public static Product create(@JsonProperty("productName") String name,
                                @JsonProperty("price") String priceStr) {
        return new Product(name, new BigDecimal(priceStr));
    }
}

JacksonInject

Inject values from ObjectReader/ObjectMapper context during deserialization.

/**
 * Inject values from deserialization context
 * @param value Injection identifier (default: use property/parameter name)
 * @param useInput Whether to use input value if available in JSON
 */
@JacksonInject(String value = "",
               OptBoolean useInput = OptBoolean.DEFAULT)
public @interface JacksonInject;

Usage Examples:

public class AuditableEntity {
    private String data;
    
    @JacksonInject
    private String createdBy;  // Injected from context
    
    @JacksonInject("timestamp")
    private LocalDateTime createdAt;  // Injected with specific key
    
    @JacksonInject(useInput = OptBoolean.FALSE)
    private String tenantId;  // Always injected, never from JSON
    
    @JsonCreator
    public AuditableEntity(@JsonProperty("data") String data,
                          @JacksonInject("userId") String userId) {
        this.data = data;
        this.createdBy = userId;
    }
}

// Usage with ObjectMapper:
ObjectMapper mapper = new ObjectMapper();
InjectableValues inject = new InjectableValues.Std()
    .addValue("userId", "john.doe")
    .addValue("timestamp", LocalDateTime.now())
    .addValue("tenantId", "tenant-123");

AuditableEntity entity = mapper.reader(inject)
    .readValue(json, AuditableEntity.class);

JsonMerge

Enable merging of property values during deserialization instead of replacement.

/**
 * Enable property value merging during deserialization
 * @param value Whether to enable merging (default: true)
 */
@JsonMerge(OptBoolean value = OptBoolean.TRUE)
public @interface JsonMerge;

Usage Examples:

public class Configuration {
    @JsonMerge
    private Map<String, String> settings = new HashMap<>();
    
    @JsonMerge
    private List<String> features = new ArrayList<>();
    
    @JsonMerge
    private DatabaseConfig database = new DatabaseConfig();
    
    // Getters and setters
}

public class DatabaseConfig {
    private String host = "localhost";
    private int port = 5432;
    private String database = "myapp";
    
    // Getters and setters
}

// Original object: {"settings": {"theme": "dark"}, "features": ["auth"], "database": {"host": "localhost", "port": 5432}}
// JSON update: {"settings": {"language": "en"}, "features": ["logging"], "database": {"port": 3306}}
// Result: {"settings": {"theme": "dark", "language": "en"}, "features": ["auth", "logging"], "database": {"host": "localhost", "port": 3306}}

Advanced Creation Patterns

Multiple Constructors

public class User {
    private String username;
    private String email;
    private String fullName;
    
    // Primary creator for full JSON objects
    @JsonCreator
    public User(@JsonProperty("username") String username,
                @JsonProperty("email") String email,
                @JsonProperty("fullName") String fullName) {
        this.username = username;
        this.email = email;
        this.fullName = fullName;
    }
    
    // Alternative creator for minimal objects
    @JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
    public static User minimal(@JsonProperty("username") String username) {
        return new User(username, null, null);
    }
}

Builder Pattern Integration

public class ComplexObject {
    private final String name;
    private final List<String> tags;
    private final Map<String, Object> metadata;
    
    private ComplexObject(Builder builder) {
        this.name = builder.name;
        this.tags = builder.tags;
        this.metadata = builder.metadata;
    }
    
    @JsonCreator
    public static ComplexObject create(@JsonProperty("name") String name,
                                      @JsonProperty("tags") List<String> tags,
                                      @JsonProperty("metadata") Map<String, Object> metadata) {
        return new Builder()
            .name(name)
            .tags(tags)
            .metadata(metadata)
            .build();
    }
    
    public static class Builder {
        private String name;
        private List<String> tags = new ArrayList<>();
        private Map<String, Object> metadata = new HashMap<>();
        
        public Builder name(String name) {
            this.name = name;
            return this;
        }
        
        public Builder tags(List<String> tags) {
            this.tags = tags != null ? new ArrayList<>(tags) : new ArrayList<>();
            return this;
        }
        
        public Builder metadata(Map<String, Object> metadata) {
            this.metadata = metadata != null ? new HashMap<>(metadata) : new HashMap<>();
            return this;
        }
        
        public ComplexObject build() {
            return new ComplexObject(this);
        }
    }
}

Context-aware Creation

public class SecureDocument {
    private String content;
    private String owner;
    private LocalDateTime createdAt;
    private String ipAddress;
    
    @JsonCreator
    public SecureDocument(@JsonProperty("content") String content,
                         @JacksonInject("currentUser") String owner,
                         @JacksonInject("requestTime") LocalDateTime createdAt,
                         @JacksonInject("clientIp") String ipAddress) {
        this.content = content;
        this.owner = owner;
        this.createdAt = createdAt;
        this.ipAddress = ipAddress;
    }
}

// Context setup:
InjectableValues context = new InjectableValues.Std()
    .addValue("currentUser", getCurrentUser())
    .addValue("requestTime", LocalDateTime.now())
    .addValue("clientIp", getClientIpAddress());

Validation during Creation

public class ValidatedUser {
    private final String email;
    private final int age;
    
    @JsonCreator
    public ValidatedUser(@JsonProperty("email") String email,
                        @JsonProperty("age") int age) {
        if (email == null || !email.contains("@")) {
            throw new IllegalArgumentException("Invalid email format");
        }
        if (age < 0 || age > 150) {
            throw new IllegalArgumentException("Invalid age: " + age);
        }
        
        this.email = email;
        this.age = age;
    }
}

JacksonInject.Value

Configuration class for programmatic injection control.

/**
 * Value class for JacksonInject configuration
 */
public static class JacksonInject.Value implements JacksonAnnotationValue<JacksonInject> {
    public static final JacksonInject.Value EMPTY;
    
    public static JacksonInject.Value construct(Object id, Boolean useInput);
    public static JacksonInject.Value forId(Object id);
    
    public Object getId();
    public Boolean getUseInput();
    
    public JacksonInject.Value withId(Object id);
    public JacksonInject.Value withUseInput(Boolean useInput);
}

Install with Tessl CLI

npx tessl i tessl/maven-com-fasterxml-jackson-core--jackson-annotations

docs

configuration.md

formatting.md

inclusion-exclusion.md

index.md

object-creation.md

object-identity.md

object-structure.md

polymorphic-types.md

property-control.md

tile.json