Looks like thread is old, I just wanted to add my solution here(Using AspectJ - AOP in spring).
Solution is to create a custom annotation @InjectSequenceValue
as follows.
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface InjectSequenceValue {
String sequencename();
}
Now you can annotate any field in entity, so that the underlying field (Long/Integer) value will be injected at runtime using the nextvalue of the sequence.
Annotate like this.
//serialNumber will be injected dynamically, with the next value of the serialnum_sequence.
@InjectSequenceValue(sequencename = "serialnum_sequence")
Long serialNumber;
So far we have marked the field we need to inject the sequence value.So we will look how to inject the sequence value to the marked fields, this is done by creating the point cut in AspectJ.
We will trigger the injection just before the save/persist
method is being executed.This is done in the below class.
@Aspect
@Configuration
public class AspectDefinition {
@Autowired
JdbcTemplate jdbcTemplate;
//@Before("execution(* org.hibernate.session.save(..))") Use this for Hibernate.(also include session.save())
@Before("execution(* org.springframework.data.repository.CrudRepository.save(..))") //This is for JPA.
public void generateSequence(JoinPoint joinPoint){
Object [] aragumentList=joinPoint.getArgs(); //Getting all arguments of the save
for (Object arg :aragumentList ) {
if (arg.getClass().isAnnotationPresent(Entity.class)){ // getting the Entity class
Field[] fields = arg.getClass().getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(InjectSequenceValue.class)) { //getting annotated fields
field.setAccessible(true);
try {
if (field.get(arg) == null){ // Setting the next value
String sequenceName=field.getAnnotation(InjectSequenceValue.class).sequencename();
long nextval=getNextValue(sequenceName);
System.out.println("Next value :"+nextval); //TODO remove sout.
field.set(arg, nextval);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
}
/**
* This method fetches the next value from sequence
* @param sequence
* @return
*/
public long getNextValue(String sequence){
long sequenceNextVal=0L;
SqlRowSet sqlRowSet= jdbcTemplate.queryForRowSet("SELECT "+sequence+".NEXTVAL as value FROM DUAL");
while (sqlRowSet.next()){
sequenceNextVal=sqlRowSet.getLong("value");
}
return sequenceNextVal;
}
}
Now you can annotate any Entity as below.
@Entity
@Table(name = "T_USER")
public class UserEntity {
@Id
@SequenceGenerator(sequenceName = "userid_sequence",name = "this_seq")
@GeneratedValue(strategy = GenerationType.SEQUENCE,generator = "this_seq")
Long id;
String userName;
String password;
@InjectSequenceValue(sequencename = "serialnum_sequence") // this will be injected at the time of saving.
Long serialNumber;
String name;
}