spring 5.1.9-RELEASE
spring boot 2.1.7-RELEASE
when i has internal class to register ,i use #EnableConfigurationProperties marks on class A and B ,at this time has happen exception; i remove the class A annotation;at this time started successful;
the class B use #EnableConfigurationProperties registering C,at this time B is also registered,the classB should b be registered at this time ?
But when I move the two internal classes to the same path as TestConfiguration, both class A and class B have to be #EnableConfigurationProperties annotated to complete the startup
package com.test.configuration;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.test.configuration.TestConfiguration.TestConfigB;
import lombok.Data;
#Configuration
#EnableConfigurationProperties(TestConfigB.class)
public class TestConfiguration {
#Bean
#ConditionalOnMissingBean(TestConfigA.class)
#ConditionalOnProperty(prefix = "test-a", name = "enable", havingValue = "true", matchIfMissing = true)
public TestConfigA testConfigA(TestConfigB testConfigB) {
return new TestConfigA();
}
#Data
public class TestConfigA {
private String name;
}
#Data
#ConfigurationProperties(prefix = "test-b")
#EnableConfigurationProperties(TestConfigC.class)
public class TestConfigB {
private String applicationId;
#Autowired
TestConfigC axxcConfig;
public String getApplicationId() {
if (applicationId == null) {
applicationId = axxcConfig.getApplicationId();
}
return applicationId;
}
}
#ConfigurationProperties(prefix = "test-c")
public class TestConfigC implements ApplicationContextAware {
private String applicationId;
private ApplicationContext applicationContext;
public String getApplicationId() {
if (applicationId == null) {
applicationId = applicationContext.getEnvironment().getProperty("spring.application.name");
}
return applicationId;
}
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
}
Your #ConfigurationProperties classes need to be static so that copies of them can be created independently of (before) the containing configuration class.
Related
I am trying to get my OrderController to work, but MVC can't seem to find it. Does anyone know why this happens?
Initializer class. The getServletMapping method keeps notifying me about Not annotated method overrides method annotated with #NonNullApi
package configs;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class Initializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[0];
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{Config.class};
}
#Override
protected String[] getServletMappings() {
return new String[] { "/api/*" };
}
}
The config class.
package configs;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ClassPathResource;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.jdbc.datasource.init.DatabasePopulatorUtils;
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import javax.sql.DataSource;
#EnableWebMvc
#Configuration
#ComponentScan(basePackages = {"model"})
#PropertySource("classpath:/application.properties")
public class Config {
#Bean
public JdbcTemplate getTemplate(DataSource ds) {
return new JdbcTemplate(ds);
}
#Bean
public DataSource dataSource(Environment env) {
DriverManagerDataSource ds = new DriverManagerDataSource();
ds.setDriverClassName("org.hsqldb.jdbcDriver");
ds.setUrl(env.getProperty("hsql.url"));
var populator = new ResourceDatabasePopulator(
new ClassPathResource("schema.sql"),
new ClassPathResource("data.sql")
);
DatabasePopulatorUtils.execute(populator, ds);
return ds;
}
}
Then the controller.
package controllers;
import model.Order;
import model.OrderDAO;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import java.util.List;
#RestController
public class OrderController {
private OrderDAO orderdao;
public OrderController(OrderDAO orderDAO) {
this.orderdao = orderDAO;
}
#PostMapping("orders")
#ResponseStatus(HttpStatus.CREATED)
public Order saveOrder(#RequestBody Order order) {
return orderdao.addOrder(order);
}
#GetMapping("orders/{id}")
public Order getOrderById(#PathVariable Long id) {
return orderdao.getOrderById(id);
}
#GetMapping("orders")
public List<Order> getOrders() {
return orderdao.getAllOrders();
}
#DeleteMapping("orders/{id}")
public void deleteOrderById(#PathVariable Long id) {
orderdao.deleteOrderById(id);
}
}
Everything seems fine, I can't find the issue.
Since the OrderController is in the controllers package, I forgot to add the package in the configs componentScan parameters.
Your controller registers the endpoints at /orders/*, but in getServletMappings you specify the /api/*. You should add /api prefix to your controller, like this
#RestController
#RequestMapping("api")
public class OrderController {
...
This question already has an answer here:
Why autowiring spring repositories doesn't work?
(1 answer)
Closed 2 years ago.
I've a test class which autowires the CatalogDao class. But the CatalogDao class is not autowired. The value is null;
Test class
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {PersistenceConfig.class})
public class CatalogDaoIT {
#Autowired
private CatalogDao catalogDao;
#Test
public void saveCatalog_readSame_foundOne() {
// arrange
Catalog catalog = new Catalog();
Config class
package ch.matica.platform.persistence.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
#Configuration
#PropertySource("classpath:application.properties")
#ComponentScan(basePackages = "ch.matica.platform.persistence")
public class PersistenceConfig {
#Bean
public static PropertySourcesPlaceholderConfigurer propertiesResolver() {
return new PropertySourcesPlaceholderConfigurer();
}
}
The DAO class
package ch.matica.platform.persistence;
import java.util.Collection;
...
#Repository
public class CatalogDao {
...
Can you change your code to this:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {PersistenceConfig.class})
public class CatalogDaoIT {
#Autowired
private CatalogDao catalogDao;
//autowire by type, a private field and a setter
#Autowired
public void setCatalogDao(CatalogDao cd){
this.catalogDao=cd;
}
#Test
public void saveCatalog_readSame_foundOne() {
// arrange
Catalog catalog = new Catalog();
I think this will help.
For me this worked
#SpringBootTest
public class CatalogDaoIT {
....
}
I want to create a DAO object by dependency injection (#Autowire) but unfortunately, this DAO object is never created and hence a Nullpointer exception is thrown.
This is my DAO implementation:
package com.sample.dao.service;
#Component
public class OrderServiceImpl implements OrderService {
private final OrderRepository orderRepository;
#Autowired
OrderServiceImpl(OrderRepository orderRepository) {
this.orderRepository = orderRepository;
}
#Override
public void save(Order order) {
return orderRepository.save(order);
}
The class where the Nullpointer exception is caused:
package com.sample.dispatcher;
#Component
public class OrderDispatcher {
private final OrderServiceImpl orderServiceImpl;
#Autowired
public OrderDispatcher(OrderServiceImpl orderServiceImpl) {
this.orderServiceImpl = orderServiceImpl;
}
public void createOrder(Order order) {
orderServiceImpl.save(order)); // --> Nullpointer
My entry class:
package com.sample;
#SpringBootApplication
#ComponentScan(basePackages = { "com.sample" , "com.webservice"})
#EnableJpaRepositories(basePackages = "com.sample.dao.repository")
public class Application {
public static void main(final String[] args) {
SpringApplication.run(Application.class, args);
I think you should change your constructor to have an argument type of interface rather than a concrete implementation. So something like this -
#Component
public class OrderDispatcher {
private final OrderService orderServiceImpl;
#Autowired
public OrderDispatcher(OrderService orderServiceImpl) {
this.orderServiceImpl = orderServiceImpl;
}
When you add the #component notation on OrderServiceImpl, Spring creates proxy for that class and it can be autowired by interface.
Maybe you forgot the #annotation configuration. Try adding this class and also you scan your entities: EntityScan
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
#Configuration
#EntityScan("com.sample.model") // Your model package
#ComponentScan(basePackages = { "com.sample" , "com.webservice"})
#EnableJpaRepositories(basePackages = "com.sample.dao.repository")
public class RepositoryConfig {
}
AppConfig contains Java Configuration.
package com.wh;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableLoadTimeWeaving;
import org.springframework.context.annotation.EnableLoadTimeWeaving.AspectJWeaving;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.aspectj.EnableSpringConfigured;
#Configuration
#EnableSpringConfigured
#EnableLoadTimeWeaving(aspectjWeaving=AspectJWeaving.ENABLED)
public class AppConfig {
#Bean
#Lazy
public EchoService echoService(){
return new EchoService();
}
#Bean
public InstrumentationLoadTimeWeaver loadTimeWeaver() throws Throwable {
InstrumentationLoadTimeWeaver loadTimeWeaver = new InstrumentationLoadTimeWeaver();
return loadTimeWeaver;
}
}
Service Class
package com.wh;
import org.springframework.stereotype.Service;
#Service
public class EchoService {
public void echo( String s ) {
System.out.println( s );
}
}
EchoDelegateService is the Non Bean class in which we have Autowired The required Bean.
We expect that the EchoService should get autowired.
Problem : EchoService not getting autowired. Gives an Null Pointer exception.
package com.wh;
import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
#Configurable( preConstruction = true, autowire = Autowire.BY_TYPE, dependencyCheck = false )
public class EchoDelegateService {
#Autowired
private EchoService echoService;
public void echo( String s ) {
echoService.echo( s );
}
}
Main Class where we are calling method of NonBean Class.
package com.wh;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class MainApp {
public static void main(String[] args) {
ApplicationContext ctx =
new AnnotationConfigApplicationContext(AppConfig.class);
new EchoDelegateService().echo("hihi, it works...");
}
}
Your question already includes the answer: "... in a non-bean class". This simply does not work. All the autowiring, aspect resolving and whatever is to that, only works for beans. Thus, you definitely need to construct your EchoDelegateService via the spring factory:
EchoDelegateService myService = ctx.getBean(EchoDelegateService.class);
myService.echo("this should really work now");
I'm trying to put together an SDK that uses Spring internally through a context it manages of its own. I want the jar that gets built to be usable regardless of whether or not Spring is in use on the application that wants to use the SDK.
I have something that works when it is running on its own. However if I attempt to use the SDK inside another Spring context (in my case a Spring Boot based application) I get a org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type exception.
Try as I might I cannot understand how to get this working, or indeed what I am doing wrong. The classes below show what I'm doing, the org.example.testapp.MySDKTest fails with the exception while the org.example.test.MySDKTest successfully passes. Sorry there is so much code but I can't reproduce the issue with a simplified case.
SDK source
package org.example.mysdk;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.example.mysdk.MyService;
import org.example.mysdk.MyServiceConfiguration;
public final class MySDK {
private static ApplicationContext applicationContext;
public static <T extends MyService> T getService(Class<? extends MyService> clazz, MyServiceConfiguration configuration) {
T tmp = (T) getApplicationContext().getBean(clazz);
tmp.setConfiguration(configuration);
return tmp;
}
private static ApplicationContext getApplicationContext() {
if (applicationContext == null) {
applicationContext = new AnnotationConfigApplicationContext(SpringContext.class);
}
return applicationContext;
}
}
.
package org.example.mysdk;
import org.springframework.beans.factory.annotation.Autowired;
public abstract class MyService {
private MyServiceConfiguration configuration;
#Autowired
private MyAutowiredService myAutowiredService;
MyService() {
}
MyService(MyServiceConfiguration configuration) {
super();
this.configuration = configuration;
}
public MyServiceConfiguration getConfiguration() {
return configuration;
}
void setConfiguration(MyServiceConfiguration configuration) {
this.configuration = configuration;
}
String getSomething(String in) {
return "something + " + myAutowiredService.getThing(configuration.getValue()) + " and " + in;
}
}
.
package org.example.mysdk;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
#Service
#Scope("prototype")
public class MyServiceImpl1 extends MyService {
public MyServiceImpl1() {
}
public MyServiceImpl1(MyServiceConfiguration configuration) {
super(configuration);
}
public String method1() {
return this.getSomething("method1");
}
}
.
package org.example.mysdk;
public class MyServiceConfiguration {
private String value;
public void setValue(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
.
package org.example.mysdk;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
#Service
public class MyAutowiredService {
private String thing = "a value";
public String getThing(String in) {
return thing + " " + in;
}
#PostConstruct
void init() {
System.out.println("MyAutowiredService bean created");
}
}
.
package org.example.mysdk;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
#Configuration
#ComponentScan(basePackages = {
"org.example.mysdk"
})
public class SpringContext {
}
Tests
This first test fails with a org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type exception,
package org.example.testapp;
import static org.junit.Assert.*;
import org.example.mysdk.MyServiceConfiguration;
import org.example.mysdk.MyServiceImpl1;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.AnnotationConfigContextLoader;
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = App.class, loader = AnnotationConfigContextLoader.class)
public class MySDKTest {
#Autowired
MyServiceImpl1 service;
#Test
public void test() {
MyServiceConfiguration conf = service.getConfiguration();
assertEquals(conf.getValue(), "this is the instance configuration");
}
}
.
package org.example.testapp;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.example.mysdk.MySDK;
import org.example.mysdk.MyServiceConfiguration;
import org.example.mysdk.MyServiceImpl1;
#Configuration
#ComponentScan(basePackages = {
"org.example.testapp"
})
public class App {
#Bean
public MyServiceImpl1 myServiceImpl1() {
MyServiceConfiguration configuration = new MyServiceConfiguration();
configuration.setValue("this is the instance configuration");
return MySDK.getService(MyServiceImpl1.class, configuration);
}
}
and this test succeeds,
package org.example.test;
import static org.junit.Assert.*;
import org.example.mysdk.MySDK;
import org.example.mysdk.MyServiceConfiguration;
import org.example.mysdk.MyServiceImpl1;
import org.junit.Test;
public class MySDKTest {
#Test
public void test() {
MyServiceConfiguration configuration = new MyServiceConfiguration();
configuration.setValue("this is the instance configuration");
MyServiceImpl1 service = MySDK.getService(MyServiceImpl1.class, configuration);
assertEquals(service.getConfiguration().getValue(), "this is the instance configuration");
}
}
If I've gone about this the completely wrong way I'm happy to hear suggestions of how this should be done differently!
You have to modify two files.
First App.java, it should scan for "org.example.mysdk" package to inject myAutowiredService in abstract class MyService, If not it has to be created in App.java. And the name of the MyServiceImpl1 bean must be different from myServiceImpl1 as it will conflict.
package org.example.testapp;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.example.mysdk.MySDK;
import org.example.mysdk.MyServiceConfiguration;
import org.example.mysdk.MyServiceImpl1;
#Configuration
#ComponentScan(basePackages = {
"org.example.testapp", "org.example.mysdk"
})
public class App {
#Bean
public MyServiceImpl1 myServiceImpl() {
MyServiceConfiguration configuration = new MyServiceConfiguration();
configuration.setValue("this is the instance configuration");
return MySDK.getService(MyServiceImpl1.class, configuration);
}
}
Then secondly in MySDKTest.java should inject myServiceImpl which was created in App.java
import static org.junit.Assert.*;
import org.example.mysdk.MyServiceConfiguration;
import org.example.mysdk.MyServiceImpl1;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.AnnotationConfigContextLoader;
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = App.class, loader = AnnotationConfigContextLoader.class)
public class MySDKTest {
#Autowired
MyServiceImpl1 myServiceImpl;
#Test
public void createOxiAccountService() {
MyServiceConfiguration conf = myServiceImpl.getConfiguration();
assertEquals(conf.getValue(), "this is the instance configuration");
}
}