[
https://issues.apache.org/jira/browse/SOLR-6645?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Fabio Piro reopened SOLR-6645:
------------------------------
> 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
>
>
> 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
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]