[ 
https://issues.apache.org/jira/browse/SOLR-6645?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Fabio Piro updated SOLR-6645:
-----------------------------
    Description: Edit  (was: Hello good people.

It is understandable that the priority of SolrJ is to provide a stable API for 
java and not a rich-feature client, I'm well aware of that. On the other hand 
more features nowadays mean most of the time Spring Solr Data. Although I 
appreciate the enrichment work of that lib, sometimes depending on its 
monolithic dependencies and magic is not a valid option.

So, I was thinking that the official DocumentObjectBinder could benefit from 
some love, and I had implemented a listener pattern for the annotations. 

*Note: No new logic or new annotations were introduced, the patch is only a 
refactor to make more extendible (for the user) the current 
DocumentObjectBinder and @Field DocField.*

You can register your annotations and they relate listeners in the binder, and 
it will invoke the corresponding method in the listener on getBean and on 
toSolrInputDocument, therefore granting the chance to do something during the 
ongoing process. Like this:

{code:java}
public static void main(String[] args) {
         Map<Class<? extends Annotation>, Class<? extends AnnotationListener>> 
annotations = new HashMap<>();
         annotations.put(FieldObject.class, 
FieldObjectAnnotationListener.class);
         annotations.put(Document.class, DocumentAnnotationListener.class);
         DocumentObjectBinder binder = new DocumentObjectBinder(annotations);

         SolrServer server = new HttpSolrServer("...");
         server.setBinder(binder);// reusable on many servers
}
{code}

Changes are:

* [MOD] */beans/DocumentObjectBinder*:  The new logic and a new constructor for 
registering the annotations
* [ADD] */impl/AccessorAnnotationListener*: Abstract utility class with the 
former get(), set(), isArray, isList, isContainedInMap etc...
* [ADD] */impl/FieldAnnotationListener*: all the rest of DocField for dealing 
with @Field
* [ADD] */AnnotationListener*: the base listener class
* [MOD] */SolrServer*: added setBinder (this is the only tricky change, I hope 
it's not a problem).

It's all well documented and the code is very easy to read. Tests are all 
green, it should be 100% backward compatible and the performance impact is void 
(the logic flow is exactly the same as now, and I only changed the bare 
essentials and nothing more, anyway).

Some Examples (they are not part of the pull-request):

The long awaited @FieldObject in 4 lines of code:

https://issues.apache.org/jira/browse/SOLR-1945

{code:java}
public class FieldObjectAnnotationListener extends 
AccessorAnnotationListener<FieldObject> {

    public FieldObjectAnnotationListener(AnnotatedElement element, FieldObject 
annotation) {
        super(element, annotation);
    }

    @Override
    public void onGetBean(Object obj, SolrDocument doc, DocumentObjectBinder 
binder) {
        Object nested = binder.getBean(target.clazz, doc);
        setTo(obj, nested);
    }

    @Override
    public void onToSolrInputDocument(Object obj, SolrInputDocument doc, 
DocumentObjectBinder binder) {
        SolrInputDocument nested = binder.toSolrInputDocument(getFrom(obj));

        for (Map.Entry<String, SolrInputField> entry : nested.entrySet()) {
            doc.addField(entry.getKey(), entry.getValue());
        }
    }
}
{code}

Or something entirely new like an annotation for ChildDocuments:

{code:java}
public class ChildDocumentsAnnotationListener extends 
AccessorAnnotationListener<ChildDocuments> {

    public ChildDocumentsAnnotationListener(AnnotatedElement element, 
ChildDocuments annotation) {
        super(element, annotation);

        if (!target.isInList || target.clazz.isPrimitive()) {
            throw new BindingException("@NestedDocuments is applicable only on 
List<Object>.");
        }
    }

    @Override
    public void onGetBean(Object obj, SolrDocument doc, DocumentObjectBinder 
binder) {
        List<Object> nested = new ArrayList<>();
        for (SolrDocument child : doc.getChildDocuments()) {
            nested.add(binder.getBean(target.clazz, child));// this should be 
recursive, but it's only an example
        }

        setTo(obj, nested);
    }

    @Override
    public void onToSolrInputDocument(Object obj, SolrInputDocument doc, 
DocumentObjectBinder binder) {
        SolrInputDocument nested = binder.toSolrInputDocument(getFrom(obj));
        doc.addChildDocuments(nested.getChildDocuments());
    }
}
{code}

In addition, all the logic is encapsulated in the listener, so you can make a 
custom FieldAnnotationListener too, and override the default one

{code:java}
public class CustomFieldAnnotationListener extends FieldAnnotationListener {

    private boolean isTransientPresent;

    public CustomFieldAnnotationListener(AnnotatedElement element, Field 
annotation) {
        super(element, annotation);
        this.isTransientPresent = element.isAnnotationPresent(Transient.class);
    }

    @Override
    public void onGetBean(Object obj, SolrDocument doc, DocumentObjectBinder 
binder) {
        if(!isTransientPresent){
            super.onGetBean(obj, doc, binder);
        }
    }

    @Override
    public void onToSolrInputDocument(Object obj, SolrInputDocument doc, 
DocumentObjectBinder binder) {
        if(!isTransientPresent){
            super.onToSolrInputDocument(obj, doc, binder);
        }
    }
}
{code}

I think this is a good solution for a win-win scenario:

- The code is almost unchanged (only shifted, wisely changed) so there is no 
new code to test and to support for the devs.

- People who only need the plain @Field will be untouched and unaware of the 
change.

- People who need some extra functionalities (like converters) can now easily 
extend the @Field logic, or make new annotations.

- With some luck, a Community-Driven repository with the most useful features 
can emerge.

- [Bonus] The binder is now entirely documented and not so scarier like before 
(we are almost at Halloween, but still... :) )

 The code is production-ready, if you are interested in merging it to the core, 
we can discuss the last touch (mainly what to leave protected and what to set 
private).

---
Update1: Added PATCH
)

> Refactored DocumentObjectBinder and added AnnotationListeners
> -------------------------------------------------------------
>
>                 Key: SOLR-6645
>                 URL: https://issues.apache.org/jira/browse/SOLR-6645
>             Project: Solr
>          Issue Type: Improvement
>          Components: clients - java
>    Affects Versions: 4.10.2
>            Reporter: Fabio Piro
>              Labels: annotations, binder, listener, solrj
>             Fix For: 5.0, Trunk
>
>
> Edit



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to