2

I am writing an insert query inside @Query annotation in a Spring application with PostGreSQL. So I am extending CRUD repository inside an interface that I have written.

@Repository
public interface PostGreRepository extends CrudRepository<FoodDetails,Long> {
@Modifying
    @Query(value="insert into fooddetails(person_id,food_desc)  select id,food_desc from person,food where id = " +
            "person_id",nativeQuery = true)
    void insertIntoPostGre();
}

Now I have the requirement to keep the query as a parameter in the application because it might change later. I cannot use @Value annotation inside an interface. So how can I parameterize this? Ideas?

Slaw
  • 37,820
  • 8
  • 53
  • 80
Mistu4u
  • 5,132
  • 15
  • 53
  • 91
  • 'Now I have the requirement to keep the query as a parameter in the application because it might change later' - could you please elaborate on that? One usually responds to changes in requirements by changing the code, why do you think it will be beneficial for this particular query to be externalized? – crizzis Jul 12 '19 at 19:55
  • @crizzis, That is how the client wants it! Actually this application is dependent on some other application who is not sending all the required data as of now, so later this query will change when the other application starts sending the missing data. – Mistu4u Jul 12 '19 at 20:01
  • Have you considered using `EntityManager`? – Yevgen Jul 12 '19 at 20:29
  • 2
    The obvious question is why are you writing a query to do the insert. Why can't you simply use the inherited `save(FoodDetails details);` When the client starts sending the missing data then populate FoodDetails accrdingly and you don't need to touch the persistence logic. – Alan Hay Jul 13 '19 at 08:36

1 Answers1

2

Just as an idea, use reflection to change annotation value:

Disclaimer: changeAnnotationValue method is taken from here, I haven't run it myself

@SuppressWarnings("unchecked")
public static Object changeAnnotationValue(Annotation annotation, String key, Object newValue){
    Object handler = Proxy.getInvocationHandler(annotation);
    Field f;
    try {
        f = handler.getClass().getDeclaredField("memberValues");
    } catch (NoSuchFieldException | SecurityException e) {
        throw new IllegalStateException(e);
    }
    f.setAccessible(true);
    Map<String, Object> memberValues;
    try {
        memberValues = (Map<String, Object>) f.get(handler);
    } catch (IllegalArgumentException | IllegalAccessException e) {
        throw new IllegalStateException(e);
    }
    Object oldValue = memberValues.get(key);
    if (oldValue == null || oldValue.getClass() != newValue.getClass()) {
        throw new IllegalArgumentException();
    }
    memberValues.put(key,newValue);
    return oldValue;
}

Using query as a parameter:

@Component
public class PostGreRepositoryParameterizer {
//...
   @Value("query")
   private String query;

   public void modify() {
      Method method = PostGreRepository.class.getMethod("insertIntoPostGre");
      final Query queryAnnotation = method.getAnnotation(Query.class);
      changeAnnotationValue(queryAnnotation, "value", query);
   }
//...
}

Dzmitry Bahdanovich
  • 1,735
  • 2
  • 17
  • 34