Why am I not able to get my Bean definition available in my Spring context with Spring Boot?

Cheloute :

I'm feeling stupid to ask this, but I can't understand where I'm wrong with my code.

The context is :

  • a Spring Boot application (1.5.7) with an embedded Jetty server and a controller to expose some endpoints
  • a unique @Configuration class, where some of my beans are defined (Singleton and Prototype scopes)
  • a @Service that uses some beans defined in my @Configuration class

The problem is:

  • a NoSuchBeanDefinitionException for one of my @Configuration bean.

Now the details:

My SpringBootApplication :

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

My @Configuration class:

@Configuration
@Profile(value = { "dev", "int", "pre", "pro" })
public class StandaloneFrontalConfig extends WebMvcConfigurerAdapter {

@Value("${kafka.bootstrap-servers}")
private String bootstrapServers;

@Bean
public Map<String, Object> producerConfigs() {
    Map<String, Object> props = new HashMap<>();
    props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers);
    props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
    props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
    return props;
}

@Bean
public ProducerFactory<String, String> producerFactory() {
    return new DefaultKafkaProducerFactory<>(producerConfigs());
}

@Bean
public KafkaTemplate<String, String> kafkaTemplate() {
    return new KafkaTemplate<>(producerFactory());
}

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry.addResourceHandler("/**").addResourceLocations("classpath:/standalone/");
}

@Bean
public WebMvcConfigurer corsConfigurer() {
    return new WebMvcConfigurerAdapter() {
        @Override
        public void addCorsMappings(CorsRegistry registry) {
            registry.addMapping("/**").allowedOrigins("*").allowedHeaders("*");
        }
    };
}

@Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON)
@Bean
public Security securityManager() {
    return new Security();
}

@Bean
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public KngAflow getTechnicalCookie() {
    return new KngAflow();
}

@Bean
public EmbeddedServletContainerCustomizer customizer() {
    return new EmbeddedServletContainerCustomizer() {

        @Override
        public void customize(ConfigurableEmbeddedServletContainer container) {
            if (container instanceof JettyEmbeddedServletContainerFactory) {
                customizeJetty((JettyEmbeddedServletContainerFactory) container);
            }
        }

        private void customizeJetty(JettyEmbeddedServletContainerFactory jetty) {
            jetty.addServerCustomizers(new JettyServerCustomizer() {

                @Override
                public void customize(Server server) {
                    for (Connector connector : server.getConnectors()) {
                        if (connector instanceof ServerConnector) {
                            HttpConnectionFactory connectionFactory = ((ServerConnector) connector)
                                    .getConnectionFactory(HttpConnectionFactory.class);
                            connectionFactory.getHttpConfiguration().setCookieCompliance(CookieCompliance.RFC2965);
                        }
                    }
                }
            });
        }
    };
}
}

My @Service:

@Service
public class CookieService implements services.CookieService, InitializingBean {

    /**
     * Serializable
     */
    private static final long serialVersionUID = -1997257884335775587L;

    @Autowired
    ApplicationContext app;

    @Override
    public Cookie createTechnicalCookie() {
        return new Cookie(app.getBean(KngAflow.class), null);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        if (app != null) {
            for (String bean : app.getBeanDefinitionNames()) {
                System.out.println("Bean: " + bean);
            }
        }
    }
}

And the "non defined" bean:

@JsonInclude(Include.NON_NULL)
@JsonIgnoreProperties({ "security", "maxAge", "domain", "updated" })
public class KngAflow implements Serializable, InitializingBean {

    @JsonProperty(value = "did")
    private String did;
    @JsonProperty(value = "checksum")
    private String checksum;
    @Autowired
    private Security security;
    private Integer maxAge;
    private String domain;
    private boolean updated = false;

    public KngAflow() {
        domain = ".mydomain.com";
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        did = UUID.randomUUID().toString();
        maxAge = 365 * 24 * 60 * 60;
        checksum = security.encrypt(did + security.md5(did));
    }
}

NB: Classes are not complete, and there are more classes in my project. I only put what I saw as relevant information. If something else is needed, just ask me please. By the way, all the endpoints are defined into a unique @Controller class, and all the endpoints are working except those needing the getTechCookie @Bean.

So, my problem occurs in runtime execution. When I start my Spring Boot app, Jetty is started and listening on the configured port. Nevertheless, if you look at the CookieService @Service, I'm listing all the bean names defined in the autowired context and my getTechnicalCookie (a.k.a KngAflow) @Bean is missing. I can't understand why.

Of course, when I invoke my @controller to execute my @Service code, the NoSuchBeanDefinitionException is thrown executing the line app.getBean(KngAflow.class).

I tried to use a bean name instead of bean type, no change. For testing purpose (as it doesn't make sense from a logical point of view), I defined my bean getTechCookie @Bean as a Singleton scoped bean, and the name is still missing from the ApplicationContext.

And the last but not least thing is: Everything works fine with Eclipse!

I mean, all my devs are done using Eclipse IDE. My Spring Boot app is built with Maven and executing it inside Eclipse works correctly (and my getTechCookie Bean is defined and listed).

When I package my app using the Maven Spring Boot plugin and execute it using java -jar, my getTechCookie (KngAflow.class) bean is missing. Nevertheless, this class is present inside the jar.

Spring parameters to launch the spring boot app are spring default values (port 8080, no SSL, ...) and the active.profiles are always between dev, int, pre or pro (those defined in my @Configuration class)

What am I doing wrong?

Thanks!

If it helps, I add my POM definition:

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <artifactId>my-app</artifactId>
    <packaging>jar</packaging>

    <parent>
        <groupId>com.mydomain.bigdata</groupId>
        <artifactId>mybigapp</artifactId>
        <version>1.1-SNAPSHOT</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jetty</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.kafka</groupId>
            <artifactId>spring-kafka</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>

    <build>
        <resources>
            <resource>
                <directory>${basedir}/src/main/resources</directory>
                <filtering>true</filtering>
                <includes>
                    <include>**/*</include>
                    <include>application.yml</include>
                </includes>
            </resource>
        </resources>

        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

EDIT: I changed my @Service class to "force" spring to accept my class as a prototype bean, and it works. It's very ugly but it works. But if someone could help me to find what's wrong, I don't like this workaround:

@Override
    public void afterPropertiesSet() throws Exception {
        if (!context.containsBeanDefinition(KngAflow.class.getName()))
            context.registerBeanDefinition(KngAflow.class.getName(),
                    BeanDefinitionBuilder.genericBeanDefinition(KngAflow.class).setScope("prototype").getBeanDefinition());
    }
Gabor Szabo :

I made a following simple application to reproduce issue.

@SpringBootApplication
public class Application {

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

}
@Configuration
@Profile("dev")
public class BeanConfiguration {

    @Bean
    @Scope(scopeName = SCOPE_PROTOTYPE)
    public PrototypeBean prototypeBean() {
        return new PrototypeBean();
    }

}
public class PrototypeBean {}
@Service
@Slf4j
public class SingletonBean implements InitializingBean {

    @Autowired
    private ApplicationContext context;

    public PrototypeBean getPrototypeBean() {
        return context.getBean(PrototypeBean.class);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        for (String name : context.getBeanDefinitionNames()) {
            Class<?> c = context.getBean(name).getClass();
            log.debug("===> Name: {}, Type = {}", name, c.getTypeName());
        }
    }

}
@RestController
@RequestMapping("/bean")
public class BeanRestController {

    @Autowired
    private SingletonBean singletonBean;

    @GetMapping("/name")
    public String getName() {
        return singletonBean.getPrototypeBean().getClass().getName();
    }

}

When I execute application with -Dspring.profiles.active=dev setting

Then I see in the log without no issue and REST endpoint gives back response properly:

===> Name: prototypeBean, Type = PrototypeBean

But if I execute application without profile setting

Then I see error in the log and REST endpoint raise exception:

org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'PrototypeBean' available

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

I get the 'Error creating bean with name 'requestMappingHandlerAdapter' defined in class path resource' for my spring boot application

i am not able to get cookie in my Servlet

Spring Boot trying to resolve bean not in my xml

Spring application context has my bean but @autowired doesn't see it

Why I can't inject a Spring Environment object into my bean?

Why I am not able to refer to my sequence with double quotes in postgres?

Why am i not able to push files into My Git Repo

Why do I get a "405 - Method Not Allowed" error when trying to open a .css file in my Spring Boot/Spring Security web app?

I am not able to get spring in the simulation

I am not able to get a field in my Django ManyToMany Relation

Why spring can't find my bean?

Why I am not able to receive data in my adapter

Why i am not able to change the dummy variable here in my code?

Why am I able to instantiate my Abstract Base Class in Python?

Why am I not being able to connect to my database?

How to programatically add an @Bean definition to Spring context?

Why i am not able to call adapter method from my activity

Why am I not able to get proper dates in my graph?

Why am I not able to get data to my AngularJS component via bindings?

Why am I not able to use promise in my basic react app?

Why am I not able oneHot encode my data labels?

Why If I upload a picture Spring Boot searches in my computer?

WHY I am not able to get state from redux to my React app?

Why am I not able to pickup items in my text based game?

Why am I not being able to insert values into my SQL database?

How can i get my Application Context in xml defination while working in Spring Boot

I am not able to search my users by email using JPA spring boot

Why am I not able to set cookies on my device?

Why am I not able to access the REST API exposed by my service?