mirror of https://github.com/apache/lucene.git
SOLR-2708: Cleaned up DocumentObjectBinder
git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1158525 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
480fd0c8b5
commit
114df7a852
|
@ -0,0 +1,29 @@
|
|||
package org.apache.solr.client.solrj.beans;
|
||||
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
public class BindingException extends RuntimeException {
|
||||
|
||||
public BindingException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public BindingException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
|
@ -33,68 +33,66 @@ import java.nio.ByteBuffer;
|
|||
* @since solr 1.3
|
||||
*/
|
||||
public class DocumentObjectBinder {
|
||||
|
||||
private final Map<Class, List<DocField>> infocache = new ConcurrentHashMap<Class, List<DocField>>();
|
||||
|
||||
public DocumentObjectBinder() {
|
||||
}
|
||||
|
||||
public <T> List<T> getBeans(Class<T> clazz, SolrDocumentList solrDocList) {
|
||||
List<DocField> fields = getDocFields( clazz );
|
||||
List<DocField> fields = getDocFields(clazz);
|
||||
List<T> result = new ArrayList<T>(solrDocList.size());
|
||||
|
||||
for(int j=0;j<solrDocList.size();j++) {
|
||||
SolrDocument sdoc = solrDocList.get(j);
|
||||
result.add(getBean(clazz, fields, sdoc));
|
||||
for (SolrDocument sdoc : solrDocList) {
|
||||
result.add(getBean(clazz, fields, sdoc));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public <T> T getBean(Class<T> clazz, SolrDocument solrDoc) {
|
||||
return getBean(clazz, null,solrDoc);
|
||||
return getBean(clazz, null, solrDoc);
|
||||
}
|
||||
|
||||
private <T> T getBean(Class<T> clazz, List<DocField> fields, SolrDocument solrDoc) {
|
||||
if (fields == null) {
|
||||
fields = getDocFields(clazz);
|
||||
}
|
||||
T obj = null;
|
||||
|
||||
try {
|
||||
obj = clazz.newInstance();
|
||||
T obj = clazz.newInstance();
|
||||
for (DocField docField : fields) {
|
||||
docField.inject(obj, solrDoc);
|
||||
}
|
||||
return obj;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Could not instantiate object of " + clazz, e);
|
||||
throw new BindingException("Could not instantiate object of " + clazz, e);
|
||||
}
|
||||
for (int i = 0; i < fields.size(); i++) {
|
||||
DocField docField = fields.get(i);
|
||||
docField.inject(obj, solrDoc);
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
public SolrInputDocument toSolrInputDocument( Object obj )
|
||||
{
|
||||
List<DocField> fields = getDocFields( obj.getClass() );
|
||||
if( fields.isEmpty() ) {
|
||||
throw new RuntimeException( "class: "+obj.getClass()+" does not define any fields." );
|
||||
public SolrInputDocument toSolrInputDocument(Object obj) {
|
||||
List<DocField> fields = getDocFields(obj.getClass());
|
||||
if (fields.isEmpty()) {
|
||||
throw new BindingException("class: " + obj.getClass() + " does not define any fields.");
|
||||
}
|
||||
|
||||
SolrInputDocument doc = new SolrInputDocument();
|
||||
for (DocField field : fields) {
|
||||
if (field.dynamicFieldNamePatternMatcher != null
|
||||
&& field.get(obj) != null && field.isContainedInMap) {
|
||||
Map<String, Object> mapValue = (HashMap<String, Object>) field
|
||||
.get(obj);
|
||||
|
||||
for (Map.Entry<String, Object> e : mapValue.entrySet()) {
|
||||
doc.setField( e.getKey(), e.getValue(), 1.0f);
|
||||
}
|
||||
} else {
|
||||
doc.setField(field.name, field.get(obj), 1.0f);
|
||||
}
|
||||
SolrInputDocument doc = new SolrInputDocument();
|
||||
for (DocField field : fields) {
|
||||
if (field.dynamicFieldNamePatternMatcher != null &&
|
||||
field.get(obj) != null &&
|
||||
field.isContainedInMap) {
|
||||
Map<String, Object> mapValue = (Map<String, Object>) field.get(obj);
|
||||
|
||||
for (Map.Entry<String, Object> e : mapValue.entrySet()) {
|
||||
doc.setField(e.getKey(), e.getValue(), 1.0f);
|
||||
}
|
||||
} else {
|
||||
doc.setField(field.name, field.get(obj), 1.0f);
|
||||
}
|
||||
}
|
||||
return doc;
|
||||
}
|
||||
|
||||
private List<DocField> getDocFields( Class clazz )
|
||||
{
|
||||
private List<DocField> getDocFields(Class clazz) {
|
||||
List<DocField> fields = infocache.get(clazz);
|
||||
if (fields == null) {
|
||||
synchronized(infocache) {
|
||||
|
@ -107,12 +105,14 @@ public class DocumentObjectBinder {
|
|||
private List<DocField> collectInfo(Class clazz) {
|
||||
List<DocField> fields = new ArrayList<DocField>();
|
||||
Class superClazz = clazz;
|
||||
ArrayList<AccessibleObject> members = new ArrayList<AccessibleObject>();
|
||||
List<AccessibleObject> members = new ArrayList<AccessibleObject>();
|
||||
|
||||
while (superClazz != null && superClazz != Object.class) {
|
||||
members.addAll(Arrays.asList(superClazz.getDeclaredFields()));
|
||||
members.addAll(Arrays.asList(superClazz.getDeclaredMethods()));
|
||||
superClazz = superClazz.getSuperclass();
|
||||
}
|
||||
|
||||
for (AccessibleObject member : members) {
|
||||
if (member.isAnnotationPresent(Field.class)) {
|
||||
member.setAccessible(true);
|
||||
|
@ -128,14 +128,15 @@ public class DocumentObjectBinder {
|
|||
private Method setter;
|
||||
private Method getter;
|
||||
private Class type;
|
||||
private boolean isArray = false, isList=false;
|
||||
private boolean isArray;
|
||||
private boolean isList;
|
||||
|
||||
/*
|
||||
* dynamic fields may use a Map based data structure to bind a given field.
|
||||
* if a mapping is done using, "Map<String, List<String>> foo", <code>isContainedInMap</code>
|
||||
* is set to <code>TRUE</code> as well as <code>isList</code> is set to <code>TRUE</code>
|
||||
*/
|
||||
boolean isContainedInMap =false;
|
||||
private boolean isContainedInMap;
|
||||
private Pattern dynamicFieldNamePatternMatcher;
|
||||
|
||||
public DocField(AccessibleObject member) {
|
||||
|
@ -149,21 +150,19 @@ public class DocumentObjectBinder {
|
|||
storeType();
|
||||
|
||||
// Look for a matching getter
|
||||
if( setter != null ) {
|
||||
if (setter != null) {
|
||||
String gname = setter.getName();
|
||||
if( gname.startsWith("set") ) {
|
||||
if (gname.startsWith("set")) {
|
||||
gname = "get" + gname.substring(3);
|
||||
try {
|
||||
getter = setter.getDeclaringClass().getMethod( gname, (Class[])null );
|
||||
}
|
||||
catch( Exception ex ) {
|
||||
getter = setter.getDeclaringClass().getMethod(gname, (Class[]) null);
|
||||
} catch( Exception ex ) {
|
||||
// no getter -- don't worry about it...
|
||||
if( type == Boolean.class ) {
|
||||
gname = "is" + setter.getName().substring( 3 );
|
||||
if (type == Boolean.class) {
|
||||
gname = "is" + setter.getName().substring(3);
|
||||
try {
|
||||
getter = setter.getDeclaringClass().getMethod( gname, (Class[])null );
|
||||
}
|
||||
catch( Exception ex2 ) {
|
||||
getter = setter.getDeclaringClass().getMethod(gname, (Class[]) null);
|
||||
} catch(Exception ex2) {
|
||||
// no getter -- don't worry about it...
|
||||
}
|
||||
}
|
||||
|
@ -184,9 +183,7 @@ public class DocumentObjectBinder {
|
|||
name = setter.getName();
|
||||
}
|
||||
}
|
||||
}
|
||||
//dynamic fields are annotated as @Field("categories_*")
|
||||
else if(annotation.value().indexOf('*') >= 0){
|
||||
} else if(annotation.value().indexOf('*') >= 0){ //dynamic fields are annotated as @Field("categories_*")
|
||||
//if the field was annotated as a dynamic field, convert the name into a pattern
|
||||
//the wildcard (*) is supposed to be either a prefix or a suffix, hence the use of replaceFirst
|
||||
name = annotation.value().replaceFirst("\\*", "\\.*");
|
||||
|
@ -201,66 +198,52 @@ public class DocumentObjectBinder {
|
|||
type = field.getType();
|
||||
} else {
|
||||
Class[] params = setter.getParameterTypes();
|
||||
if (params.length != 1)
|
||||
throw new RuntimeException("Invalid setter method. Must have one and only one parameter");
|
||||
if (params.length != 1) {
|
||||
throw new BindingException("Invalid setter method. Must have one and only one parameter");
|
||||
}
|
||||
type = params[0];
|
||||
}
|
||||
|
||||
if(type == Collection.class || type == List.class || type == ArrayList.class) {
|
||||
type = Object.class;
|
||||
isList = true;
|
||||
/*ParameterizedType parameterizedType = null;
|
||||
if(field !=null){
|
||||
if( field.getGenericType() instanceof ParameterizedType){
|
||||
parameterizedType = (ParameterizedType) field.getGenericType();
|
||||
Type[] types = parameterizedType.getActualTypeArguments();
|
||||
if (types != null && types.length > 0) type = (Class) types[0];
|
||||
}
|
||||
}*/
|
||||
} else if(type == byte[].class){
|
||||
} else if (type == byte[].class) {
|
||||
//no op
|
||||
}else if (type.isArray()) {
|
||||
} else if (type.isArray()) {
|
||||
isArray = true;
|
||||
type = type.getComponentType();
|
||||
}
|
||||
//corresponding to the support for dynamicFields
|
||||
else if (type == Map.class || type == HashMap.class) {
|
||||
} else if (type == Map.class || type == HashMap.class) { //corresponding to the support for dynamicFields
|
||||
isContainedInMap = true;
|
||||
//assigned a default type
|
||||
type = Object.class;
|
||||
if(field != null){
|
||||
if(field.getGenericType() instanceof ParameterizedType){
|
||||
if (field != null) {
|
||||
if (field.getGenericType() instanceof ParameterizedType) {
|
||||
//check what are the generic values
|
||||
ParameterizedType parameterizedType = (ParameterizedType) field.getGenericType();
|
||||
Type[] types = parameterizedType.getActualTypeArguments();
|
||||
if(types != null && types.length == 2 && types[0] == String.class){
|
||||
if (types != null && types.length == 2 && types[0] == String.class) {
|
||||
//the key should always be String
|
||||
//Raw and primitive types
|
||||
if(types[1] instanceof Class){
|
||||
//the value could be multivalued then it is a List ,Collection,ArrayList
|
||||
if (types[1] instanceof Class) {
|
||||
//the value could be multivalued then it is a List, Collection, ArrayList
|
||||
if(types[1]== Collection.class || types[1] == List.class || types[1] == ArrayList.class){
|
||||
type = Object.class;
|
||||
isList = true;
|
||||
}else{
|
||||
} else{
|
||||
//else assume it is a primitive and put in the source type itself
|
||||
type = (Class) types[1];
|
||||
}
|
||||
}
|
||||
//Of all the Parameterized types, only List is supported
|
||||
else if(types[1] instanceof ParameterizedType){
|
||||
} else if( types[1] instanceof ParameterizedType) { //Of all the Parameterized types, only List is supported
|
||||
Type rawType = ((ParameterizedType)types[1]).getRawType();
|
||||
if(rawType== Collection.class || rawType == List.class || rawType == ArrayList.class){
|
||||
type = Object.class;
|
||||
isList = true;
|
||||
}
|
||||
}
|
||||
//Array types
|
||||
else if(types[1] instanceof GenericArrayType){
|
||||
} else if (types[1] instanceof GenericArrayType) { //Array types
|
||||
type = (Class) ((GenericArrayType) types[1]).getGenericComponentType();
|
||||
isArray = true;
|
||||
}
|
||||
//Throw an Exception if types are not known
|
||||
else{
|
||||
throw new RuntimeException("Allowed type for values of mapping a dynamicField are : " +
|
||||
} else { //Throw an Exception if types are not known
|
||||
throw new BindingException("Allowed type for values of mapping a dynamicField are : " +
|
||||
"Object, Object[] and List");
|
||||
}
|
||||
}
|
||||
|
@ -279,31 +262,35 @@ public class DocumentObjectBinder {
|
|||
@SuppressWarnings("unchecked")
|
||||
private Object getFieldValue(SolrDocument sdoc){
|
||||
Object fieldValue = sdoc.getFieldValue(name);
|
||||
if(fieldValue != null) {
|
||||
if (fieldValue != null) {
|
||||
//this is not a dynamic field. so return te value
|
||||
return fieldValue;
|
||||
}
|
||||
//reading dynamic field values
|
||||
if(dynamicFieldNamePatternMatcher != null){
|
||||
if (dynamicFieldNamePatternMatcher != null) {
|
||||
Map<String, Object> allValuesMap = null;
|
||||
ArrayList allValuesList = null;
|
||||
if(isContainedInMap){
|
||||
List allValuesList = null;
|
||||
if (isContainedInMap) {
|
||||
allValuesMap = new HashMap<String, Object>();
|
||||
} else {
|
||||
allValuesList = new ArrayList();
|
||||
}
|
||||
for(String field : sdoc.getFieldNames()){
|
||||
if(dynamicFieldNamePatternMatcher.matcher(field).find()){
|
||||
|
||||
for (String field : sdoc.getFieldNames()) {
|
||||
if (dynamicFieldNamePatternMatcher.matcher(field).find()) {
|
||||
Object val = sdoc.getFieldValue(field);
|
||||
if(val == null) continue;
|
||||
if(isContainedInMap){
|
||||
if(isList){
|
||||
if (val == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isContainedInMap) {
|
||||
if (isList) {
|
||||
if (!(val instanceof List)) {
|
||||
ArrayList al = new ArrayList();
|
||||
List al = new ArrayList();
|
||||
al.add(val);
|
||||
val = al;
|
||||
}
|
||||
} else if(isArray){
|
||||
} else if (isArray) {
|
||||
if (!(val instanceof List)) {
|
||||
Object[] arr= (Object[]) Array.newInstance(type,1);
|
||||
arr[0] = val;
|
||||
|
@ -313,7 +300,7 @@ public class DocumentObjectBinder {
|
|||
}
|
||||
}
|
||||
allValuesMap.put(field, val);
|
||||
}else {
|
||||
} else {
|
||||
if (val instanceof Collection) {
|
||||
allValuesList.addAll((Collection) val);
|
||||
} else {
|
||||
|
@ -330,31 +317,33 @@ public class DocumentObjectBinder {
|
|||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
<T> void inject(T obj, SolrDocument sdoc) {
|
||||
Object val = getFieldValue(sdoc);
|
||||
if(val == null) {
|
||||
return;
|
||||
}
|
||||
if(isArray && !isContainedInMap){
|
||||
List list = null;
|
||||
if(val.getClass().isArray()){
|
||||
|
||||
if (isArray && !isContainedInMap) {
|
||||
List list;
|
||||
if (val.getClass().isArray()) {
|
||||
set(obj,val);
|
||||
return;
|
||||
} else if (val instanceof List) {
|
||||
list = (List) val;
|
||||
} else{
|
||||
} else {
|
||||
list = new ArrayList();
|
||||
list.add(val);
|
||||
}
|
||||
set(obj, list.toArray((Object[]) Array.newInstance(type,list.size())));
|
||||
} else if(isList && !isContainedInMap){
|
||||
set(obj, list.toArray((Object[]) Array.newInstance(type,list.size())));
|
||||
} else if (isList && !isContainedInMap) {
|
||||
if (!(val instanceof List)) {
|
||||
ArrayList list = new ArrayList();
|
||||
List list = new ArrayList();
|
||||
list.add(val);
|
||||
val = list;
|
||||
}
|
||||
set(obj, val);
|
||||
} else if(isContainedInMap){
|
||||
} else if (isContainedInMap) {
|
||||
if (val instanceof Map) {
|
||||
set(obj, val);
|
||||
}
|
||||
|
@ -366,8 +355,8 @@ public class DocumentObjectBinder {
|
|||
|
||||
|
||||
private void set(Object obj, Object v) {
|
||||
if(v!= null && type == ByteBuffer.class && v.getClass()== byte[].class) {
|
||||
v = ByteBuffer.wrap((byte[])v);
|
||||
if (v != null && type == ByteBuffer.class && v.getClass() == byte[].class) {
|
||||
v = ByteBuffer.wrap((byte[]) v);
|
||||
}
|
||||
try {
|
||||
if (field != null) {
|
||||
|
@ -377,29 +366,25 @@ public class DocumentObjectBinder {
|
|||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException("Exception while setting value : "+v+" on " + (field != null ? field : setter), e);
|
||||
throw new BindingException("Exception while setting value : " + v + " on " + (field != null ? field : setter), e);
|
||||
}
|
||||
}
|
||||
|
||||
public Object get( final Object obj )
|
||||
{
|
||||
|
||||
public Object get(final Object obj) {
|
||||
if (field != null) {
|
||||
try {
|
||||
return field.get(obj);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException("Exception while getting value: " + field, e);
|
||||
} catch (Exception e) {
|
||||
throw new BindingException("Exception while getting value: " + field, e);
|
||||
}
|
||||
} else if (getter == null) {
|
||||
throw new BindingException("Missing getter for field: " + name + " -- You can only call the 'get' for fields that have a field of 'get' method");
|
||||
}
|
||||
else if (getter == null) {
|
||||
throw new RuntimeException( "Missing getter for field: "+name+" -- You can only call the 'get' for fields that have a field of 'get' method" );
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
return getter.invoke( obj, (Object[])null );
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException("Exception while getting value: " + getter, e);
|
||||
return getter.invoke(obj, (Object[]) null);
|
||||
} catch (Exception e) {
|
||||
throw new BindingException("Exception while getting value: " + getter, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue