4

20 years in other programming languages and now I am new to Java, feeling like an noob programmer...

I use an Indexable abstract class to extend all of my @entity classes so I don't need to put the @Id @GeneratedValue @SequenceGenerator on all of them. And I also have Auditable with @CreatedBy @CreatedDate @ModifiedBy @ModifiedDate which leads to those inheritance path:

  • MostEntityClasses > AuditableClass > IndexableClass;
  • SomeEntityClasses > IndexableClass.

Now I noticed that 99% of my entity classes also have:

@Column(nullable = false, unique = true) private String name;

I thought of moving that line to the Indexable class to avoid that boilerplate code in those 99%, but the two classes that don't have the name field are important auditable classes and I don't want to just copy all the ancestor fields to them just to prevent errors of null names on it.

The question is: if I override that field's annotations on those two classes to make it nullable and transient, will it work to avoid creating this field on the table and also not bothering the user with null names?

class SomeAuditableClass extends Audited {
  //@override
  @Column(nullable = true) @Transient private String name;

The content in Is there a way to override class variables in Java? did not helped much...

NaN
  • 8,596
  • 20
  • 79
  • 153
  • The `@AttributeOverride` annotation can't emulate `@Transient`, can it? – NaN Dec 09 '18 at 22:08
  • What happened when you tried it? – Bernie Dec 09 '18 at 22:13
  • I am at modeling stage, I haven't tried it yet, I am sorry! I did not want to model it one way, and only after realized it was wrong and then have to remodel all again. – NaN Dec 09 '18 at 22:17

2 Answers2

5

While not an answer to your exact question, the typical way of approaching this would be to extend Indexable with another class, say, IndexableWithName. Then, the 99% of your entities that have the name field would extend IndexableWithName, while the two classes that don't have the name field would directly extend Indexable.

I couldn't say without trying it whether what you propose would work as far as the database mapping is concerned. But I think it would be bad class design, as presumably you would have a getter and maybe a setter for the name field in the superclass, and they wouldn't make sense on the two classes that don't really have a name field.

Bernie
  • 2,253
  • 1
  • 16
  • 18
  • It is a good approach, but those 1% extends to Auditable, which extends to Indexable, so they are extending Indexable indirectly. – NaN Dec 09 '18 at 22:19
  • Right, you kind of want multiple inheritance here... If there were more fields than just `name`, I'd suggest using an `Embeddable`, but for a single field it's probably not worth it. – Bernie Dec 09 '18 at 22:23
4

No you can't override them:

  • At the Java language level, there are no annotation overriding mechanisms for fields.
  • Private fields of a parent class are inaccessible in a child class to prevent the child class from breaking / interfering with the abstraction.

At runtime you could potentially break abstraction using reflection to see the annotations a superclasses private fields. But you cannot add or remove them: see Adding Java Annotations at Runtime. And even if you could, runtime may be too late.

The only way that you could get some traction here would be to identify the code that is processing the annotations, and modify it to (somehow!) accept overrides from some (non-java) file.

But for your use-case, that seems like a very bad idea. You don't want to create and maintain a private fork of (say) Hibernate with non-standard functionality just to save you a relatively small amount on boilerplate code.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216