mercredi 29 mai 2019

UnsatisfiedDependencyException: Error creating bean with name 'trafficMapper'

I work with a Spring boot application and get the error provided below,

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'trafficMapper': Unsatisfied dependency expressed through field 'config'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.ratepay.iris.ella.config.MasterConfig' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:596)
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:90)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:374)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1378)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:575)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:498)
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:846)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:863)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:546)
    at org.springframework.context.annotation.AnnotationConfigApplicationContext.<init>(AnnotationConfigApplicationContext.java:88)
    at com.ratepay.iris.ella.service.EllaServiceIntegrationTest.setup(EllaServiceIntegrationTest.java:72)
    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 org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
    at com.github.tomakehurst.wiremock.junit.WireMockRule$1.evaluate(WireMockRule.java:73)
    at org.junit.rules.RunRules.evaluate(RunRules.java:20)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
    at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.ratepay.iris.ella.config.MasterConfig' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1644)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1203)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1164)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:593)
    ... 38 more

The error occurred when I try to do the setup for designing an integration test.

    @Before
    @SuppressWarnings( "resource" )
    public void setup() {
        int port = wireMockRule.port();

        System.setProperty( "ella.uri", "http://localhost:" + port + ELLA_ENDPOINT );
        //        System.setProperty( "freud.master.config", "src/test/resources/test-master-config.json" );
        System.setProperty( "ella.shadowmode", "enabled" );

        ApplicationContext context = new AnnotationConfigApplicationContext( EllaConfiguration.class );
        ellaService = context.getBean( EllaService.class );
    }

This is the LOC that provides the error,

ApplicationContext context = new AnnotationConfigApplicationContext( EllaConfiguration.class );

The EllaConfiguration class is provided below,

@Configuration
@ComponentScan( "com.ratepay.iris.ella" )
public class EllaConfiguration {

    public static final String ELLA_CONNECTOR_BEAN_NAME = "ellaConnector";

    private static final String URI_CONFIG_KEY = "ella.uri";
    private static final String CONNECTION_TIMEOUT_CONFIG_KEY = "ella.connection_timeout";
    private static final String READ_TIMEOUT_CONFIG_KEY = "ella.read_timeout";

    private static final int DEFAULT_CONNECTION_TIMEOUT = 100;
    private static final int DEFAULT_READ_TIMEOUT = 800;

    public static final String ELLA_SHADOW_MODE_KEY = "ella.shadowmode";
    public static final String ELLA_SHADOW_MODE_ENABLED_VALUE = "enabled";

    @Bean( name = ELLA_CONNECTOR_BEAN_NAME )
    public EntityServiceConnectable<EllaResponse> timeoutConfiguration( final Environment env ) {
        return ServiceConnectorBuilder.create( createConnectionConfiguration( env ) ).timeout( createTimeoutConfiguration( env ) ).build();
    }

    private SimpleTimeoutConfiguration createTimeoutConfiguration( final Environment env ) {
        return new SimpleTimeoutConfiguration( env.getProperty( CONNECTION_TIMEOUT_CONFIG_KEY, Integer.class, DEFAULT_CONNECTION_TIMEOUT ),
                                               env.getProperty( READ_TIMEOUT_CONFIG_KEY, Integer.class, DEFAULT_READ_TIMEOUT ) );
    }

    public boolean isEllaShadowModeEnabled( final Environment env ) {
        return env.getRequiredProperty( ELLA_SHADOW_MODE_KEY ).equals( ELLA_SHADOW_MODE_ENABLED_VALUE );
    }

    private PostConnectionConfiguration<EllaResponse> createConnectionConfiguration( final Environment env ) {
        return new SimplePostConnectionConfiguration<>( env.getRequiredProperty( URI_CONFIG_KEY ), EllaResponse.class );
    }
}

The EllaService class is provided,

@Service
public class EllaService {

    public static final int IRIS_ACCEPT = 0;
    public static final int IRIS_REJECT = 100;

    @Autowired
    @Qualifier( ELLA_CONNECTOR_BEAN_NAME )
    private EntityServiceConnectable<EllaResponse> connector;

    @Autowired
    private TrafficMapper trafficMapper;

    @Autowired
    private EllaConfiguration config;

    @Autowired
    private Environment env;

    @Getter
    private boolean shadowModeEnabled = false;

    /**
     * Initialize the service.
     */
    @PostConstruct
    public void initialize() {
        this.shadowModeEnabled = config.isEllaShadowModeEnabled( env );
    }

    /**
     * Asynchronously call Ella. Determine if traffic is applicable for Ella and if yes forward to Ella.
     *
     * @param irisEo
     * @return List<ResultBo>
     * @throws EllaGatewayUnsuccessfulResponseException
     */
    @Async
    public void invokeEllaAsync( final IrisEo irisEo ) throws EllaGatewayUnsuccessfulResponseException {
        invokeEllaSync( irisEo );
    }

    /**
     * Synchronously call Ella. Determine if traffic is applicable for Ella and if yes forward to Ella.
     *
     * @param irisEo
     * @return List<ResultBo>
     * @throws EllaGatewayUnsuccessfulResponseException
     */
    public List<ResultBo> invokeEllaSync( final IrisEo irisEo ) throws EllaGatewayUnsuccessfulResponseException {

        Optional<String> mapId = trafficMapper.getApplicableMapId( irisEo );

        if( mapId.isPresent() && StringUtils.isNotEmpty( mapId.get() ) ) {

            try {
                return irisEo.getOrder().getProducts().stream().map( product -> fetchEllaResult( irisEo, mapId.get(), product ) )
                        .collect( Collectors.toList() );
            }
            catch( EllaGatewayUnsuccessfulResponseException ex ) {
                throw new EllaGatewayUnsuccessfulResponseException( ex.getMessage(), ex.getCause() );
            }
        }
        return Collections.emptyList();
    }

    private ResultBo fetchEllaResult( final IrisEo irisEo, String mapId, String product ) throws EllaGatewayUnsuccessfulResponseException {

        HttpHeaders freudHeaders = createRequestHeaders( irisEo );

        ServiceResponse<EllaResponse> response = connector
                .call( EllaDtoConverter.convertToRequest( irisEo, mapId, product ), freudHeaders );

        if( !response.isSuccess() ) {
            throw new EllaGatewayUnsuccessfulResponseException( response.getErrorMessage(), response.getException().getCause() );
        }

        EllaResult prediction = response.getResponse().getResult();

        return convertToResultBo( prediction, product );

    }

    private ResultBo convertToResultBo( EllaResult prediction, String product ) {

        ClassificationResult classification = prediction.getClassification();
        final int irisPrediction = ClassificationResult.FRAUD.equals( classification ) ? IRIS_REJECT : IRIS_ACCEPT;
        //        final int irisPrediction = Integer.valueOf( classification.getValue() ) < 900 ? IRIS_REJECT : IRIS_ACCEPT;

        return new ResultBo( product, irisPrediction );
    }

    private HttpHeaders createRequestHeaders( final IrisEo irisEo ) {

        HttpHeaders freudHeaders = new HttpHeaders();

        freudHeaders.add( ACCEPT, APPLICATION_JSON_UTF8_VALUE );
        RatepayHeaders.append( freudHeaders, irisEo.getRequestInfo() );

        return freudHeaders;
    }

}

I get an NPE from the invokeEllaSync method in the LOC,

Optional<String> mapId = trafficMapper.getApplicableMapId( irisEo );

The TrafficMapper class is provided,

@Component
public class TrafficMapper {

    @Autowired
    private MasterConfig config;

    private final Map<Integer, String> shopIdToMapId = new HashMap<>();

    /**
     * Initialize the component.
     */
    @PostConstruct
    public void initialize() {
        fillShopIdMap();
    }

    /**
     * Return an optional holding a specific map id.
     *
     * @param irisEo
     * @return Optional<String>
     */
    public Optional<String> getApplicableMapId( IrisEo irisEo ) {

        Integer shopId = irisEo.getOrder().getShopId();
        return Optional.ofNullable( this.shopIdToMapId.get( shopId ) );
    }

    private void fillShopIdMap() {

        this.config.getTrafficMappings().stream().forEach( trafficMapping -> trafficMapping.getTrafficDescription().getShopIds().stream()
                .forEach( shopId -> this.shopIdToMapId.put( shopId, trafficMapping.getMapId() ) ) );
    }
}

The MasterConfig class is provided,

@Getter
@Setter
@ToString
public class MasterConfig {

    @NotNull
    @JsonProperty( "traffic_mappings" )
    private List<TrafficMapping> trafficMappings;
}

The reason I provided the classes is I am unable to find the issue and wanted to provide more information for the investigation.

How do I solve the UnsatisfiedDependencyException error?





Aucun commentaire:

Enregistrer un commentaire