2

Assume I have these classes:

@Entity
@Data
class Student{
    @Size(min = 8)
    public String name;
    public int age;
    ...
}

@Data
class StudentDTO{
    @Size(min = 8)
    public String name;
    ....
}

To reduce duplicate annotations, I've figured out a simple trick like this:

interface HasName {
    @Size(min=8)
    String getName();
}
@Entity
@Data
class Student implements HasName {
    public String name;
    public int age;
}
@Data
class StudentDTO implements HasName{
    public String name;
}

There could be more fields.

Pro:

  • No duplicate annotation
  • Annotation will be unified

Cons:

  • Increase complexity
  • Increase dependency

But it look like a code smell to me, so is it good or bad?

  • Look at your pros and cons again, and answer the question yourself. Is it good or bad? You've eliminated one annotation at the cost of adding an interface and two more lines of code. Which one is better should be obvious. – Robert Harvey May 7 '18 at 19:38
  • Your approach would make more sense if the factored-out interface included more inter-related getters. One interface per field seems a bit wordy. If you keep changing the size often between builds, though, it might make sense still; I don't know if it's your case. – 9000 May 7 '18 at 20:25
3

Your strategy will work, but I can't see as a good solution. Your classes would implement so many interfaces that the objective to have a Interface in your class will be lost if you mix with more meaningful interfaces: the ones that really will acts like contracts in your code.

The classic solution for this kind of annotation problem is create a new annotation that aggregates other annotations, like:

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Size(min = 8)
public @interface Name {

}

And to use:

@Name
private String name;

The @Name annotation will continue to be replicated, but you can change the min size (per example) and add another annotations to the name (like @NotNull) on one single place.

Generally, I don't like to use annotations to do the validation for my classes. So, if you already trying to unify the validation without spreading the annotation , try to do the validation on the constructor without any annotation, something more OOP, like:

private Name name;

And Name:

class Name {
    Name(String name) {
        if (name.size() < 8) {
            //throw some exception
        }
    }
}
  • 1
    "do the validation on the constructor" is a great advice; it prevents existence of objects in invalid state. It is still compatible with the builder pattern, as provided by e.g. Lombok. – 9000 May 7 '18 at 20:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.