Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create POJOs for (some) interfaces #79

Open
sbrossie opened this issue Jan 5, 2022 · 1 comment
Open

Create POJOs for (some) interfaces #79

sbrossie opened this issue Jan 5, 2022 · 1 comment

Comments

@sbrossie
Copy link
Member

sbrossie commented Jan 5, 2022

We would like to start by creating POJOs matching the interfaces we have defined in our catalog module. For instance, given the interface Plan, we would like to create a class ApiPlan (this is a suggestion for the naming, perhaps there is something better) that implements the interface.

The goal is to make it easier for folks writing plugin and avoid having them to write all kinds of POJOs themselves.

Each of these POJO would need to have:

  • Default CTOR
  • CTOR with all fields
  • All fields private final
  • toString method
  • equals and hashCode method
@pierre
Copy link
Member

pierre commented Jan 5, 2022

Proposal

Scenario A: POJO

// Existing interface -- simple POJO
interface POJO {

    DateTime getValueA();

    Long getValueB();
}

// Provided default immutable implementation for POJO -- ready to use with builder pattern
class DefaultPOJO implements POJO {

    private final DateTime valueA;
    private final Long valueB;

    public DefaultPOJO(final DateTime valueA,
                       final Long valueB) {
        this.valueA = valueA;
        this.valueB = valueB;
    }

    @Override
    public DateTime getValueA() {
        return valueA;
    }

    @Override
    public Long getValueB() {
        return valueB;
    }

    @Override
    public String toString() {
        final StringBuffer sb = new StringBuffer("DefaultPOJO{");
        sb.append("valueA=").append(valueA);
        sb.append(", valueB=").append(valueB);
        sb.append('}');
        return sb.toString();
    }

    @Override
    public boolean equals(final Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }

        final DefaultPOJO that = (DefaultPOJO) o;

        // Need to use compareTo for DateTime, LocalDate, etc.
        if ((valueA != null &&
             that.valueA != null &&
             valueA.compareTo(that.valueA) != 0) ||
            ((valueA != null && that.valueA == null) ||
             (valueA == null && that.valueA != null))) {
            return false;
        }

        // Otherwise, use Objects.equals
        return Objects.equals(valueB, that.valueB);
    }

    @Override
    public int hashCode() {
        int result = Objects.hashCode(valueA.hashCode());
        result = 31 * result + Objects.hashCode(valueB.hashCode());
        return result;
    }

    public static class DefaultPOJOBuilder {

        private DateTime valueA = null;
        private Long valueB = null;

        public DefaultPOJOBuilder withValueA(final DateTime valueA) {
            this.valueA = valueA;
            return this;
        }

        public DefaultPOJOBuilder withValueB(final Long valueB) {
            this.valueB = valueB;
            return this;
        }

        public DefaultPOJO build() {
            return new DefaultPOJO(valueA, valueB);
        }
    }
}

// Example usage
class MyPlugin {

    public static void main() {
        final DefaultPOJO defaultPOJO = new DefaultPOJOBuilder().withValueA(DateTime.now())
                                                                .withValueB(0L)
                                                                .build();
    }
}

Scenario B: POJO with abstract methods

// Existing interface -- POJO with abstract methods to implement
interface POJOWithMethod {

    int getValue();

    int doSomething(boolean input);
}

// Provided default implementation for POJOWithMethod -- ready to use
class DefaultPOJOWithMethod implements POJOWithMethod {

    private final int value;

    public <T extends DefaultPOJOWithMethodBuilder<T>> DefaultPOJOWithMethod(final DefaultPOJOWithMethodBuilder<?> builder) {
        this.value = builder.value;
    }

    @Override
    public int getValue() {
        return value;
    }

    @Override
    public int doSomething(final boolean input) {
        // Default implementation
        throw new UnsupportedOperationException("doSomething must be implemented");
    }

    @Override
    public String toString() {
        final StringBuffer sb = new StringBuffer("DefaultPOJOWithMethod{");
        sb.append("value=").append(value);
        sb.append('}');
        return sb.toString();
    }

    @Override
    public boolean equals(final Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        final DefaultPOJOWithMethod that = (DefaultPOJOWithMethod) o;
        return value == that.value;
    }

    @Override
    public int hashCode() {
        return Objects.hash(value);
    }

    // Generified, to allow for custom builders (optional): https://stackoverflow.com/a/17165079
    public static class DefaultPOJOWithMethodBuilder<T extends DefaultPOJOWithMethodBuilder<T>> {

        private int value;

        public T withValue(final int value) {
            this.value = value;
            return (T) this;
        }

        public DefaultPOJOWithMethod build() {
            return new DefaultPOJOWithMethod(this);
        }
    }
}

// Example usage with custom implementation
class MyPOJOWithMethod extends DefaultPOJOWithMethod {

    public MyPOJOWithMethod(final DefaultPOJOWithMethodBuilder<?> builder) {
        super(builder);
    }

    @Override
    public int doSomething(final boolean input) {
        return input ? 0 : -1;
    }
}

class MyPlugin {

    public static void main() {
        final MyPOJOWithMethod myPOJOWithMethod = new MyPOJOWithMethod(new DefaultPOJOWithMethodBuilder().withValue(0));
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants