Interface DerivedAttribute<T>

Type Parameters:
T - the value type
All Superinterfaces:
Attribute<T>

public interface DerivedAttribute<T> extends Attribute<T>
An attribute which value is derived from one or more source attributes.

Derived attributes compute their values from other attributes within the same entity or from related entities. They provide calculated fields, formatting, concatenation, and other derived values without being stored in the database.

Derived attributes are defined using value providers that receive source values and compute the derived result:

public class Store extends DefaultDomain {

    interface Customer {
        EntityType TYPE = DOMAIN.entityType("store.customer");

        Column<String> FIRST_NAME = TYPE.stringColumn("first_name");
        Column<String> LAST_NAME = TYPE.stringColumn("last_name");
        Column<String> EMAIL = TYPE.stringColumn("email");
        Column<LocalDate> BIRTH_DATE = TYPE.localDateColumn("birth_date");

        // Derived attributes
        Attribute<String> FULL_NAME = TYPE.stringAttribute("full_name");
        Attribute<String> DISPLAY_NAME = TYPE.stringAttribute("display_name");
        Attribute<Integer> AGE = TYPE.integerAttribute("age");
        Attribute<String> INITIALS = TYPE.stringAttribute("initials");
    }

    void defineCustomer() {
        Customer.TYPE.define(
                Customer.FIRST_NAME.define()
                    .column(),
                Customer.LAST_NAME.define()
                    .column(),
                Customer.EMAIL.define()
                    .column(),
                Customer.BIRTH_DATE.define()
                    .column(),

                // Simple concatenation
                Customer.FULL_NAME.define()
                    .attribute()
                    .derived(Customer.FIRST_NAME, Customer.LAST_NAME)
                    .valueProvider(values -> {
                        String first = values.get(Customer.FIRST_NAME);
                        String last = values.get(Customer.LAST_NAME);
                        return (first != null ? first : "") + " " + (last != null ? last : "");
                    }),

                // Complex formatting with multiple sources
                Customer.DISPLAY_NAME.define()
                    .attribute()
                    .derived(Customer.FULL_NAME, Customer.EMAIL)
                    .valueProvider(values -> {
                        String fullName = values.get(Customer.FULL_NAME);
                        String email = values.get(Customer.EMAIL);
                        return fullName + " (" + email + ")";
                    }),

                // Age calculation
                Customer.AGE.define()
                    .attribute()
                    .derived(Customer.BIRTH_DATE)
                    .valueProvider(values -> {
                        LocalDate birthDate = values.get(Customer.BIRTH_DATE);
                        return birthDate != null ?
                            Period.between(birthDate, LocalDate.now()).getYears() : null;
                    }),

                // Initials from names
                Customer.INITIALS.define()
                    .attribute()
                    .derived(Customer.FIRST_NAME, Customer.LAST_NAME)
                    .valueProvider(values -> {
                        String first = values.get(Customer.FIRST_NAME);
                        String last = values.get(Customer.LAST_NAME);
                        String firstInitial = first != null && !first.isEmpty() ?
                            first.substring(0, 1).toUpperCase() : "";
                        String lastInitial = last != null && !last.isEmpty() ?
                            last.substring(0, 1).toUpperCase() : "";
                        return firstInitial + lastInitial;
                    }))
            .build();
    }
}

// Usage
Entity customer = entities.builder(Customer.TYPE)
    .with(Customer.FIRST_NAME, "John")
    .with(Customer.LAST_NAME, "Doe")
    .with(Customer.EMAIL, "john.doe@example.com")
    .with(Customer.BIRTH_DATE, LocalDate.of(1990, 5, 15))
    .build();

// Derived values are computed automatically
String fullName = customer.get(Customer.FULL_NAME);       // "John Doe"
String displayName = customer.get(Customer.DISPLAY_NAME); // "John Doe (john.doe@example.com)"
Integer age = customer.get(Customer.AGE);                 // Calculated age
String initials = customer.get(Customer.INITIALS);       // "JD"
See Also: