How to inject property values into Spring Boot component - jdbc

In my Spring Boot Application, I implemented the following class with a method to call a stored procedure.
#Component
#ConfigurationProperties(prefix = "spring")
public class FmTrfUtil {
static int returnVal;
#Value("${spring.datasource.url}")
static String url;
public static int insertFmTrfs(List<String> trfs, String source) {
System.out.println(url);
EntityManager em = Persistence.createEntityManagerFactory("RIStore_FM").createEntityManager();
Session session = em.unwrap( Session.class );
final String[] trfArray = trfs.toArray(new String[trfs.size()]);
final String src = source;
session.doWork( new Work(){
public void execute(Connection conn) throws SQLException {
CallableStatement stmt = null;
OracleConnection oraCon = conn.unwrap(OracleConnection.class);
Array array = oraCon.createARRAY("VARCHAR2_TAB_T", trfArray);
stmt = conn.prepareCall("{? = call FM_TRF_UTIL.process_fm_trf(?,?)}");
stmt.registerOutParameter(1, Types.INTEGER);
stmt.setArray(2, array);
stmt.setString(3, src);
stmt.execute();
returnVal = stmt.getInt(1);
}
});
return returnVal;
}
}
Since calling stored procedure requires database connection, I need to load the these corresponding property values from application.properties:
spring.profiles.active=dev
spring.datasource.url=jdbc:oracle:thin:#ldap://xxx:389/risdev3, cn=OracleContext,dc=x,dc=net
spring.datasource.username=owner
spring.datasource.password=owner987
Based on the following articles about similar issue, Spring boot - custom variables in Application.properties and Using Spring-Boot configuration properties in your own classes and Spring Boot #ConfigurationProperties example, I added this annotation for my class #ConfigurationProperties(prefix = "spring") (properties for db connection all have "spring" as prefix). However when I run it with a test class as follows, I got error "the application must supply JDBC connection" which means properties in application.properties are not picked up.
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = RistoreWebApplication.class, initializers = ConfigFileApplicationContextInitializer.class)
public class FmTrfUtilTest {
#Test
public void test() {
List<String> trfs = new ArrayList<String>();
trfs.add("TRF000001");
trfs.add("TRF000002");
int ret = FmTrfUtil.insertFmTrfs(trfs, "SARC");
assertTrue(ret > 0);
}
}
In order for #ConfigurationProperties to work, I added maven dependency spring-boot-configuration-processor too. Why is it still not working? What did I miss?

There are few things wrong here:
#Value does not work on static fields
#ConfigurationProperties are used to bind fields from application.properties or application.yml to Java object. Look at any #ConfigurationProperties annotated class from Spring Boot itself to easily understand how it should be used.
you should not use your own #ConfigurationProperties with prefix spring since it's already used by Spring Boot itself
spring-boot-configuration-processor is used only for nicer code completion in your IDE. You do not need this.
If you want to utilize Spring Boot configuration properties for database connection, instead of creating EntityManager like you do:
EntityManager em = Persistence.createEntityManagerFactory("RIStore_FM").createEntityManager();
You should just inject it assuming you have Spring Data JPA Starter in your dependency list.
I see you use lots of static methods and fields. That's not going to work with Spring. Use dependency injection instead and autowire what you need.

Related

Programmatic RedissonClient in Spring boot project

I am trying to implement Hibernate second level caching in a Spring boot project using Redisson.
I have followed this blog as a reference
https://pavankjadda.medium.com/implement-hibernate-2nd-level-cache-with-redis-spring-boot-and-spring-data-jpa-7cdbf5632883
Also i am trying to initialize the RedissionClient programmatically and not through declaratively /through a config file
Created a spring bean to be initialized which should create the RedissonClient instance.
#Configuration
#Lazy(value = false)
public class RedissonConfig {
#Bean
public RedissonClient redissionClient() {
Config config = new Config();
config.useSingleServer().setAddress("redis://127.0.0.1:6379");
return Redisson.create(config);
}
}
However this bean is never intialized and i get the following error while application startup.
Caused by: org.hibernate.cache.CacheException: Unable to locate Redisson configuration
at org.redisson.hibernate.RedissonRegionFactory.createRedissonClient(RedissonRegionFactory.java:107) ~[redisson-hibernate-53-3.12.1.jar:3.12.1]
at org.redisson.hibernate.RedissonRegionFactory.prepareForUse(RedissonRegionFactory.java:83) ~[redisson-hibernate-53-3.12.1.jar:3.12.1]
It seems Spring boot Hibernate still trying to load the Redisson config through a config file.
is it possible to load the Redission config in spring boot programmatically ?
Best Regards,
Saurav
I just did exactly this, here is how:
you need a custom RegionFactory that is similar to the JndiRedissonRegionFactory but gets its RedissonClient injected somehow.
an instance of this Class, fully configured, is put into the hibernate-properties map. Hibernates internal code is flexible: if the value of hibernate.cache.region.factory_class is a string it is treated as a FQDN. If it is an instance of Class<?>, it will be instantiated. If it is an Object, it will be used.
Spring offers a rather simple way to customize hibernate properties with a bean:
#AutoConfiguration(after = RedissonAutoConfiguration.class, before = JpaAutoConfiguration.class)
#ConditionalOnProperty("spring.jpa.properties.hibernate.cache.use_second_level_cache")
public class HibernateCacheAutoConfiguration {
#Bean
public HibernatePropertiesCustomizer setRegionFactory(RedissonClient redisson) {
return hibernateProperties -> hibernateProperties.put(AvailableSettings.CACHE_REGION_FACTORY, new SpringBootRedissonRegionFactory(redisson));
}
}
My RegionFactory is really simple:
#AllArgsConstructor
public class SpringBootRedissonRegionFactory extends RedissonRegionFactory {
private RedissonClient redissonClient;
#Override
protected RedissonClient createRedissonClient(Map properties) {
return redissonClient;
}
#Override
protected void releaseFromUse() {
}
}
I used the redisson-starter to get a RedissonClient, hence the reference to RedissonAutoConfiguration, but you could just create an instance by hand.
It is possible, but then you need to provide a custom implementation of RegionFactory to Hibernate, which can extends RedissonRegionFactory but uses your own client instance.

Spring Boot ConfigurationProperties issues

I have been having issues getting my properties to load in a spring boot app. I made a very simple version and it still fails. I have been going over other questions from the site and just have not been able to figure it out.
application.properties is in main/java/resources
rim.dbuser=RIM_API_USER
rim.dbpassword=rimpassword
rim.dbconnection=jdbc:oracle:thin:#kuga.myrim.com:1515:dev179
rim.dbdriver=oracle.jdbc.driver.OracleDriver
A simple class for the properties
#ConfigurationProperties(prefix = "rim")
public class RIMProperties {
private String driver;
private String dbURL;
private String user;
private String password;
<getters and setters>
My object using the RIMproperties
#Component
public class RIMObject {
#Autowired
private RIMProperties rimProperties;
public void print(){
System.out.println("dbuser = "+rimProperties.getUser());
System.out.println("password = "+rimProperties.getPassword());
System.out.println("driver = "+ rimProperties.getDriver());
System.out.println("DBURL = "+rimProperties.getDbURL());
}
}
and my app class
#SpringBootApplication
#EnableConfigurationProperties(RIMProperties.class)
public class App {
public static void main(String[] args)
{
ApplicationContext context = SpringApplication.run(App.class, args);
RIMObject rimObject = context.getBean(RIMObject.class);
rimObject.print();
RIMProperties prop = context.getBean(RIMProperties.class);
System.out.println(prop.getDriver());
System.out.println(prop.getDbURL());
}
}
I get nulls on everything. Not sure why it is not picking up the properties.
I think the problem is with your variable names, change them to match your props file.
private String driver; to private String dbdriver;
you get the idea...
I assume, you have posted correct code.
As mentioned in some other answer looks like your java field names differ to the properties fields.
For more info take a look at https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config-typesafe-configuration-properties
Spring Boot Autoconfiguration
Moreover, as you are using spring-boot, is there a reason you are not using spring-boot's out of the box auto configuration feature?
In you example you are mapping datasource properties in your java class.
You just need to use spring-boot's standard datasource fields in properties and it will automatically create a DataSource and even JdbcTemplate instance which you can simply autowire anywhere in your app.
Please have a look for more https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-sql.html#boot-features-connect-to-production-database

JAX-RS, Spring & ServletConfig: How to access Servlet Config in Configurator

I have troubles getting a javax.servlet.ServletConfig into a class annotated with org.springframework.context.annotation.Configuration.
My team decided that we should use spring for dependency injection and I'm trying to use it to migrate one of our simple Rest services.
My constraints are:
JAX-RS: We have several REST Services implemented JAX-RS and we don't really want to change that.
Not bound to a specific implementation of JAX-RS (Jersey & RESTEasy work fine for us and we can change from one to the other without changing underlying code)
Import as few dependencies as possible from spring: at the moment I import only org.springframework:spring-context from the spring project.
No API breakage: Deprecated is fine but the service should keep working during the transition, using our old way of doing things.
A string parameter is defined in the service's web.xml. I need to get it, instantiate a Bean with it and inject the resulting bean at several place in the code.
I don't want to mess with Spring Boot/MVC/... as the service already works and I just want the Dependency Injection part.
What I already have:
The code use javax.ws.rs.core.Application, with a class that look like that:
public class MyApplication extends Application {
#Context
private ServletConfig cfg;
public DSApplication() {
}
#Override
public Set<Class<?>> getClasses() {
return new HashSet<>();
}
#Override
public Set<Object> getSingletons() {
Set<Object> set = new HashSet<>();
String injectionStr = cfg.getInitParameter("injection");
boolean injection = false;
if (null != injectionStr && !injectionStr.isEmpty()) {
injection = Boolean.valueOf(injectionStr);
}
if (injection) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
DSServiceProducer.class,
CContextBeanProvider.class
);
IDSService service = context.getBean(IDSService.class);
set.add(service);
} else {
set.add(new DSService()); //Old way
}
return set;
}
}
I need the servlet config in CContextBeanProvider, which look like:
#Configuration
public class CContextBeanProvider {
private ServletConfig cfg; // How to get this here ?
#Bean
public CContextBean cContextBean() {
String bean = cfg.getInitParameter("cpuContext");
return new CContextBean(bean);
}
}
CContextBean is a setting bean initialized from a string found in the web.xml of the service.
Is it possible ?
Do you have any idea how ?
Would it be easier with CDI, knowing that we run on base Tomcat ? (I've already find this if I need to use tomcat with CDI)
Could you please try to add all jersey CDI related jars to your applications ?

Best way to test JPA Spring 3.1

I have written several JPA Repositories, Services and support classes for my Spring 3.1.1/JPA/Hibernate 4 web app. However, I really want to write some unit and integration tests for it (I know, you are supposed to write those first). I am using JavaConfig rather than XML, so I am wondering the best way to test. Here is the particular problem I am trying to solve:
I have a #Configuration that declares DataSource, JpaTransactionManager, LocalContainerEntityManagerFactoryBean, and all my respositories. Obviously I don't want to start all that up for an integration test, so I thought I could use the EmbeddedDatabase and H2 to create an in memory database, populate with values, and then use my Repositories against it. However, the documentation I have seen hasn't helped me put this together. I have this:
#RunWith( SpringJUnit4ClassRunner.class )
public class TestMenuService {
private EmbeddedDatabase database;
#Autowired
private MenuRepository menuRepository;
#Before
public void setUp() throws Exception {
database = new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2).setName("myschema")
.addScript("classpath:schema.sql").build();
menuRepository = new MenuRepository();
Assert.assertNotNull(database);
}
But the menuRepository does not get instantiated, so I tried creating a test version of my #Configuration
#Configuration } )
#ComponentScan( basePackages = { "com.mycompany.service"} )
#EnableTransactionManagement
#ImportResource( "classpath:applicationContext.xml" )
#PropertySource( "classpath:test-application.properties" )
public class TestEdmConfiguration {
#Bean
MenuRepository menuRepository() {
return new MenuRepository();
}
My test-applicationContext.xml
<jpa:repositories base-package="com.mycompany.servce.repository"/>
My test-application.properties:
db.driver=org.h2.Driver
db.username=sa
db.password=
db.url=jdbc:h2:mem:myschema
hibernate.dialect=org.hibernate.dialect.H2Dialect
hibernate.format_sql=true
hibernate.hbm2ddl.auto=create
hibernate.ejb.naming_strategy=org.hibernate.cfg.ImprovedNamingStrategy
hibernate.show_sql=true
But this requires that I create all the datasources, etc mentioned above. It seems like I am just duplicating all the support beans for this one.
Is there a way to have the reposository and embeddeddatabase isolated to my test without all the other dependencies?
If you want to test your repository in a full integration test I would image that you need everything else to be setup i.e. EntityManagerFactory, PlatformTransactionManager etc.
Since you are using Spring 3.1 I would suggest that you achieve this using bean profiles.
I would create two profiles one for tests and one for the application, each of which supplies a datasource.
#Configuration
#Profile("test")
public class EmbeddedDataSource {
#Bean
public DataSource dataSource() {
// Return a H2 datasource
}
}
#Configuration
#Profile("application")
public class ApplicationDataSource {
#Bean
public DataSource dataSource() {
// Return a normal datasource
}
}
The you can create a test which starts up the spring context as follows:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(loader = AnnotationConfigContextLoader.class, classes = { MyConfigClass.class })
#ActiveProfiles(profiles = {"test"})
#TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
public class TestRepository {
}
In here you can specify the profiles where are active for the test.

Convert Spring bean configuration into XML configuration

i am working on BIRT reporting tool. which is need to called by spring MVC.
i got one example from spring which is here. in this example, configuration is done via bean. can anyone help me convert this configuration in to xml based configuration ?
#EnableWebMvc
#ComponentScan({ "org.eclipse.birt.spring.core","org.eclipse.birt.spring.example" })
#Configuration
public class BirtWebConfiguration extends WebMvcConfigurerAdapter {
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/reports").setViewName("birtView");
}
#Bean
public BirtView birtView() {
BirtView bv = new BirtView();
// bv.setReportFormatRequestParameter("ReportFormat");
// bv.setReportNameRequestParameter("ReportName");
bv.setBirtEngine(this.engine().getObject());
return bv;
}
#Bean
public BeanNameViewResolver beanNameResolver() {
BeanNameViewResolver br = new BeanNameViewResolver();
return br;
}
#Bean
protected BirtEngineFactory engine() {
BirtEngineFactory factory = new BirtEngineFactory();
return factory;
}
}
I wants a similar configuration in xml file.
There's really no tool for extracting Spring annotations to Spring bean context xml file. You'll have to do it by hand, shouldn't be too hard as all the Spring annotations functionality can be duplicated into Spring context xml tags.
if you want to use spingmvc, so no need the configuration files.
my solution is that in Birt Script i call the impl java file like this :
sampleService = new Packages.com.example.warlock.service.SampleServiceImpl();
pojo = new Packages.com.example.warlock.entity.Sample();
iterator = sampleService.getSamples().iterator();
because my SampleService is a interface and SampleServiceImpl is impl java, the two java file are not config as #Bean.
At first i want to get the data from ModelMap but failed, so i skip the controller and straight to call Service, then final call the DAO to get the Data from DB

Resources