员工Bean类:
public class Employee2 {
private String id;
private String name;
private String designation;
private double salary;
private double totalExperience;
// private Address2 address2;
private Collection<Technology2> technologies2;
private String content_type = "employee2";
public Employee2() {
super();
}
public Employee2(String id, String name, String designation, double salary, double totalExperience,
Collection<Technology2> technologies2) {
super();
this.id = id;
this.name = name;
this.designation = designation;
this.salary = salary;
this.totalExperience = totalExperience;
// this.address2 = address2;
this.technologies2 = technologies2;
}
/**
* @return the id
*/
public String getId() {
return id;
}
/**
* @param id the id to set
*/
@Field (value = "id")
public void setId(String id) {
this.id = id;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
@Field (value = "name")
public void setName(String name) {
this.name = name;
}
/**
* @return the designation
*/
public String getDesignation() {
return designation;
}
/**
* @param designation the designation to set
*/
@Field (value = "designation_s")
public void setDesignation(String designation) {
this.designation = designation;
}
/**
* @return the salary
*/
public double getSalary() {
return salary;
}
/**
* @param salary the salary to set
*/
@Field (value = "salary_d")
public void setSalary(double salary) {
this.salary = salary;
}
/**
* @return the totalExperience
*/
public double getTotalExperience() {
return totalExperience;
}
/**
* @param totalExperience the totalExperience to set
*/
@Field (value = "totalExperience_d")
public void setTotalExperience(double totalExperience) {
this.totalExperience = totalExperience;
}
// /**
// * @return the address2
// */
// public Address2 getAddress() {
// return address2;
// }
//
// /**
// * @param address2 the address2 to set
// */
// @Field (child = true)
// public void setAddress(Address2 address2) {
// this.address2 = address2;
// }
/**
* @return the technologies2
*/
public Collection<Technology2> getTechnologies2() {
return technologies2;
}
/**
* @param technologies2 the technologies2 to set
*/
@Field (child = true)
public void setTechnologies2(Collection<Technology2> technologies2) {
this.technologies2 = technologies2;
}
/**
* @return the content_type
*/
public String getContent_type() {
return content_type;
}
/**
* @param content_type the content_type to set
*/
@Field(value="content_type_t")
public void setContent_type(String content_type) {
this.content_type = content_type;
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "Employee2 [id=" + id + ", name=" + name + ", designation=" + designation + ", salary=" + salary +
", totalExperience=" + totalExperience + ", technologies2=" + this.getTechnologies(technologies2) +
", content_type=" + content_type + "]";
}
private String getTechnologies(Collection<Technology2> technologies2) {
String strTechnologies = "[";
for(Technology2 technology: technologies2) {
strTechnologies = strTechnologies+technology.toString();
}
return strTechnologies+"]";
}
}
技术Bean类:
public class Technology2 {
private String id;
private String name;
private int experience;
private boolean certified;
private String content_type = "technology2";
public Technology2() {
super();
}
public Technology2(String id, String name, int experience, boolean certified) {
super();
this.id = id;
this.name = name;
this.experience = experience;
this.certified = certified;
}
/**
* @return the id
*/
public String getId() {
return id;
}
/**
* @param id the id to set
*/
@Field(value="id")
public void setId(String id) {
this.id = id;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
@Field(value="name")
public void setName(String name) {
this.name = name;
}
/**
* @return the experience
*/
public int getExperience() {
return experience;
}
/**
* @param experience the experience to set
*/
@Field(value="experience_i")
public void setExperience(int experience) {
this.experience = experience;
}
/**
* @return the certified
*/
public boolean getCertified() {
return certified;
}
/**
* @param certified the certified to set
*/
@Field(value="certified_b")
public void setCertified(boolean certified) {
this.certified = certified;
}
/**
* @return the content_type
*/
public String getContent_type() {
return content_type;
}
/**
* @param content_type the content_type to set
*/
@Field(value="content_type_t")
public void setContent_type(String content_type) {
this.content_type = content_type;
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "Technology2 [id=" + id + ", name=" + name + ", experience=" + experience + ", certified=" + certified +
", content_type=" + content_type + "]";
}
如果员工bean有一个嵌套的地址Bean,那么Bean插入方法工作正常,但是在我们的例子中,员工bean有嵌套的技术Bean集合,它通过下面的行引起异常
UpdateResponse response = solrClient.addBean(bean);
插入方法:
public <T> boolean insert (T bean) {
try {
UpdateResponse response = solrClient.addBean(bean);
System.out.println("insert bean ElapsedTime: " + response.getElapsedTime());
solrClient.commit();
return true;
} catch (IOException | SolrServerException e) {
e.printStackTrace();
}
return false;
}
这里返回null指针异常,下面是Employee2的toString值
Employee2 [id = EE130S,name = Vulrp,names = NjLtK, 薪水= 127334.59626719051,totalExperience = 49.989444163266164, technologies2 = [Technology2 [id = 0TE130S,name = uyIOFlh,experience = 21, certified = true,content_type = technology2] Technology2 [id = 1TE130S, name = FmZJjak,经验= 43,认证= false, content_type = technology2] Technology2 [id = 2TE130S,name = ddJbOXg, 经验= 11,认证=假,content_type =技术2]技术2 [id = 3TE130S,name = rIxumUe,experience = 5,certified = true, content_type = technology2]],content_type = employee2]
导致异常:
java.lang.NullPointerException
at org.apache.solr.client.solrj.beans.DocumentObjectBinder$DocField.storeType(DocumentObjectBinder.java:243)
at org.apache.solr.client.solrj.beans.DocumentObjectBinder$DocField.<init>(DocumentObjectBinder.java:183)
at org.apache.solr.client.solrj.beans.DocumentObjectBinder.collectInfo(DocumentObjectBinder.java:144)
at org.apache.solr.client.solrj.beans.DocumentObjectBinder.getDocFields(DocumentObjectBinder.java:123)
at org.apache.solr.client.solrj.beans.DocumentObjectBinder.toSolrInputDocument(DocumentObjectBinder.java:76)
at org.apache.solr.client.solrj.SolrClient.addBean(SolrClient.java:277)
at org.apache.solr.client.solrj.SolrClient.addBean(SolrClient.java:259)
at com.opteamix.buildpal.poc.SampleSolrDAO.insert(SampleSolrDAO.java:62)
at com.opteamix.buildpal.poc.SampleSolrDAOTest.testEmployees2Insert(SampleSolrDAOTest.java:94)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at junit.framework.TestCase.runTest(TestCase.java:168)
at junit.framework.TestCase.runBare(TestCase.java:134)
at junit.framework.TestResult$1.protect(TestResult.java:110)
at junit.framework.TestResult.runProtected(TestResult.java:128)
at junit.framework.TestResult.run(TestResult.java:113)
at junit.framework.TestCase.run(TestCase.java:124)
at junit.framework.TestSuite.runTest(TestSuite.java:243)
at junit.framework.TestSuite.run(TestSuite.java:238)
at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:83)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
答案 0 :(得分:5)
插入一个关联bean列表的bean对象正在按预期工作。
最后看完solrj6.0.0源代码后,我找到了解决问题的方法。实际上solrj6.0.0中存在一个错误。那是: 如果我们在Employee2 bean的set方法中给出@Field注释,如下所示:
/**
* @param technologies2 the technologies2 to set
*/
@Field (child = true)
public void setTechnologies2(Collection<Technology2> technologies2) {
this.technologies2 = technologies2;
}
然后它导致我们的Employee2 bean插入异常,它聚合了技术列表。这似乎是来自sorlj代码的错误:
DocumentObjectBinder的嵌套DocField类具有以下实现:
public DocField(AccessibleObject member) {
if (member instanceof java.lang.reflect.Field) {
field = (java.lang.reflect.Field) member;
} else {
setter = (Method) member;
}
annotation = member.getAnnotation(Field.class);
storeName(annotation);
storeType();
// Look for a matching getter
if (setter != null) {
String gname = setter.getName();
if (gname.startsWith("set")) {
gname = "get" + gname.substring(3);
try {
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);
try {
getter = setter.getDeclaringClass().getMethod(gname, (Class[]) null);
} catch(Exception ex2) {
// no getter -- don't worry about it...
}
}
}
}
}
}
因为我们在setter处注释了@Field(child = true),因此在这种情况下,field是null,这是由storeType()方法导致空指针异常
private void storeType() {
if (field != null) {
type = field.getType();
} else {
Class[] params = setter.getParameterTypes();
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) {
isList = true;
if (annotation.child()) {
populateChild(field.getGenericType());
} else {
type = Object.class;
}
} else if (type == byte[].class) {
//no op
} else if (type.isArray()) {
isArray = true;
if (annotation.child()) {
populateChild(type.getComponentType());
} else {
type = type.getComponentType();
}
} else if (type == Map.class || type == HashMap.class) { //corresponding to the support for dynamicFields
if (annotation.child()) throw new BindingException("Map should is not a valid type for a child document");
isContainedInMap = true;
//assigned a default type
type = Object.class;
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) {
//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] == Collection.class || types[1] == List.class || types[1] == ArrayList.class) {
type = Object.class;
isList = true;
} else {
//else assume it is a primitive and put in the source type itself
type = (Class) types[1];
}
} 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;
}
} else if (types[1] instanceof GenericArrayType) { //Array types
type = (Class) ((GenericArrayType) types[1]).getGenericComponentType();
isArray = true;
} 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");
}
}
}
}
} else {
if (annotation.child()) {
populateChild(type);
}
}
}
到目前为止,我在字段级别而不是在setter处注释@Field注释:
@Field (child = true)
private Collection<Technology2> technologies2;
所以现在插入这样的bean是成功的,在检索时我得到的结果低于预期:
Employee2 [id = E3,name = KzWhg,names = aTDiu, 薪水= 190374.70126209356,totalExperience = 2.0293696897450584, technologies2 = [Technology2 [id = 0T3,name = nxTdufv,experience = 46, certified = false,content_type = technology2] Technology2 [id = 1T3, name = waSMXpf,experience = 26,certified = false, content_type = technology2] Technology2 [id = 2T3,name = jqNbZZr, 经验= 30,认证=真,content_type =技术2]技术2 [id = 3T3,name = VnidjyI,经验= 21,认证=真, content_type = technology2] Technology2 [id = 4T3,name = ulGnHFm, 经验= 33,认证=假,content_type =技术2]技术2 [id = 5T3,name = cpUfgrY,experience = 21,certified = false, content_type = technology2]],content_type = employee2] Employee2 [id = E4, name = xeKOY,names = WfPSm,salary = 169700.53869292728, totalExperience = 22.047282596410284,technologies2 = [Technology2 [id = 0T4,name = rleygcW,经验= 30,认证=真, content_type = technology2] Technology2 [id = 1T4,name = yxjHrxV, 经验= 27,认证=假,content_type =技术2]技术2 [id = 2T4,name = czjHAEE,experience = 31,certified = false, content_type = technology2] Technology2 [id = 3T4,name = RDhoIJw, 经验= 22,认证=假,content_type =技术2]技术2 [id = 4T4,name = UkbldDN,经验= 19,认证= false, content_type = technology2]],content_type = employee2] Employee2 [id = E5, name = tIWuY,names = WikuL,薪水= 41462.47225086359, totalExperience = 13.407976384902403,technologies2 = [Technology2 [id = 0T5,name = CDCMunq,experience = 6,certified = false, content_type = technology2] Technology2 [id = 1T5,name = NmkADyB, 经验= 31,认证=假,content_type =技术2]技术2 [id = 2T5,name = IhXnLfc,experience = 9,certified = true, content_type = technology2]],content_type = employee2] Employee2 [id = E6, name = YluDp,names = EtFqG,salary = 159724.66206009954, totalExperience = 26.26819742766281,technologies2 = [Technology2 [id = 0T6, name = mFvKDIK,experience = 33,certified = false, content_type = technology2] Technology2 [id = 1T6,name = arTNoHj, 经验= 44,认证=真,content_type =技术2]技术2 [id = 2T6,name = KYMseTW,经验= 34,认证= false, content_type = technology2] Technology2 [id = 3T6,name = ZTphSVn, 经验= 13,认证=真,content_type = technology2]], content_type = employee2] Employee2 [id = E7,name = qMkKG, 指定= SQHCo,薪水= 111861.53447042785, totalExperience = 13.29234679211927,technologies2 = [Technology2 [id = 0T7, name = PTKxjFl,experience = 23,certified = false, content_type = technology2] Technology2 [id = 1T7,name = gJfxbto, 经验= 17,认证=真,content_type =技术2]技术2 [id = 2T7,name = eekPYPN,experience = 40,certified = true, content_type = technology2] Technology2 [id = 3T7,name = aRdsEag, 经验= 40,认证=真,content_type =技术2]技术2 [id = 4T7,name = loDFVyM,经验= 40,认证=真, content_type = technology2] Technology2 [id = 5T7,name = xPXNaDV, 经验= 0,认证=假,content_type = technology2]], content_type = employee2] Employee2 [id = E8,name = WyNsf, 指定= TtanH,薪水= 107942.13641940584, totalExperience = 47.036469485140984,technologies2 = [Technology2 [id = 0T8,name = kakGXqh,experience = 14,certified = true, content_type = technology2] Technology2 [id = 1T8,name = ugwgdHy, 经验= 9,认证=真,content_type =技术2]技术2 [id = 2T8,name = rNzwcdQ,experience = 31,certified = false, content_type = technology2] Technology2 [id = 3T8,name = ZBXUhuB, 经验= 6,认证=真,content_type = technology2]], content_type = employee2] Employee2 [id = E9,name = EzuLC, 指定= IXYGj,薪水= 133064.4485190016, totalExperience = 16.075378097234232,technologies2 = [Technology2 [id = 0T9,name = GmvOUWp,experience = 5,certified = true, content_type = technology2] Technology2 [id = 1T9,name = ZWyvRxk, 经验= 24,认证=假,content_type =技术2]技术2 [id = 2T9,name = uWkTrfB,经验= 5,认证= false, content_type = technology2] Technology2 [id = 3T9,name = NFknqJj, 经验= 29,认证=真,content_type = technology2]], content_type = employee2] Employee2 [id = E10,name = quFKB, 指定= eUoBJ,薪水= 198332.3270496455, totalExperience = 14.035578311712438,technologies2 = [Technology2 [id = 0T10,name = MOXduwi,experience = 49,certified = false, content_type = technology2] Technology2 [id = 1T10,name = LpXGRvn, 经验= 28,认证=假,content_type =技术2]技术2 [id = 2T10,name = QeAOjIp,experience = 3,certified = true, content_type = technology2] Technology2 [id = 3T10,name = aVxGhOV, 经验= 34,认证=真,content_type =技术2]技术2 [id = 4T10,name = fbSaBUm,experience = 42,certified = true, content_type = technology2]],content_type = employee2]
我在JIRA中引发了代码缺陷: https://issues.apache.org/jira/browse/SOLR-9112
答案 1 :(得分:3)
即使Solrj Code也不支持将多个子元素作为bean插入。它给出了例外:不支持多个子节点。但是通过其他方式,可以通过SolrInput类插入/索引聚合多个bean的Bean。