As this service ist the first of several I’ll invest a little bit more in a generic approach. Some of the generics and abstract classes might seem a little bit over the top.
I’ll as well use Lombok even it’s not the considered for some functionality on the entities. Feel free to de-lombok the functions. For now it will spare me some boilerplate.
Metadata
All of entities will implement the interface MetaData
.
public interface MetaData<T extends Serializable> {
T getId();
Long getVersion();
String getCreatedBy();
ZonedDateTime getCreatedDate();
String getLastModifiedBy();
ZonedDateTime getLastModifiedDate();
}
To make this a little bit more convenient the abstract class AbstractEntity
offers all functions so that this methods can be called via extends
.
@AllArgsConstructor
@Data
@EntityListeners(AuditingEntityListener.class)
@EqualsAndHashCode(of = {"lastModifiedBy", "lastModifiedDate", "name", "id"}, callSuper = false)
@MappedSuperclass
@NoArgsConstructor
@SuperBuilder
@ToString
@Validated
public abstract class AbstractEntity<T extends Serializable> implements MetaData<T>, View<T> {
@Id
@GeneratedValue(strategy = GenerationType.UUID)
@Column(name = "ID", nullable = false, unique = true)
private T id;
@NotBlank
@Size(min = 3, max = 50)
@Column(name = "NAME", length = 50)
private String name;
@Version
@Column(name = "VERSION")
private Long version;
@CreatedBy
@Column(name = "CREATED_BY")
private String createdBy;
@CreatedDate
@Column(name = "CREATED_DATE")
private ZonedDateTime createdDate;
@LastModifiedBy
@Column(name = "LAST_MODIFIED_BY")
private String lastModifiedBy;
@LastModifiedDate
@Column(name = "LAST_MODIFIED_DATE")
private ZonedDateTime lastModifiedDate;
@Builder.Default
@Convert(converter = MapStringConverter.class)
@Column(name = "attributes", nullable = false)
private Map<String, String> attributes = new HashMap<>();
}
At this point the strategy of the id-generation is generic as a type but the annotation doesn’t support this. This a known Bug for the moment.
UserEntity
All entities extend from the abstract class AbstractEntity.
The UserEntity is an example how this is done.
@AllArgsConstructor
@Data
@Entity
@EqualsAndHashCode(callSuper = false)
@NoArgsConstructor
@SuperBuilder
@Table(name = "USERS")
@ToString
@Validated
public class UserEntity extends AbstractEntity<UUID> {
@NotBlank
@Size(min = 3, max = 50)
@Column(name = "FIRSTNAME", length = 50)
private String firstname;
@NotBlank
@Size(min = 3, max = 50)
@Column(name = "LASTNAME", length = 50)
private String lastname;
@NotBlank
@Size(min = 3, max = 50)
@Column(name = "PASSWORD", length = 50)
@ToString.Exclude
private String password;
@OneToOne(cascade = CascadeType.ALL)
@ToString.Exclude
@JoinColumn(name = "DOCUMENT", referencedColumnName = "id")
private DocumentEntity document;
}
The other classes can be found in the git-repo which I’ll link in the next few weeks.