I set up a @Repository for an Entity with a @Version property and published it via @RepositoryRestResource which was pretty straight forward. The version is transfered to the and from the client in the Http Header as an ETag and it works perfectly.
In my current scenario I have a child Entity which doesn't have a @Version-Tag itself, instead the @Version-Tag of its parent has to be used. That means, that every change of the child or the parent has to increment the parent version. Also the operation should fail, if the parent version is outdated. For this case EntityManager offers the LockModeType.OPTIMISTIC_FORCE_INCREMENT.
How do I customize Spring Data Rest to implement such behavior? Do I have to implement a @RestController from scratch?
----------------- edit ----------------
Here is a small example i set up which works for a simple entity
Application.java
@SpringBootApplication
public class Application
{
public static void main(String[] args)
{
SpringApplication.run(Application.class, args);
}
@Configuration
@EnableJpaRepositories
public static class ServerConfiguration
{
private EntityManagerFactory emf;
@Bean
public EntityManagerFactory entityManagerFactory()
{
if (emf == null)
{
Map<String, Object> properties = new HashMap<>();
properties.put(AvailableSettings.CLASSLOADERS, Collections.singleton(Thread.currentThread().getContextClassLoader()));
emf = Persistence.createEntityManagerFactory("test", properties);
}
return emf;
}
@Bean
public PlatformTransactionManager transactionManager()
{
JpaTransactionManager transactionManager = new JpaTransactionManager(entityManagerFactory());
return transactionManager;
}
@Bean
public ShallowEtagHeaderFilter shallowEtagHeaderFilter()
{
return new ShallowEtagHeaderFilter();
}
}
}
SimpleRepository.java
@Repository
@RepositoryRestResource(collectionResourceRel = "simples", path = "simples")
public interface SimpleRepository extends JpaRepository<Simple, Long>
{
}
Simple.java
@Data
@NoArgsConstructor
@Entity
@Table(name = "SIMPLE")
public class Simple
{
@JsonCreator
public Simple(@JsonProperty("changeable") String changeable)
{
this.changeable = changeable;
}
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "ID")
@SequenceGenerator(name = "ID", sequenceName = "ID", allocationSize = 1)
@Column(name = "ID")
private Long id;
@Version
@Column(name = "VERSION")
private int version;
@Column(name = "CHANGEABLE")
private String changeable;
}
It works perfectly with just these three classes, I can interact with the exposed JPA repository via postman, the version number is shipped in the http header as an ETag.
Now I want to extend it for a parent-child-relationship where the version is only incremented in the parent entity.
Parent.java
@Data
@NoArgsConstructor
@Entity
@Table(name = "PARENT")
public class Parent
{
@JsonCreator
public Parent(@JsonProperty("changeable") String changeable)
{
this.changeable = changeable;
}
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "PARENT_ID")
@SequenceGenerator(name = "PARENT_ID", sequenceName = "PARENT_ID", allocationSize = 1)
@Column(name = "PARENT_ID")
private Long id;
@Version
@Column(name = "VERSION")
private int version;
@OneToMany(mappedBy = "parent", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private Collection<Child> children = new LinkedHashSet<>();
@Column(name = "CHANGEABLE")
private String changeable;
}
Child.java
@Data
@NoArgsConstructor
@Entity
@Table(name = "CHILD")
public class Child
{
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "CHILD_ID")
@SequenceGenerator(name = "CHILD_ID", sequenceName = "CHILD_ID", allocationSize = 1)
@Column(name = "CHILD_ID")
private Long id;
// NO VERSION! Parent version should be incremented on change
// @Version
// @Column(name = "VERSION")
// private int version;
@ManyToOne(optional = false)
@JoinColumn(name = "PARENT_ID", referencedColumnName = "PARENT_ID")
private Parent parent;
@Column(name = "CHANGEABLE")
private String changeable;
}
You can find the full example on http://github.com/Meini777/example
What is the best way to implement it? I could code a @RestController on my own instead of using the implicit one from @RepositoryRestResource, but in this case i have implement all the behavior including HATEOAS and ALPS.