【问题标题】:Spring doesn't save object to MongoDB correctlySpring没有正确地将对象保存到MongoDB
【发布时间】:2014-10-03 23:15:36
【问题描述】:

以下问题已与此问题分开: ArrayIndexOutOfBoundsException while Spring save data to MongoDB

我在将对象保存到 MongoDB 时遇到问题。我注意到这个问题可能是由过于复杂的对象引起的。我有以下类层次结构:

ClassAClassBClassC 的超类。 ClassD 包含地图的地图。 ClassC 包含 ClassB

我调用的代码如下:

ClassC c = new ClassC()
c.setName("NAME");
mongoOperation.save(c, "Mongo"); // MongoOperations object

问题在于 Mongo 不保存对象的数据。它只保存_id_class

实际数据

{
    "_id" : ObjectId("53e86cd9c506f66eafaa03cb"),
    "_class" : "com.sample.ClassC"
}

预期数据

{
    "_id" : ObjectId("53e86cd9c506f66eafaa03cb"),
    "_class" : "com.sample.ClassC",
    "name" : "NAME"
}

有趣的是,当我在 ClassD 中注释掉地图字段时,一切正常。

是否可能是我尝试序列化的对象过于复杂造成的?


编辑

当我从 ClassC 中删除 bObject 时,它也可以正常工作。


编辑 2

所有类都是带有 setter 和 getter 的简单 bean。

例如

public class ClassD{

    private TreeMap<String, TreeMap<String,String>> map;

    public TreeMap<String, TreeMap<String, String>> getMap() {
        return map;
    }

    public void setMap(TreeMap<String, TreeMap<String, String>> map) {
        this.map = map;
    }
}

编辑 3

下面的完整示例,它具有与上图相同的类层次结构。

public class Application implements CommandLineRunner {

    @Autowired
    private MongoTemplate mongoTemplate;

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        ClassC cObject = new ClassC();
        cObject.setName("Jon");
        try {
            mongoTemplate.save(cObject);
        }catch(Exception e){
            e.printStackTrace();
        }
        mongoTemplate.save(cObject);
    }
}


class ClassA{

    private String name;

    private ClassD dObject;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public ClassD getdObject() {
        return dObject;
    }

    public void setdObject(ClassD dObject) {
        this.dObject = dObject;
    }
}

class ClassB extends ClassA {
}

class ClassC extends ClassA {
    private ClassB b;

    public ClassB getB() {
        return b;
    }

    public void setB(ClassB b) {
        this.b = b;
    }
}

class ClassD {

    private TreeMap<String, TreeMap<String, String>> map = new TreeMap<>();

    public TreeMap<String, TreeMap<String, String>> getMap() {
        return map;
    }
    public void setMap(TreeMap<String, TreeMap<String, String>> map) {
        this.map = map;
    }

}

【问题讨论】:

  • 能否提供ClassD的代码?
  • 所有类都是带有setter和getter的简单bean。

标签: java spring mongodb spring-boot


【解决方案1】:

以下代码似乎有效:

@EnableAutoConfiguration
public class Application implements CommandLineRunner {

    @Autowired
    private MongoTemplate mongoTemplate;

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        Customer customer = new Customer("myself");
        ClassB classB = new ClassB();
        TreeMap<String, TreeMap<String, String>> map =  new TreeMap<String, TreeMap<String, String>>();
        TreeMap<String, String> innermap = new TreeMap<String, String>();
        innermap.put("iam", "cool");
        map.put("innermap", innermap);
        TreeMap<String, String> innermap2 = new TreeMap<String, String>();
        innermap2.put("youare", "yellow");
        map.put("innermap2", innermap2);
        classB.setMap(map);
        customer.setClassB(classB);
        try {
            mongoTemplate.save(customer);
        } catch (Exception e) {
            e.printStackTrace();
        }
        mongoTemplate.save(customer);
        System.out.println(mongoTemplate.findAll(Customer.class));;
    }
}


public class ClassB {

    private TreeMap<String, TreeMap<String, String>> map = new TreeMap<String, TreeMap<String, String>>();

    public TreeMap<String, TreeMap<String, String>> getMap() {
        return map;
    }

    public void setMap(TreeMap<String, TreeMap<String, String>> map) {
        this.map = map;
    }
}


@Document(collection ="customer")
public class Customer {

    @Id
    private String id;

    private String name;

    private ClassB classB;

    public Customer() {
    }

    public Customer(String name) {
        this.name = name;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public ClassB getClassB() {
        return classB;
    }

    public void setClassB(ClassB classB) {
        this.classB = classB;
    }

    @Override
    public String toString() {
        return "Customer [id=" + id + ", name=" + name + ", classB=" + classB
                + "]";
    }

}

the ArrayIndexOutOfBoundsException-issue 仍然存在。

【讨论】:

  • 您的代码工作正常,但它具有完全不同的类层次结构。我附上了我的代码示例。
【解决方案2】:

我猜你的 spring-data-mongodb.jar 的特定版本中的 MongoConverter 工作不正确。 Spring 必须将您的ClassC 实例转换为DBObject 格式,然后调用DBCollection.save 将数据保存到数据库中。您可以检查"com.mongodb.DBCollection.save"方法中DBObject参数的内容是否包含您期望的正确数据。

我用完整的结构和测试复制了你的ClassC,它很好,无法重现你上面描述的内容。我使用 spring-data-mongdb-1.2.3-RELEASE.jar。你采用的版本是什么?

【讨论】:

  • 我的版本是1.5.0。当我使用 1.0.1 时它运行良好,但现在我无法将其降级到低于 1.5.0 的任何版本...
  • 是的,1.5.0 版有这个错误。如果你可以使用HashMap代替TreeMap,它会帮助你,否则你必须等待作者修复错误。它发生在 spring-data-commons-1.8.0-RELEASE.jar 中。该代码将TreeMap 视为普通实体类,而不是容器类。不幸的是,TreeMap 中的字段定义与 HashMap 有所不同,例如 TreeMap 中的 private transient EntrySet entrySet = null; - 这是发出该异常的原因之一。
猜你喜欢
  • 1970-01-01
  • 2014-03-05
  • 2020-02-13
  • 1970-01-01
  • 2023-03-28
  • 1970-01-01
  • 2018-04-27
  • 2012-11-04
  • 1970-01-01
相关资源
最近更新 更多