Spring 引导找不到我的 Java bean 映射器

Spring Boot doesn't find my Java bean mapper

当我尝试使用 Java bean 映射器启动 Spring 引导时出现错误。我在 Windows、Gradle 上使用 Eclipse 进行构建。这只是我用来学习这些组件的学习项目。

我正在监听 ActiveMQ Artemis 队列,使用传入数据调用 Web 服务,然后将订单响应保存在 MondoDB 中。所有组件都在工作,除了映射器将 api 响应转换为 MongoDB 实体。

谁能看出我做错了什么?这与我注入 OrderMapper 的方式有关,但我现在不确定。这是 Spring 输出:

  .   ____          _            __ _ _
 /\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.4.5)

2021-04-30 14:16:15.860  INFO 2320 --- [           main] c.b.R.RestClientPocApplication           : Starting RestClientPocApplication using Java 11.0.9 on PSPLT-F7VYYY2 with PID 2320 (C:\Users\Bwarrick\Workspaces\Java\RESTClientPOC\bin\main started by Bwarrick in C:\Users\Bwarrick\Workspaces\Java\RESTClientPOC)
2021-04-30 14:16:15.863  INFO 2320 --- [           main] c.b.R.RestClientPocApplication           : No active profile set, falling back to default profiles: default
2021-04-30 14:16:16.405  INFO 2320 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data MongoDB repositories in DEFAULT mode.
2021-04-30 14:16:16.567  INFO 2320 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 157 ms. Found 1 MongoDB repository interfaces.
2021-04-30 14:16:16.991  INFO 2320 --- [           main] org.mongodb.driver.cluster               : Cluster created with settings {hosts=[192.168.56.102:27017], mode=SINGLE, requiredClusterType=UNKNOWN, serverSelectionTimeout='30000 ms'}
2021-04-30 14:16:17.064  INFO 2320 --- [68.56.102:27017] org.mongodb.driver.connection            : Opened connection [connectionId{localValue:1, serverValue:49}] to 192.168.56.102:27017
2021-04-30 14:16:17.064  INFO 2320 --- [68.56.102:27017] org.mongodb.driver.connection            : Opened connection [connectionId{localValue:2, serverValue:50}] to 192.168.56.102:27017
2021-04-30 14:16:17.065  INFO 2320 --- [68.56.102:27017] org.mongodb.driver.cluster               : Monitor thread successfully connected to server with description ServerDescription{address=192.168.56.102:27017, type=STANDALONE, state=CONNECTED, ok=true, minWireVersion=0, maxWireVersion=9, maxDocumentSize=16777216, logicalSessionTimeoutMinutes=30, roundTripTimeNanos=23420200}
2021-04-30 14:16:17.332  WARN 2320 --- [           main] onfigReactiveWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'artemisConsumer' defined in file [C:\Users\Bwarrick\Workspaces\Java\RESTClientPOC\bin\main\com\benwarrick\RESTClientPOC\jms\ArtemisConsumer.class]: Unsatisfied dependency expressed through constructor parameter 1; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.benwarrick.RESTClientPOC.service.OrderMapper' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
2021-04-30 14:16:17.355  INFO 2320 --- [           main] ConditionEvaluationReportLoggingListener : 

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2021-04-30 14:16:17.370 ERROR 2320 --- [           main] o.s.b.d.LoggingFailureAnalysisReporter   : 

***************************
APPLICATION FAILED TO START
***************************

Description:

Parameter 1 of constructor in com.benwarrick.RESTClientPOC.jms.ArtemisConsumer required a bean of type 'com.benwarrick.RESTClientPOC.service.OrderMapper' that could not be found.


Action:

Consider defining a bean of type 'com.benwarrick.RESTClientPOC.service.OrderMapper' in your configuration.

这是我的组件:

package com.benwarrick.RESTClientPOC.jms;

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.jms.annotation.JmsListener;
    import org.springframework.stereotype.Component;
    
    import com.benwarrick.RESTClientPOC.persistance.OrderEntity;
    import com.benwarrick.RESTClientPOC.persistance.OrderRepository;
    import com.benwarrick.RESTClientPOC.service.CoinBaseClientServiceImpl;
    import com.benwarrick.RESTClientPOC.service.OrderMapper;
    import com.benwarrick.RESTClientPOC.service.OrderResponse;
    import com.benwarrick.RESTClientPOC.service.Price;
    import com.benwarrick.RESTClientPOC.service.Prices;
    import reactor.core.publisher.Mono;
    import reactor.core.publisher.Flux;
    
    @Component
    public class ArtemisConsumer {
    
        private final OrderRepository orderRepository; 
        private final OrderMapper orderMapper;
        
        @Autowired
        public ArtemisConsumer(OrderRepository orderRepository, OrderMapper orderMapper) {
            this.orderRepository = orderRepository; 
            this.orderMapper = orderMapper; 
        }
        
        
        @JmsListener(destination = "test.topic::test.queue")
        public void receive(String msg){
            System.out.println("Got Message: " + msg);
            
            CoinBaseClientServiceImpl client = new CoinBaseClientServiceImpl();
            
            Mono<OrderResponse>orderCreate = client.createOrder("market", "USD", "BTC", "5");
            orderCreate.log().subscribe(
                    successValue -> processResponse(successValue),
                    error -> System.err.println(error.getMessage()),
                    () -> System.out.println("mono consumed")
                    );
        }
        
        public void processResponse(OrderResponse orderResponse) {
            
            System.out.println(orderResponse.getOrderID() + " " + orderResponse.getSellingCurrency() + orderResponse.getBuyingCurrency() + " Qty: " 
                    + orderResponse.getBoughtQty() + " Type: " + orderResponse.getOrderType()) ;
            try {
            OrderEntity entity = orderMapper.apiResponseToEntity(orderResponse); 
            OrderEntity newEntity = orderRepository.save(entity); 
            System.out.println("Test: " + newEntity.getBoughtQuantity()); 
            }
            catch(Exception e) {
                System.out.println("Exception: " + e.toString()) ;
            }
        }
    }

这是我的主要流程:

package com.benwarrick.RESTClientPOC;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.scheduling.annotation.EnableAsync;

@SpringBootApplication
@EnableAsync
public class RestClientPocApplication {
    private static final Logger LOG = LoggerFactory.getLogger(RestClientPocApplication.class);

    public static void main(String[] args) {
        ConfigurableApplicationContext ctx = 
        SpringApplication.run(RestClientPocApplication.class, args);
        String mongoDBHost = ctx.getEnvironment().getProperty("spring.data.mongodb.host");
        String mongoDbPort = ctx.getEnvironment().getProperty("spring.data.mongodb.port");
        LOG.info("Connected to MongoDb: " + mongoDBHost + ":" + mongoDbPort); 
    }

}

这是未找到的 bean:

package com.benwarrick.RESTClientPOC.service;

import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;

import com.benwarrick.RESTClientPOC.persistance.OrderEntity;

@Mapper (componentModel = "spring")
public interface OrderMapper {
    
    @Mappings({
        @Mapping(target = "id", ignore = true),
        @Mapping(target = "version", ignore = true),
        @Mapping(target = "orderId", source="orderID"),
        @Mapping(target = "orderID", source="boughtQty")
    })
    OrderEntity apiResponseToEntity(OrderResponse api); 
}

还有我的build.graddle

plugins {
    id 'org.springframework.boot' version '2.4.5'
    id 'io.spring.dependency-management' version '1.0.11.RELEASE'
    id 'java'
}

group = 'com.benwarrick'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'

repositories {
    mavenCentral()
}

ext {
    mapstructVersion = "1.4.2.Final"
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-artemis'
    implementation 'org.springframework.boot:spring-boot-starter-webflux'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    testImplementation 'io.projectreactor:reactor-test'
    
    implementation("org.mapstruct:mapstruct:${mapstructVersion}")
    compileOnly "org.mapstruct:mapstruct-processor:${mapstructVersion}"
    annotationProcessor "org.mapstruct:mapstruct-processor:${mapstructVersion}"
    testAnnotationProcessor "org.mapstruct:mapstruct-processor:${mapstructVersion}"
    
    implementation('org.springframework.boot:spring-boot-starter-data-mongodb')
    testImplementation('de.flapdoodle.embed:de.flapdoodle.embed.mongo')
}

test {
    useJUnitPlatform()
}

对于 MapStruct,您需要正确设置注释处理器,以便 IDE(在您的情况下为 Eclipse)和构建工具 Gradle 可以很好地协同工作。

您可以在 MapStruct page uder IDE support 上阅读相关内容。现在我没能以这种方式让它正常工作。

插件来拯救!现在,我建议您使用以下 Gradle 插件,它可以为您正确设置 Eclipse IDE。插件:https://plugins.gradle.org/plugin/com.diffplug.eclipse.apt

我看到您已经知道如何包含插件,以防万一您必须添加到 build.gradle:

的代码
plugins {
    ...
    id 'com.diffplug.eclipse.apt' version "3.29.1"
}

然后 运行 您的项目中将设置 Eclipse 的命令:

./gradlew eclipseJdtApt eclipseFactorypath eclipseJdt

在 Eclipse 中,您现在必须 运行 右键单击​​项目并 select Gradle / 刷新 Gradle 项目。

之后,项目/清洁。有了这个干净的构建,注释处理器应该 运行ning.

我希望 Eclipse Buildship 能够接受这一点并使其更容易支持他的功能。