Currently I have a repositories package. I map that package to the MongoTemplate like this
#Setter
#Configuration
#EnableConfigurationProperties
#ConfigurationProperties(prefix = "myservice.mongodb")
#EnableMongoRepositories(basePackages = { "mycustom.repository" }, mongoTemplateRef = "customMongoTemplate")
public class CustomMongoConfiguration extends MongoConfiguration {
private String host;
private String database;
private int port;
#Bean(name = "customMongoTemplate")
public MongoTemplate getMongoTemplate() throws Exception {
return new MongoTemplate(mongoDbFactory(host,port,database));
}
}
In mongoDbFactory(), I'm using SimpleMongoDbFactory() to return an instance of MongoDbFactory.
Is there a way to make the mapping of my mongoTemplate bean to my repository package during runtime/dynamically?
A small example would be helpful. Thanks
Related
I am trying to retrieve value from application.yml. The final line below is showing kafkaConfig as null, and cannot read. How do I setup the Kafka Config and code properly, to read from the json file? We are using #Data instead of getters/setters.
KafkaConfig.java
#Configuration
#ConfigurationProperties("kafka")
#Data
public class KafkaConfig {
private String topic;
private String event;
}
Application.yml
kafka:
topic: "testTopic"
event: "testEvent"
KafkaProducerBeans.java
#Component
public class KafkaProducerBeans {
#Autowired
private KafkaConfig kafkaConfig;
public KafkaProducerBeans(KafkaConfig kafkaConfig) {
this.kafkaConfig = kafkaConfig;
}
#Bean(name = "kafkaTestClient")
public String getData() {
return kafkaConfig.getTopic(); // final line is creating null for kafka Config
}
Resource: https://codingnconcepts.com/spring-boot/spring-configuration-properties-using-yml/
I think the recommended way of binding properties to pojos is to use the #EnableConfigurationProperties annotation like so:
KafkaConfig.java
#ConfigurationProperties("kafka")
#Data
public class KafkaConfig {
private String topic;
private String event;
}
KafkaProducerBeans.java
#Component
#EnableConfigurationProperties(KafkaConfig.class)
public class KafkaProducerBeans {
private final KafkaConfig kafkaConfig;
#Autowired
public KafkaProducerBeans(KafkaConfig kafkaConfig) {
this.kafkaConfig = kafkaConfig;
}
// [...]
}
Refer to the official Spring Documentation for further details:
https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.external-config.typesafe-configuration-properties.java-bean-binding
https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.external-config.typesafe-configuration-properties.enabling-annotated-types
Add one more annotation #EnableConfigurationProperties on the class KafkaConfig
KafkaConfig.java
#Configuration
#EnableConfigurationProperties // new added annotation
#ConfigurationProperties("kafka")
#Data
public class KafkaConfig {
private String topic;
private String event;
}
#ComponentScan(basePackages ="PATH" )
PATH: the package path you want it to look for
#ComponentScan(basePackages ="PATH" )
#Configuration
#Import(value = {
KafkaProducerBeans.class
})
public class AppConfig{
}
i would like to load #Configuration classes in an order. i have two configuration classes. i am having a requirement of loading my SampleProperties class before sampleconfiguration class.
I have tried the following annotations but it is not working as expected.
#AutoConfigureAfter(SampleProperties.class )
#AutoConfigureBefore(SampleConfiguration.class)
I have put my congiurations class in diff package in order to read configurations classes in an order.using #Import function, i am including my configuration classes into my application
My Main Class:
#Import({SampleProperties.class,SampleConfiguration.class,})
public class SampleApplication{
public static void main(String[] args) {
SpringApplication.run(SampleApplication.class, args);
}
}
My SampleProperties Class
#Configuration
#AutoConfigureBefore(SampleConfiguration.class)
#ConfigurationProperties("demo")
#Data
public class SampleProperties {
private String team;
private int teamSize;
private String teamLeader;
}
My sampleconfiguration Class:
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(entityManagerFactoryRef="sampleEntityManager",
transactionManagerRef="sampleTransactionManager",
basePackages= {"com.example.demo.repo"})
#AutoConfigureAfter(SampleProperties.class)
public class SampleConfiguration {
#Autowired
Environment env;
#Bean(name="sampleDataSource")
#Primary
public DataSource dmsDataSource() {
// functions
return null;
}
#Primary
#Bean(name = "sampleEntityManager")
public LocalContainerEntityManagerFactoryBean dmsEntityManagerFactory(EntityManagerFactoryBuilder builder) {
// functions
return null;
}
#Primary
#Bean(name = "sampleTransactionManager")
public PlatformTransactionManager dmsTransactionManager(#Qualifier("sampleEntityManager") EntityManagerFactory entityManagerFactory) {
// functions
return null;
}
}
can anyone tell me what missing and where am making mistakes?
I think you have to use #Order annotation.
#Component
#Order(1)
public class SampleProperties {
// code
}
#Component
#Order(2)
public class SampleConfiguration {
// code
}
I have a simple SpringBoot application in which i am using the Environment.class to access the properties under application.properties file. The Environment bean works when it is accessed in the main method of the Application.class
#Configuration
#EnableAutoConfiguration
#ComponentScan(basePackages = "com.cisco.sdp.cdx.consumers")
public class StreamingConsumerApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(StreamingConsumerApplication.class, args);
Environment env = context.getBean(Environment.class);
StreamingConsumerFactory factory = context.getBean(StreamingConsumerFactory.class);
StreamingConsumer streamingConsumer = factory.createStreamingConsumer(StreamType.valueOf(env.getRequiredProperty("streaming.application.type")));
streamingConsumer.consume();
}
}
When the same is used in a different class it throws NullPointerException. I tried annotating the class with #Configuration,#Component,#Repository,#Service annotations but did not work.
I tried #Autowired as well as #Resource annotations. But, it didn't work.
#Component
public class InventoryStreamingConsumer implements StreamingConsumer {
#Autowired
private Environment env;
#Autowired
private JavaSparkSessionSingleton sparksession;
#Autowired
private StreamingContext _CONTEXT;
private final Map<String, String> kafkaParams = new HashMap<String, String>();
#Override
public void consume() {
if(env == null) {
System.out.println("ENV is NULL");
}
System.out.println(env.getRequiredProperty("kafka.brokerlist"));
kafkaParams.put("metadata.broker.list", env.getRequiredProperty("kafka.brokerlist"));
Set<String> topics = Collections.singleton(env.getRequiredProperty("kafka.topic"));
// Unrelated code.
}
I tried following the answers provided in the below questions
Spring Boot - Environment #Autowired throws NullPointerException
Autowired Environment is null
I am looking for suggestions on solving the issue.
The #Configuration annotation is misused here for InventoryStreamingConsumer. Try #Component, #Repository or #Service.
UPDATE
Another misuse is
StreamingConsumer streamingConsumer = factory.createStreamingConsumer(StreamType.valueOf(env.getRequiredProperty("streaming.application.type")));
#Autowired or #Resource can only work in bean created by Spring. the streamingConsumer created by your StreamingConsumerFactory factory cannot use #Autowired for injection of its properties.
You should create an #Configuration class, to tell Spring to create streamingConsumer from your factory. Like this
#Configuration
public class ConsumerCreator {
#Autowired
StreamingConsumerFactory factory;
#Bean
public StreamingConsumer streamingConsumer() {
return factory.createStreamingConsumer(StreamType.valueOf(env.getRequiredProperty("streaming.application.type")));
}
}
And use no annotation for InventoryStreamingConsumer, meanwhile use
StreamingConsumer streamingConsumer = context.getBean(StreamingConsumer.class);
in your StreamingConsumerApplication.main() method instead to retrieve streamingConsumer
First, please annotate the main class with only #SpringBootApplication
#SpringBootApplication
public class StreamingConsumerApplication {
}
#ComponentScan is required if your packages are not within the same structure as main class with main class being outside the sub-package and inside parent package with every other class in the same or some sub-package of parent package.
Second, Please create a Configuration class and annotate it with #Configuration separately and define a #Bean there for StreamingConsumer streamingConsumer and than it can be #Autowired or injected in the InventoryStreamingConsumer class.
Third, where is the #Bean for JavaSparkSessionSingleton defined? Are you sure it can be AutoConfigured for injection
Fourth, InventoryStreamingConsumer can be a #Component, injecting Environment with #Autowiring will work once the above things are sorted.
Also, recommending to change your class to this for the sake depending on how consume() method is used.
#Component
public class InventoryStreamingConsumer implements StreamingConsumer {
private final Environment env;
private final JavaSparkSessionSingleton sparksession;
private final StreamingContext _CONTEXT;
private final Map<String, String> kafkaParams = new HashMap<String, String>();
#Autowired
public InventoryStreamingConsumer(Environment env, JavaSparkSessionSingleton sparkSession, StreamingContext context) {
this.env = env;
this.sparksession = sparkSession;
this._CONTEXT = context;
}
#Override
public void consume() {
if(env == null) {
System.out.println("ENV is NULL");
}
System.out.println(env.getRequiredProperty("kafka.brokerlist"));
kafkaParams.put("metadata.broker.list", env.getRequiredProperty("kafka.brokerlist"));
Set<String> topics = Collections.singleton(env.getRequiredProperty("kafka.topic"));
// Unrelated code.
}
I have similar issue but read the properties from different file and different location like common/jdbc.properties. I solved this issue by doing this:
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.core.env.Environment;
#Configuration
#PropertySource(value = {"classpath:common/jdbc.properties"})
public class ExternalConfig implements EnvironmentAware {
private Environment environment;
public void setEnvironment(Environment environment) {
this.environment = environment;
}
#Bean
public static PropertySourcesPlaceholderConfigurer propertyConfigInDev() {
return new PropertySourcesPlaceholderConfigurer();
}
public String getJdbcUrl() {
return environment.getProperty("jdbc.url");
}
}
Try adding
#PropertySource("classpath:application.properties")
on InventoryStreamingConsumer class
This is how am using it
#Configuration
#ComponentScan({ "com.spring.config" })
#EnableTransactionManagement
#PropertySource("classpath:application.properties")
public class HibernateConfiguration {
private static final String PROPERTY_NAME_DATABASE_DRIVER = "db.driver";
private static final String PROPERTY_NAME_DATABASE_PASSWORD = "db.password";
private static final String PROPERTY_NAME_DATABASE_URL = "db.url";
private static final String PROPERTY_NAME_DATABASE_USERNAME = "db.username";
private static final String PROPERTY_NAME_HIBERNATE_DIALECT = "hibernate.dialect";
private static final String PROPERTY_NAME_HIBERNATE_SHOW_SQL = "hibernate.show_sql";
#Autowired
private Environment env;
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(env.getRequiredProperty(PROPERTY_NAME_DATABASE_DRIVER));
dataSource.setUrl(env.getRequiredProperty(PROPERTY_NAME_DATABASE_URL));
dataSource.setUsername(env.getRequiredProperty(PROPERTY_NAME_DATABASE_USERNAME));
dataSource.setPassword(env.getRequiredProperty(PROPERTY_NAME_DATABASE_PASSWORD));
return dataSource;
}
I have a Spring application and in it I do not use xml configuration, only Java Config. Everything is OK, but when I try to test it I faced problems with enabling autowiring of components in the tests. So let's begin. I have an interface:
#Repository
public interface ArticleRepository extends CrudRepository<Page, Long> {
Article findByLink(String name);
void delete(Page page);
}
And a component/service:
#Service
public class ArticleServiceImpl implements ArticleService {
#Autowired
private ArticleRepository articleRepository;
...
}
I don't want to use xml configurations so for my tests I try to test ArticleServiceImpl using only Java Configuration. So for the test purpose I made:
#Configuration
#ComponentScan(basePackages = {"com.example.core", "com.example.repository"})
public class PagesTestConfiguration {
#Bean
public ArticleRepository articleRepository() {
// (1) What to return ?
}
#Bean
public ArticleServiceImpl articleServiceImpl() {
ArticleServiceImpl articleServiceImpl = new ArticleServiceImpl();
articleServiceImpl.setArticleRepository(articleRepository());
return articleServiceImpl;
}
}
In articleServiceImpl() I need to put instance of articleRepository() but it is an interface. How to create new object with new keyword? Is it possible without creating xml configuration class and enable Autowiring? Can autowired be enabled when using only JavaConfigurations during testing?
This is what I have found is the minimal setup for a spring controller test which needs an autowired JPA repository configuration (using spring-boot 1.2 with embedded spring 4.1.4.RELEASE, DbUnit 2.4.8).
The test runs against a embedded HSQL DB which is auto-populated by an xml data file on test start.
The test class:
#RunWith( SpringJUnit4ClassRunner.class )
#ContextConfiguration( classes = { TestController.class,
RepoFactory4Test.class } )
#TestExecutionListeners( { DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class,
TransactionDbUnitTestExecutionListener.class } )
#DatabaseSetup( "classpath:FillTestData.xml" )
#DatabaseTearDown( "classpath:DbClean.xml" )
public class ControllerWithRepositoryTest
{
#Autowired
private TestController myClassUnderTest;
#Test
public void test()
{
Iterable<EUser> list = myClassUnderTest.findAll();
if ( list == null || !list.iterator().hasNext() )
{
Assert.fail( "No users found" );
}
else
{
for ( EUser eUser : list )
{
System.out.println( "Found user: " + eUser );
}
}
}
#Component
static class TestController
{
#Autowired
private UserRepository myUserRepo;
/**
* #return
*/
public Iterable<EUser> findAll()
{
return myUserRepo.findAll();
}
}
}
Notes:
#ContextConfiguration annotation which only includes the embedded TestController and the JPA configuration class RepoFactory4Test.
The #TestExecutionListeners annotation is needed in order that the subsequent annotations #DatabaseSetup and #DatabaseTearDown have effect
The referenced configuration class:
#Configuration
#EnableJpaRepositories( basePackageClasses = UserRepository.class )
public class RepoFactory4Test
{
#Bean
public DataSource dataSource()
{
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
return builder.setType( EmbeddedDatabaseType.HSQL ).build();
}
#Bean
public EntityManagerFactory entityManagerFactory()
{
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setGenerateDdl( true );
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter( vendorAdapter );
factory.setPackagesToScan( EUser.class.getPackage().getName() );
factory.setDataSource( dataSource() );
factory.afterPropertiesSet();
return factory.getObject();
}
#Bean
public PlatformTransactionManager transactionManager()
{
JpaTransactionManager txManager = new JpaTransactionManager();
txManager.setEntityManagerFactory( entityManagerFactory() );
return txManager;
}
}
The UserRepository is a simple interface:
public interface UserRepository extends CrudRepository<EUser, Long>
{
}
The EUser is a simple #Entity annotated class:
#Entity
#Table(name = "user")
public class EUser
{
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.AUTO)
#Max( value=Integer.MAX_VALUE )
private Long myId;
#Column(name = "email")
#Size(max=64)
#NotNull
private String myEmail;
...
}
The FillTestData.xml:
<?xml version="1.0" encoding="UTF-8"?>
<dataset>
<user id="1"
email="alice#test.org"
...
/>
</dataset>
The DbClean.xml:
<?xml version="1.0" encoding="UTF-8"?>
<dataset>
<user />
</dataset>
If you're using Spring Boot, you can simplify these approaches a bit by adding #SpringBootTest to load in your ApplicationContext. This allows you to autowire in your spring-data repositories. Be sure to add #RunWith(SpringRunner.class) so the spring-specific annotations are picked up:
#RunWith(SpringRunner.class)
#SpringBootTest
public class OrphanManagementTest {
#Autowired
private UserRepository userRepository;
#Test
public void saveTest() {
User user = new User("Tom");
userRepository.save(user);
Assert.assertNotNull(userRepository.findOne("Tom"));
}
}
You can read more about testing in spring boot in their docs.
You cant use repositories in your configuration class because from configuration classes it finds all its repositories using #EnableJpaRepositories.
So change your Java Configuration to:
#Configuration
#EnableWebMvc
#EnableTransactionManagement
#ComponentScan("com.example")
#EnableJpaRepositories(basePackages={"com.example.jpa.repositories"})//Path of your CRUD repositories package
#PropertySource("classpath:application.properties")
public class JPAConfiguration {
//Includes jpaProperties(), jpaVendorAdapter(), transactionManager(), entityManagerFactory(), localContainerEntityManagerFactoryBean()
//and dataSource()
}
If you have many repository implementation classes then create a separate class like below
#Service
public class RepositoryImpl {
#Autowired
private UserRepositoryImpl userService;
}
In your controller Autowire to RepositoryImpl and from there you can access all your repository implementation classes.
#Autowired
RepositoryImpl repository;
Usage:
repository.getUserService().findUserByUserName(userName);
Remove #Repository Annotation in ArticleRepository and ArticleServiceImpl should implement ArticleRepository not ArticleService.
What you need to do is:
remove #Repository from ArticleRepository
add #EnableJpaRepositories to PagesTestConfiguration.java
#Configuration
#ComponentScan(basePackages = {"com.example.core"}) // are you sure you wanna scan all the packages?
#EnableJpaRepositories(basePackageClasses = ArticleRepository.class) // assuming you have all the spring data repo in the same package.
public class PagesTestConfiguration {
#Bean
public ArticleServiceImpl articleServiceImpl() {
ArticleServiceImpl articleServiceImpl = new ArticleServiceImpl();
return articleServiceImpl;
}
}
I am trying to get a Spring-boot application going and I am not sure what I am doing wrong here. I have a application.properties file at src/main/resources & src/test/resources. I have an #Bean for my ConfigurationSettings so that I can use them throughout my application:
#Component
public class ConfigurationSettings {
private String product;
private String version;
private String copyright;
private String appName;
private String appDescription;
...
// getters and setters
}
Here is how I kick the application off:
#Configuration
#EnableJpaRepositories
#EnableAutoConfiguration
#EnableConfigurationProperties
#PropertySources(value = {#PropertySource("classpath:application.properties")})
#ComponentScan(basePackages = "com.product")
#EnableScheduling
public class OFAC {
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run( OFAC.class, args );
}
And here is my configuration class:
#Configuration
#ComponentScan(basePackages = {"com.product"})
#PropertySources(value = {#PropertySource("classpath:application.properties")})
public class OFAConfiguration {
#Autowired
private Environment env;
#Bean
public ConfigurationSettings configurationSettings() {
ConfigurationSettings configurationSettings = new ConfigurationSettings();
configurationSettings.setAppDescription( env.getRequiredProperty("app.description" ) );
configurationSettings.setAppName( env.getRequiredProperty( "app.name" ) );
configurationSettings.setServerPort( env.getRequiredProperty( "server.port" ) );
return configurationSettings;
}
I am trying to use it in a controller:
#RestController
public class AboutController {
#Autowired
private ConfigurationSettings configurationSettings;
#RequestMapping(value = "/about", method = RequestMethod.GET)
public About index() {
String product = configurationSettings.getProduct();
String version = configurationSettings.getVersion();
String copyright = configurationSettings.getCopyright();
return new About( product, version, copyright );
}
}
However, when step thru this, all the values of ConfigurationSettings are null. I do have a test that successfully loads the values:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {OFAConfiguration.class})
public class OFAConfigurationTest {
#Autowired
private Environment environment;
#Autowired
private ConfigurationSettings configurationSettings;
#Test
public void testConfigurationLoads() {
assertNotNull(environment);
Assert.assertNotNull(configurationSettings);
}
#Test
public void testConfigurationSettingValues() {
assertEquals("Product Name", configurationSettings.getProduct());
assertEquals("0.0.1", configurationSettings.getVersion());
assertEquals("2014 Product", configurationSettings.getCopyright());
}
Can anyone see why the ConfigurationSettings are not being populated in my Controller?
Your configuration leads to 2 instances of the ConfigurationSettings class and probably one instance overrides the other.
The 'ConfigurationSettings' has the #Component annotation as you are scanning for components (#ComponentScan) this will lead to an instance. You also have a #Bean annotated method which also leads to an instance. The latter is overridden with the first.
In short remove the #Component annotation as that isn't needed because you already have a factory method for this class.
public class ConfigurationSettings { ... }
You should also remove the #PropertySource annotations as Spring-Boot will already load the application.properties for you.
Finally you should not use the #ContextConfiguration annotation on your test class but the #SpringApplicationConfiguration and pass in your application class (not your configuration class!).
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes=OFAC.class)
public class OFAConfigurationTest {
#Autowired
private Environment environment;
#Autowired
private ConfigurationSettings configurationSettings;
#Test
public void testConfigurationLoads() {
assertNotNull(environment);
assertNotNull(configurationSettings);
}
#Test
public void testConfigurationSettingValues() {
assertEquals("Product Name", configurationSettings.getProduct());
assertEquals("0.0.1", configurationSettings.getVersion());
assertEquals("2014 Product", configurationSettings.getCopyright());
}
This will fix your runtime configuration problems and will let your test use the power of Spring Boot to configure your application.