SOLRJ-6.0.0:插入一个bean对象,该对象关联bean对象列表,给出空指针异常

San*_*ani 4 indexing solr nested nullpointerexception solrj

员工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+"]";
    }

}
Run Code Online (Sandbox Code Playgroud)

技术豆类:

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 + "]";
    }
Run Code Online (Sandbox Code Playgroud)

如果员工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;
    }
Run Code Online (Sandbox Code Playgroud)

这里是返回空指针异常,下面是Employee2的toString值

Employee2 [id = EE130S,name = Vulrp,names = NjLtK,salary = 127334.59626719051,totalExperience = 49.989444163266164,technologies2 = [Technology2 [id = 0TE130S,name = uyIOFlh,experience = 21,certified = true,content_type = technology2] Technology2 [id = 1TE130S,name = FmZJjak,experience = 43,certified = false,content_type = technology2] Technology2 [id = 2TE130S,name = ddJbOXg,experience = 11,certified = false,content_type = technology2] Technology2 [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)
Run Code Online (Sandbox Code Playgroud)

San*_*ani 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;
    }
Run Code Online (Sandbox Code Playgroud)

然后它导致我们的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...
              }
            }
          }
        }
      }
    }
Run Code Online (Sandbox Code Playgroud)

因为我们在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);
        }
      }
    }
Run Code Online (Sandbox Code Playgroud)

所以到目前为止,我在字段级别而不是在setter处注释@Field注释:

 @Field (child = true)
    private Collection<Technology2> technologies2;
Run Code Online (Sandbox Code Playgroud)

所以现在插入这样的bean是成功的,在检索时我得到的结果低于预期:

Employee2 [id = E3,name = KzWhg,names = aTDiu,salary = 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,experience = 30,certified = true,content_type = technology2] Technology2 [id = 3T3,name = VnidjyI ,experience = 21,certified = true,content_type = technology2] Technology2 [id = 4T3,name = ulGnHFm,experience = 33,certified = false,content_type = technology2] Technology2 [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,experience = 30,认证= TRUE,CONTENT_TYPE =技术2]技术2 [ID = 1T4,名称= yxjHrxV,经验= 27,认证=假,content_typ e = technology2] Technology2 [id = 2T4,name = czjHAEE,experience = 31,certified = false,content_type = technology2] Technology2 [id = 3T4,name = RDhoIJw,experience = 22,certified = false,content_type = technology2] Technology2 [ id = 4T4,name = UkbldDN,experience = 19,certified = false,content_type = technology2]],content_type = employee2] Employee2 [id = E5,name = tIWuY,names = WikuL,salary = 41462.47225086359,totalExperience = 13.407976384902403,technologies2 = [Technology2 [id = 0T5,name = CDCMunq,experience = 6,certified = false,content_type = technology2] Technology2 [id = 1T5,name = NmkADyB,experience = 31,certified = false,content_type = technology2] Technology2 [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,expe rience = 44,certified = true,content_type = technology2] Technology2 [id = 2T6,name = KYMseTW,experience = 34,certified = false,content_type = technology2] Technology2 [id = 3T6,name = ZTphSVn,experience = 13,certified = true,content_type = technology2]],content_type = employee2] Employee2 [id = E7,name = qMkKG,names = SQHCo,salary = 111861.53447042785,totalExperience = 13.29234679211927,technologies2 = [Technology2 [id = 0T7,name = PTKxjFl,experience = 23 ,certified = false,content_type = technology2] Technology2 [id = 1T7,name = gJfxbto,experience = 17,certified = true,content_type = technology2] Technology2 [id = 2T7,name = eekPYPN,experience = 40,certified = true,content_type = technology2] Technology2 [id = 3T7,name = aRdsEag,experience = 40,certified = true,content_type = technology2] Technology2 [id = 4T7,name = loDFVyM,experience = 40,certified = true,content_type = technology2] Technology2 [id = 5T7,name = xPXNaDV,experience = 0,certified = false,content_type = technology2]],content_type = employee2] Employee2 [id = E8,name = WyNsf,designat ion = TtanH,salary = 107942.13641940584,totalExperience = 47.036469485140984,technologies2 = [Technology2 [id = 0T8,name = kakGXqh,experience = 14,certified = true,content_type = technology2] Technology2 [id = 1T8,name = ugwgdHy,experience = 9 ,certified = true,content_type = technology2] Technology2 [id = 2T8,name = rNzwcdQ,experience = 31,certified = false,content_type = technology2] Technology2 [id = 3T8,name = ZBXUhuB,experience = 6,certified = true,content_type = technology2]],content_type = employee2] Employee2 [id = E9,name = EzuLC,names = IXYGj,salary = 133064.4485190016,totalExperience = 16.075378097234232,technologies2 = [Technology2 [id = 0T9,name = GmvOUWp,experience = 5,certified = true,content_type = technology2] Technology2 [id = 1T9,name = ZWyvRxk,experience = 24,certified = false,content_type = technology2] Technology2 [id = 2T9,name = uWkTrfB,experience = 5,certified = false,content_type = technology2]技术2 [ID = 3T9,名称= NFknqJj,经验= 29,认证= TRUE,CONTENT_TYPE =技术2],CONTENT_TYPE =和Employee2] EMPL oyee2 [id = E10,name = quFKB,designation = eUoBJ,salary = 198332.3270496455,totalExperience = 14.035578311712438,technologies2 = [Technology2 [id = 0T10,name = MOXduwi,experience = 49,certified = false,content_type = technology2] Technology2 [id = 1T10,name = LpXGRvn,experience = 28,certified = false,content_type = technology2] Technology2 [id = 2T10,name = QeAOjIp,experience = 3,certified = true,content_type = technology2] Technology2 [id = 3T10,name = aVxGhOV ,experience = 34,certified = true,content_type = technology2] Technology2 [id = 4T10,name = fbSaBUm,experience = 42,certified = true,content_type = technology2]],content_type = employee2]

我在JIRA中提出了代码缺陷:https: //issues.apache.org/jira/browse/SOLR-9112