java - MongoDB Java 驱动程序 4.2.2 - 将 .iterator 或 .into 与 .find 链接时出现 java.lang.noSuchMethodError

标签 java mongodb api runtime-error mongo-java-driver

完成 M220J 类(class)后,我尝试构建自己的应用程序和后端 API,以进一步了解 Mongo Java 驱动程序,但遇到了阻碍。

上下文

我正在创建一个书签管理应用程序,并使用 Mongo 驱动程序和 Spring Boot 用 Ja​​va 重建后端。在 .find() 之后使用 .iterator() 或 .into() 查询我的 Atlas 数据库时,会出现错误。在 .find() 之后使用 .first() 时,不会出现错误。

我的 pom.xml 包含 mongodb-driver-sync 版本 4.2.2。我使用的是 Java 15.0.1。

文件夹集合使用 CodecRegistry,与 MongoDB 大学类(class) M220J 的 mflix 应用程序中创建用户或 session 集合的方式非常相似,这意味着对foldersCollection的查询应返回文件夹类型的文档。我已经验证数据在数据库和Folder.java类中具有相同的字段。

代码

在代码中,user_id 字段当前在文件夹文档中存储为字符串,而不是 ObjectId(充当外键),这不会导致错误。 .into() 技巧取自 this article talking about Mongo and Java Pojos.

这是我当前的实现,但是它不起作用

  // Returns an array of folders, given a user id
  public List<Folder> getFolders(String id) {
    if (id == null || id.isEmpty()) return null;
    List<Folder> folders = foldersCollection.find(new Document("user_id", id)).into(new ArrayList<>());
    return folders;
  }

此代码也不起作用,它在 .find() 之后使用 .iterator(),并排除 id 来获取所有文件夹。如果我在查询中包含 id,它也不起作用。

  public List<Folder> getAllFolders(){
    List<Folder> folders = new ArrayList<>();
    foldersCollection.find().iterator().forEachRemaining(folders::add);
    return folders;
  }

我已经通过 Java 和 Postman 中的测试验证了此代码可以正常工作:

  // Gets a folder from db given folder _id
  public Folder getFolder(String id) {
    if (id == null || id.isEmpty()) return null;
    return foldersCollection.find(new Document("_id", new ObjectId(id))).first();
  }

NoSuchMethodError:

当我使用 .into() 时,它看起来像是指向 .find() 方法,但我已经确认 .find() 在与 .first() 链接时有效,所以我不认为 .find () 是问题所在。使用 .iterator() 时也会出现同样的错误。

java.lang.NoSuchMethodError: 'com.mongodb.internal.operation.ExplainableReadOperation com.mongodb.internal.operation.SyncOperations.find(org.bson.conversions.Bson, java.lang.Class, com.mongodb.internal.client.model.FindOptions)'

    at com.mongodb.client.internal.FindIterableImpl.asReadOperation(FindIterableImpl.java:236)
    at com.mongodb.client.internal.FindIterableImpl.asReadOperation(FindIterableImpl.java:40)
    at com.mongodb.client.internal.MongoIterableImpl.execute(MongoIterableImpl.java:135)
    at com.mongodb.client.internal.MongoIterableImpl.iterator(MongoIterableImpl.java:92)
    at com.mongodb.client.internal.MongoIterableImpl.forEach(MongoIterableImpl.java:121)
    at com.mongodb.client.internal.MongoIterableImpl.into(MongoIterableImpl.java:130)
    at com.bookmarkd.api.daos.FolderDao.getFolders(FolderDao.java:46)
    at com.bookmarkd.FolderTest.GetFolders(FolderTest.java:50) <31 internal lines>
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) <9 internal lines>
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) <23 internal lines>

最后,这是我的文件夹类和 Atlas 数据库中一些文档的图像:

public class Folder {

  @BsonId
  @JsonIgnore
  private ObjectId oid;

  @JsonProperty("_id")
  @BsonIgnore
  private String id;

  @JsonProperty("user_id")
  private String userId;

  private String name;
  private String icon;
  private boolean shareable;

  // Constructor, getters, and setters... 
}

An image of a few Folder documents in the foldersCollection

非常感谢任何调试此问题的帮助!


附加代码/问题解释:

(虽然这使得帖子很长,但我认为在这里查看所有代码比从 Github 存储库查看更容易。)

也许我把事情复杂化了,但我正在尝试学习和使用 Spring Boot MVC。有一个FolderController 处理Http 请求,它调用FolderService,后者调用在Atlas 集群上执行CRUD 方法的FolderDao。所有这些文件都存储在各自的包中: Controller 、服务、daos、模型和配置。

FolderDao 扩展了一个 AbstractDao 类,该类使用从 @Autowired FoldDao 构造函数接收的值来设置客户端和数据库。

最后,MongoDBConfiguration 类配置设置并连接到 Atlas 集群。我在这里配置了PojoRegistry,as shown in this example 。我相信这个类实际上是在Application.java中的@SpringBootApplication启动后立即运行的。 mflix 应用程序中就是这样做的。您可以看到a completed mflix app here供引用。

也许错误来自 Atlas?我的 M0 免费层集群是版本 4.4.4,但我在完成 M220J 类(class)时没有遇到任何问题,其中此逻辑是使用 mflix 实现的。

以下是每个类的完整代码,按照我上面描述的顺序排列:

文件夹 Controller

package com.bookmarkd.api.controllers;

import com.bookmarkd.api.models.Folder;
import com.bookmarkd.api.services.FolderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@CrossOrigin(origins = "*")
@RequestMapping("/api/folders")
@RestController
public class FolderController {

  @Autowired
  FolderService folderService;

  public FolderController() { super(); }

  public void getFolders() {}

  // Get all folders, given the user id
  @GetMapping("")
  public ResponseEntity getFoldersByUserId(@RequestParam(value = "userid", required = false) String folderId) {
    List<Folder> folders = folderService.getFolders(folderId);
    if (folders == null) return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
    return ResponseEntity.status(HttpStatus.OK).body(folders);
  }

  // Get a single public folder, given the folder id
  @GetMapping("/{id}")
  public ResponseEntity getFolder(@PathVariable(value = "id") String folderId) {
    Folder folder = folderService.getFolder(folderId);
    if (folder == null) return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
    return ResponseEntity.status(HttpStatus.OK).body(folder);
  }

  public void addFolder() {}

  public void updateFolder() {}

  public void deleteFolder() {}
}

文件夹服务

package com.bookmarkd.api.services;

import com.bookmarkd.api.daos.FolderDao;
import com.bookmarkd.api.models.Folder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Service;

import java.util.List;

@Configuration
@Service
public class FolderService {

  @Autowired
  private FolderDao folderDao;

  public FolderService() {
    super();
  }

  public List<Folder> getFolders(String id) {
    return folderDao.getFolders(id);
  }

  public Folder getFolder(String id) {
    return folderDao.getFolder(id);
  }

  // Add folder, update folder, delete folder, to-be-implemented later...
}

文件夹Dao

package com.bookmarkd.api.daos;

import com.bookmarkd.api.models.Folder;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoCollection;
import org.bson.Document;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

@Configuration
public class FolderDao extends AbstractDao {

  private final MongoCollection<Folder> foldersCollection;

  @Autowired
  public FolderDao(MongoClient mongoClient, @Value("${spring.mongodb.database}") String databaseName) {
    super(mongoClient, databaseName);

    foldersCollection = db.getCollection("folders", Folder.class);
  }

  // Returns an array of folders, given a user _id
  public List<Folder> getFolders(String id) {
    if (id == null || id.isEmpty()) return null;
    List<Folder> folders = foldersCollection.find(new Document("user_id", id)).into(new ArrayList<>());

//    List<Folder> folders = new ArrayList<>();
//    foldersCollection.find(new Document("user_id", id)); //.iterator().forEachRemaining(folders::add);

    return folders;
  }

  // Gets a folder from db given folder _id
  public Folder getFolder(String id) {
    if (id == null || id.isEmpty()) return null;
    return foldersCollection.find(new Document("_id", new ObjectId(id))).first();
  }
}

抽象道

package com.bookmarkd.api.daos;

import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoDatabase;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;

@Configuration
public abstract class AbstractDao {

  protected String LBV_DATABASE;
  protected MongoDatabase db;
  protected MongoClient mongoClient;

  protected AbstractDao(MongoClient mongoClient, String databaseName) {

    this.mongoClient = mongoClient;
    LBV_DATABASE = databaseName;
    this.db = this.mongoClient.getDatabase(LBV_DATABASE);
  }
}

MongoDBConfiguration(这是我注册 Pojo 编解码器的位置,它适用于 User 模型和folderCollection.find().first() 实现)

package com.bookmarkd.api.config;

import com.mongodb.ConnectionString;
import com.mongodb.MongoClientSettings;
import com.mongodb.WriteConcern;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import org.bson.codecs.configuration.CodecRegistry;
import org.bson.codecs.pojo.PojoCodecProvider;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;

import static org.bson.codecs.configuration.CodecRegistries.fromProviders;
import static org.bson.codecs.configuration.CodecRegistries.fromRegistries;

// Used to configure connection to Atlas cluster
@Configuration
@Service
public class MongoDBConfiguration {

  @Bean
  @Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON)
  public MongoClient mongoClient(@Value("${spring.mongodb.uri}") String connectionString) {

    CodecRegistry pojoCodecRegistry = fromRegistries(
            MongoClientSettings.getDefaultCodecRegistry(),
            fromProviders(PojoCodecProvider.builder().automatic(true).build())
    );

    ConnectionString connString = new ConnectionString(connectionString);
    WriteConcern writeConcern = WriteConcern.MAJORITY; //.withWTimeout(2500, TimeUnit.MILLISECONDS);
    MongoClientSettings settings = MongoClientSettings.builder()
            .writeConcern(writeConcern)
            .applyConnectionString(connString)
            .codecRegistry(pojoCodecRegistry)
            .build();
    MongoClient mongoClient = MongoClients.create(settings);

    return mongoClient;
  }
}

希望所有代码的完整 View 能让您深入了解出了什么问题!

最佳答案

事实证明,我需要三个 Mongo 特定的依赖项,且版本相同。

org.mongo:bson:4.2.3org.mongo.mongodb-driver-code:4.2.3 添加到现有的 org.mongodb pom.xml 中的 -driver-sync:4.2.3 依赖项解决了该问题(我之前使用的是 4.1.2 版本的 mongodb-driver-core 和 mongodb-driver-bson)。

哇,这样的压力仅仅涉及依赖性问题!不幸的是,文档不清楚是否需要全部三个,我认为您只需要 mongodb-driver-sync。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.4.4</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.bookmarkd</groupId>
    <artifactId>LBV</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>LBV</name>
    <description>Bookmarkd Java REST API backend try 2</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.mongodb/mongodb-driver-sync -->
        <dependency>
            <groupId>org.mongodb</groupId>
            <artifactId>mongodb-driver-sync</artifactId>
            <version>4.2.3</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.mongodb/mongodb-driver-core -->
        <dependency>
            <groupId>org.mongodb</groupId>
            <artifactId>mongodb-driver-core</artifactId>
            <version>4.2.3</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.mongodb/bson -->
        <dependency>
            <groupId>org.mongodb</groupId>
            <artifactId>bson</artifactId>
            <version>4.2.3</version>
        </dependency>

    </dependencies>

<!--    <build>-->
<!--        <plugins>-->
<!--            <plugin>-->
<!--                <groupId>org.springframework.boot</groupId>-->
<!--                <artifactId>spring-boot-maven-plugin</artifactId>-->
<!--            </plugin>-->
<!--        </plugins>-->
<!--    </build>-->

</project>

关于java - MongoDB Java 驱动程序 4.2.2 - 将 .iterator 或 .into 与 .find 链接时出现 java.lang.noSuchMethodError,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67023553/

相关文章:

java - iReport java堆空间

java - Java中Comparable<T>的异常现象

php - 如何使用 Volusion API 在 Volusion 中创建新类别

api - 为什么使用http请求时使用async?

swift - 如何在 Swift 3 中发出 GET 请求?

java - 如何使用 Swing 计时器

java - 在 SmartGWT 中创建具有小部件的表单

MongoDB 查找与聚合性能

java - 聚合框架 - 组操作抛出 NumberFormatException

MongoDb $addFields inside arrays $multiply 数组中的两个值