javaspring-bootreflectionsolrspring-data-solr

Unable to set SolrDocument annotation at RUNTIME


I am using Spring Data Solr and I have the following Solr document model class and have a corresponding SolrCrudRepository for this class

@SolrDocument(collection = "oldCollectionName")
public class TestDocument {

            @Id
            @Indexed(name = "id", type = "string")
            private String id;

            @Field(value = "name")
            private String name;

            @Field(value = "externalid")
            private Integer externalId;
}

I am trying to modify the annotation '@SolrDocument(collection = "oldCollectionName")' at runtime.

I have a Service which has the following method to find all documents using the repository and the model class

public List<TestDocument> getDocumentsByName(String name){

        String newSolrDocument = getModifiedSolrCollectionName();
        alterAnnotationValue(TestDocument.class, SolrDocument.class, newSolrDocument);

        SolrDocument solrDocument = TestDocument.class.getAnnotation(SolrDocument.class);

        LOGGER.info("Dynamically set SolrDocument Annotaation: "+solrDocument.collection());

        return testDocumentRepository.findByName(name);
    }

The code to alter annotation looks like this

   public void alterAnnotationValue(Class<?> targetClass, Class<? extends Annotation> targetAnnotation, Annotation targetValue) {
        try {
            Method method = Class.class.getDeclaredMethod(ANNOTATION_METHOD, null);
            method.setAccessible(true);

            Object annotationData = method.invoke(targetClass);

            Field annotations = annotationData.getClass().getDeclaredField(ANNOTATIONS);
            annotations.setAccessible(true);

            Map<Class<? extends Annotation>, Annotation> map = (Map<Class<? extends Annotation>, Annotation>) annotations.get(annotationData);
            map.put(targetAnnotation, targetValue);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

Using this I am correctly getting the newDocumentName set into the annotation map but when calling the testDocumentRepository's find method to find documents. The old collection name is getting picked.

Do I have to do something more for this to work? or I am missing anything?

For reference, I have followed the following tutorial http://www.baeldung.com/java-reflection-change-annotation-params


Solution

  • Why don't you just write a custom SolrRepository to solve this? You can inject a SolrTemplate in your custom repository, allowing you to specify a collection for your query like so:

    public class TestDocumentRepositoryImpl implements TestDocumentRepository {
    
        private SolrOperations solrTemplate;
        ...
        public CustomSolrRepositoryImpl(SolrOperations solrTemplate) {
            super();
            this.solrTemplate = solrTemplate;
        }
    
        @Override
        public TestDocument findOneSpecifyingCollection(String collection, String id) {
            return solrTemplate.getById(collection, id, TestDocument.class);
        }
    }
    

    You can do that similarly for repository operation you'd like. People typically need their own implementations if the standard Spring JPA Repositories don't suit their needs. However, you can still mix your own with the standard SolrCrudRepository if that's desirable.

    See this for an example from Spring.