Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CAPI-571 Fix SolrJ Bind Nested Child DTO Fields #63

Open
wants to merge 1 commit into
base: bw_branch_8_11_2
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,10 @@ public SolrInputDocument toSolrInputDocument(Object obj) {
doc.setField(e.getKey(), e.getValue());
}
} else {
if (field.child != null) {
addChild(obj, field, doc);
if (field.child != null && field.annotation.anonymizeChild()) {
addAnonymousChild(obj, field, doc);
} else if (field.child != null) {
addNestedChild(obj, field, doc);
} else {
doc.setField(field.name, field.get(obj));
}
Expand All @@ -101,7 +103,7 @@ public SolrInputDocument toSolrInputDocument(Object obj) {
return doc;
}

private void addChild(Object obj, DocField field, SolrInputDocument doc) {
private void addAnonymousChild(Object obj, DocField field, SolrInputDocument doc) {
Object val = field.get(obj);
if (val == null) return;
if (val instanceof Collection) {
Expand All @@ -119,6 +121,31 @@ private void addChild(Object obj, DocField field, SolrInputDocument doc) {
}
}

private void addNestedChild(Object obj, DocField field, SolrInputDocument doc) {
Object val = field.get(obj);
if (val == null) return;
if (val instanceof Collection) {
@SuppressWarnings({"rawtypes"})
Collection collection = (Collection) val;
List<SolrInputDocument> docs = new ArrayList<>(collection.size());
for (final Object o : collection) {
final SolrInputDocument inpDoc = toSolrInputDocument(o);
docs.add(inpDoc);
}
val = docs;
} else if (val.getClass().isArray()) {
Object[] objs = (Object[]) val;
SolrInputDocument[] docs = (SolrInputDocument[]) Array.newInstance(SolrInputDocument.class, objs.length);
for (int i = 0; i < objs.length; i++) {
docs[i] = toSolrInputDocument(objs[i]);
}
val = docs;
} else {
val = toSolrInputDocument(val);
}
doc.addField(field.name, val);
}

private List<DocField> getDocFields(@SuppressWarnings({"rawtypes"})Class clazz) {
List<DocField> fields = infocache.get(clazz);
if (fields == null) {
Expand Down Expand Up @@ -146,7 +173,7 @@ private List<DocField> collectInfo(@SuppressWarnings({"rawtypes"})Class clazz) {
if (member.isAnnotationPresent(Field.class)) {
AccessController.doPrivileged((PrivilegedAction<Void>) () -> { member.setAccessible(true); return null; });
DocField df = new DocField(member);
if (df.child != null) {
if (df.child != null && df.annotation.anonymizeChild()) {
if (childFieldFound)
throw new BindingException(clazz.getName() + " cannot have more than one Field with child=true");
childFieldFound = true;
Expand Down Expand Up @@ -334,7 +361,20 @@ private void populateChild(Type typ) {
@SuppressWarnings({"unchecked", "rawtypes"})
private Object getFieldValue(SolrDocument solrDocument) {
if (child != null) {
List<SolrDocument> children = solrDocument.getChildDocuments();
List<SolrDocument> children = null;
if(solrDocument.hasChildDocuments()){
children = solrDocument.getChildDocuments();
} else if (!annotation.anonymizeChild()){
final Object val = solrDocument.getFieldValue(name);
if(val == null){
return null;
} else if (isList || isArray) {
children = (List<SolrDocument>) val;
} else {
children = new ArrayList<>();
children.add((SolrDocument) val);
}
}
if (children == null || children.isEmpty()) return null;
if (isList) {
ArrayList list = new ArrayList(children.size());
Expand Down
11 changes: 11 additions & 0 deletions solr/solrj/src/java/org/apache/solr/client/solrj/beans/Field.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,16 @@
@Retention(RUNTIME)
public @interface Field {
boolean child() default false;

/**
* When converting fields with the `@Field(child=true)` annotation, this will
* determine if they should be converted as an anonymized nested child document
* or as a regular (mapped) nested child document.
*
* If intending to use `AtomicUpdates` or `ChildDocumentTransformer`, this
* should be set to `false`.
*/
boolean anonymizeChild() default true;

String value() default DEFAULT;
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@
import org.junit.Test;

import java.io.StringReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -151,10 +153,124 @@ public void testChild() throws Exception {
assertEquals(arrIn.child[1].name, arrOut.child[1].name);

}
public void testMappedChild() throws Exception {
DocumentObjectBinder binder = new DocumentObjectBinder();

Child childOne = new Child();
childOne.id = "1.1";
childOne.name = "Name One";
Child childTwo = new Child();
childTwo.id = "1.2";
childTwo.name = "Name Two";
Child childThree = new Child();
childThree.id = "1.3";
childThree.name = "Name Three";
Child childFour = new Child();
childFour.id = "1.4";
childFour.name = "Name Four";

SingleValueNestedChild nestedNullChildIn = new SingleValueNestedChild();
nestedNullChildIn.id = "1-null-child";
nestedNullChildIn.child = null;
SolrInputDocument nestedNullSolrInputDoc = binder.toSolrInputDocument(nestedNullChildIn);
SolrDocument nestedNullSolrDoc = toSolrDocument(nestedNullSolrInputDoc);
assertNull(nestedNullSolrInputDoc.getChildDocuments());
assertNull(nestedNullSolrDoc.getChildDocuments());
SingleValueNestedChild nestedNullChildOut = binder.getBean(SingleValueNestedChild.class, nestedNullSolrDoc);
assertEquals(nestedNullChildIn.id, nestedNullChildOut.id);
assertNull(nestedNullChildIn.child);
assertNull(nestedNullChildOut.child);

SingleValueNestedChild singleNestedIn = new SingleValueNestedChild();
singleNestedIn.id = "1";
singleNestedIn.child = childOne;
SolrInputDocument singleNestedSolrInputDoc = binder.toSolrInputDocument(singleNestedIn);
SolrDocument singleNestedSolrDoc = toSolrDocument(singleNestedSolrInputDoc);
assertNull(singleNestedSolrInputDoc.getChildDocuments());
assertNull(singleNestedSolrDoc.getChildDocuments());
SingleValueNestedChild singleNestedOut = binder.getBean(SingleValueNestedChild.class, singleNestedSolrDoc);
assertEquals(singleNestedIn.id, singleNestedOut.id);
assertEquals(singleNestedIn.child.id, singleNestedOut.child.id);
assertEquals(singleNestedIn.child.name, singleNestedOut.child.name);

ListNestedChild listNestedIn = new ListNestedChild();
listNestedIn.id = "2";
listNestedIn.child = Arrays.asList(childOne, childTwo);
SolrInputDocument listNestedSolrInputDoc = binder.toSolrInputDocument(listNestedIn);
SolrDocument listNestedSolrDoc = toSolrDocument(listNestedSolrInputDoc);
assertNull(listNestedSolrInputDoc.getChildDocuments());
assertNull(listNestedSolrDoc.getChildDocuments());
ListNestedChild listNestedOut = binder.getBean(ListNestedChild.class, listNestedSolrDoc);
assertEquals(listNestedIn.id, listNestedOut.id);
assertEquals(listNestedIn.child.get(0).id, listNestedOut.child.get(0).id);
assertEquals(listNestedIn.child.get(0).name, listNestedOut.child.get(0).name);
assertEquals(listNestedIn.child.get(1).id, listNestedOut.child.get(1).id);
assertEquals(listNestedIn.child.get(1).name, listNestedOut.child.get(1).name);

ArrayNestedChild arrayNestedIn = new ArrayNestedChild();
arrayNestedIn.id = "3";
arrayNestedIn.child = new Child[]{childOne, childTwo};
SolrInputDocument arrayNestedSolrInputDoc = binder.toSolrInputDocument(arrayNestedIn);
SolrDocument arrayNestedSolrDoc = toSolrDocument(arrayNestedSolrInputDoc);
assertNull(arrayNestedSolrInputDoc.getChildDocuments());
assertNull(arrayNestedSolrDoc.getChildDocuments());
ArrayNestedChild arrayNestedOut = binder.getBean(ArrayNestedChild.class, arrayNestedSolrDoc);
assertEquals(arrayNestedIn.id, arrayNestedOut.id);
assertEquals(arrayNestedIn.child[0].id, arrayNestedOut.child[0].id);
assertEquals(arrayNestedIn.child[0].name, arrayNestedOut.child[0].name);
assertEquals(arrayNestedIn.child[1].id, arrayNestedOut.child[1].id);
assertEquals(arrayNestedIn.child[1].name, arrayNestedOut.child[1].name);

MultipleNestedArrayChild multipleNestedIn = new MultipleNestedArrayChild();
multipleNestedIn.id = "4";
multipleNestedIn.favorite = childOne;
multipleNestedIn.bestChildren = new Child[]{childTwo, childThree};
multipleNestedIn.worstChildren = new Child[]{childFour};
SolrInputDocument multipleNestedSolrInputDoc = binder.toSolrInputDocument(multipleNestedIn);
SolrDocument multipleNestedSolrDoc = toSolrDocument(multipleNestedSolrInputDoc);
assertNull(multipleNestedSolrInputDoc.getChildDocuments());
assertNull(multipleNestedSolrDoc.getChildDocuments());
MultipleNestedArrayChild multipleNestedOut = binder.getBean(MultipleNestedArrayChild.class, multipleNestedSolrDoc);
assertEquals(multipleNestedIn.id, multipleNestedOut.id);
assertEquals(multipleNestedIn.favorite.id, multipleNestedOut.favorite.id);
assertEquals(multipleNestedIn.favorite.name, multipleNestedOut.favorite.name);
assertEquals(multipleNestedIn.bestChildren[0].id, multipleNestedOut.bestChildren[0].id);
assertEquals(multipleNestedIn.bestChildren[0].name, multipleNestedOut.bestChildren[0].name);
assertEquals(multipleNestedIn.bestChildren[1].id, multipleNestedOut.bestChildren[1].id);
assertEquals(multipleNestedIn.bestChildren[1].name, multipleNestedOut.bestChildren[1].name);
assertEquals(multipleNestedIn.worstChildren[0].id, multipleNestedOut.worstChildren[0].id);
assertEquals(multipleNestedIn.worstChildren[0].name, multipleNestedOut.worstChildren[0].name);
}

private static SolrDocument toSolrDocument(SolrInputDocument d) {
SolrDocument doc = new SolrDocument();
for (SolrInputField field : d) {
if (field.getValue() != null) {
if (field.getValue() instanceof Collection) {
Collection<?> values = (Collection<?>) field.getValue();
if (!values.isEmpty() && values.iterator().next() instanceof SolrInputDocument) {
List<SolrDocument> docs = new ArrayList<>(values.size());
for (Object value : values) {
docs.add(toSolrDocument((SolrInputDocument) value));
}
doc.setField(field.getName(), docs);
continue;
}
} else if (field.getValue().getClass().isArray()) {
Object[] values = (Object[]) field.getValue();
if (values.length > 0 && values[0] instanceof SolrInputDocument) {
SolrDocument[] docs = new SolrDocument[values.length];
for (int i = 0; i < values.length; i++) {
docs[i] = toSolrDocument((SolrInputDocument) values[i]);
}
doc.setField(field.getName(), docs);
continue;
}
} else if (field.getValue() instanceof SolrInputDocument) {
doc.setField(field.getName(), toSolrDocument((SolrInputDocument) field.getValue()));
continue;
}
}
doc.setField(field.getName(), field.getValue());
}
if (d.getChildDocuments() != null) {
Expand Down Expand Up @@ -245,7 +361,48 @@ public static class ArrayChild {
@Field(child = true)
Child[] child;
}


public static class SingleValueNestedChild {
@Field
String id;

@Field(child = true, anonymizeChild = false)
Child child;
}

public static class ListNestedChild {

@Field
String id;

@Field(child = true, anonymizeChild = false)
List<Child> child;
}

public static class ArrayNestedChild {

@Field
String id;

@Field(child = true, anonymizeChild = false)
Child[] child;
}

public static class MultipleNestedArrayChild {

@Field
String id;

@Field(child = true, anonymizeChild = false)
Child favorite;

@Field(child = true, anonymizeChild = false)
Child[] bestChildren;

@Field(child = true, anonymizeChild = false)
Child[] worstChildren;

}

public static class NotGettableItem {
@Field
Expand Down
Loading