Setting SimpleJdbcTemplate for Servlet - java

I am new to Spring and I am working on CAS. I need to query a database for user authentication but I am using a servlet as a controller. Therefore I need to know if there is any way to set up a SimpleJdbcTemplate in that servlet and use it to query the data base. If there is how to configure the web.xml file or any other file.
Thank you already.

It is not a good Idea to inject or access JdbcTemplate directly into a Servlet or a Controller.
You can have a DAO layer in between and inject your JdbcTemplate in you DAO would be a better approach.
In order to use a JdbcTemplate you need to have a DataSource defined somewhere in your configuration (Spring context either through xml or Annotations).
If you have a UserDao, then your spring configuration would be as follows
<bean class="com.xxx.dao.UserDAOImpl" id="userDAO">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>
<bean class="org.springframework.jdbc.core.JdbcTemplate" id="jdbcTemplate">
<constructor-arg ref="dataSource"/>
</bean>
and here you need to difine your "dataSource" there are multiple ways to configure it, You may get better help from google.
And now, your UserDaoImpl looks a like
public class UserDAOImpl implements UserDAO {
private JdbcTemplate jdbcTemplate;
//setter and getter for jdbcTemplate
public List<Map<String, Object>> getUsers() {
String query = "select * from user";
return jdbcTemplate.queryForList(query, new HashMap<String, String>());
}
}
In your Servlet, you need to get the reference of this Dao using a ServiceLocator
in servlet class
...
public UserDAO getUserDao() {
return ServiceLocator.getBean(UserDAO.class);
}
...
Again there are multiple ways to design the ServiceLocator, Here is the simple implementation.
public class ServiceLocator implements ApplicationContextAware {
private static ApplicationContext applicationContext;
/**
* #return Returns the applicationContext.
*/
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
public static <T> T getBean(Class<T> requiredType) throws BeansException {
return getApplicationContext().getBean(requiredType);
}
/**
* #param applicationContext The applicationContext to set.
*/
public void setApplicationContext(ApplicationContext applicationContext) {
ServiceLocator.applicationContext = applicationContext;
}
}
Finally, all these pieces are independent, You need to read upon individually, You will get much and precise help on google or Spring forums.

Related

Changing the value of an #Bean at runtime in Java Spring Boot

In Java with Spring Boot framework there is an #Bean named DataSource that is used to make connections to a database, and is used by another #Bean called JdbcTemplate that serves to perform actions on the database. But, there is a problem, this #Bean DataSource, which serves to make the connection to the database, requires the properties for the connection to be preconfigured (url, username and password). The #Bean DataSource needs to start with an "empty" or "default" value at project startup, and at runtime it changes this value. I want a certain Endpoint to execute the action of changing the value of #Bean, to be more exact. And with the change of the value of the #Bean DataSource the JdbcTemplate, consequently, will be able to perform actions in several database.
Some details:
I have already evaluated this issue of using multiple databases, and in my case, it will be necessary.
All databases to be connected have the same model.
I do not think I need to delete and create another #Bean DataSource at runtime, maybe just override the #Bean values ​​that the Spring Boot itself already creates automatically.
I have already made the #Bean DataSource start with an "empty" value by making a method with the #Bean annotation and that returns a DataSource object that is literally this code: DataSourceBuilder.build().create();.
My English is not very good so if it's not very understandable, sorry.
DataSource #Bean code:
#Bean
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
Main class:
#SpringBootApplication(scanBasePackages = "br.com.b2code")
#RequiredArgsConstructor(onConstructor = #__(#Autowired))
public class RunAdm extends SpringBootServletInitializer implements
CommandLineRunner {
public static final String URL_FRONTEND = "*";
/**
* Método main do módulo de Gestão.
*
* #param args argumentos de inicialização
* #throws Exception uma exception genérica
*/
public static void main(String[] args) throws Exception {
SpringApplication.run(RunAdm.class, args);
}
#Override
protected SpringApplicationBuilder
configure(SpringApplicationBuilder application) {
return application.sources(RunAdm.class);
}
#Override
public void run(String... args) throws Exception {
}
}
A class to exemplify how I use JdbcTemplate:
#Repository
#RequiredArgsConstructor(onConstructor = #__(#Autowired))
public class ClienteQueryRepositoryImpl implements ClienteQueryRepository {
private final #NonNull
JdbcTemplate jdbc;
#Override
public List<Cliente> findAll() {
return jdbc.query(ClienteQuerySQL.SELECT_ALL_CLIENTE_SQL, new ClienteRowMapper());
}
}
I think as a general approach you might consider a Proxy Design Pattern for the actual DataSource Implementation.
Let's suppose the DataSource is an interface that has getConnection method by user and password (other methods are not really important because this answer is theoretical):
interface DataSource {
Connection getConnection(String user, String password);
}
Now, in order to maintain many databases you might want to provide an implementation of the datasource which will act as a proxy for other datasources that will be created on the fly (upon the endpoint call as you say).
Here is an example:
public class MultiDBDatasource implements DataSource {
private DataSourcesRegistry registry;
public Connection getConnection(String user, String password) {
UserAndPassword userAndPassword = new UserAndPassword(user, password);
registry.get(userAndPassword);
}
}
#Component
class DataSourcesRegistry {
private Map<UserAndPassword, DataSource> map = ...
public DataSource get(UserAndPassword a) {
map.get(a);
}
public void addDataSource(UserAndPassword cred, DataSource ds) {
// add to Map
map.put(...)
}
}
#Controller
class InvocationEndPoint {
// injected by spring
private DataSourcesRegistry registry;
#PostMapping ...
public void addNewDB(params) {
DataSource ds = createDS(params); // not spring based
UserAndPassword cred = createCred(params);
registry.addDataSource(cred, ds);
}
}
A couple of notes:
You should "override" the bean of DataSource offered by spring - this can be done by defining your own bean with the same name in your own configuration that will take precedence over spring's definition.
Spring won't create Dynamic Data Source, they'll be created from the "invocation point" (controller in this case for brevity, in real life probably some service). in any case only Registry will be managed by spring, not the data sources.
Keep in mind that this approach is very high-level, in a real life you'll have to think about:
Connection Pooling
Metering
Transaction Support
Multithreaded Access
and many other things

Spring Java Configuration Overriding Beans

I have a problem with creating two beans of the same class but different qualifier name. Basically One bean is created with the annotations #Repository and the other one is creating inside #Configuration class.
This is the class that we wont two instances with different datasources:
#Repository ("someDao")
public class SomeDaoImpl implements SomeDao {
private NamedParameterJdbcTemplate jdbcTemplate;
#Autowired
public void setDataSource(DataSource dataSource) {
jdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
}
}
And then we have a service like this:
#Service
public class SomeServiceImpl implements
SomeService {
#Resource(name = "someDao")
private SomeDao someDao;
#Resource(name = "someDaoAnotherDataSource")
private SomeDao someDaoAnotherDataSource;
}
My first bean is created by the annotation #Repository and the other one I declared in a Spring Configuration class:
#Configuration
#ComponentScan(basePackages = "mypackages")
public abstract class ApplicationRootConfiguration {
#Bean(name = "otherDataSource")
public DataSource otherDataSource() throws NamingException {
...
}
#Bean(name = "someDaoAnotherDataSource")
public SomeDao getSomeDaoAnotherDataSource(#Qualifier("otherDataSource")
DataSource dataSource) throws NamingException {
SomeDao dao = new SomeDaoImpl();
dao.setDataSource(dataSource);
return dao;
}
}
If I run my application, the property someDaoAnotherDataSource in SomeServiceImpl doesn't have my bean declared in the configuration class, it have the bean declared with the annotation Repository.
Also, if I running the same example in XML configuration it works:
<bean id="someDaoAnotherDataSource" class="SomeDaoImpl">
<property name="dataSource" ref="otherDataSource" />
</bean>
Any idea why is not autowiring the proper bean?
Thanks in advance.
Just a thought, instead of injecting the datasource into the method try the following
#Bean(name = "someDaoAnotherDataSource")
public SomeDao getSomeDaoAnotherDataSource() throws NamingException {
SomeDao dao = new SomeDaoImpl();
dao.setDataSource(otherDataSource());
return dao;
}
Although both should work.
Make sure that the name is correct in your #Resource annotation and instead of (or next to) specifing the name of the bean in the #Bean annotation, rename your method to the same.
#Bean(name = "someDaoAnotherDataSource")
public SomeDao someDaoAnotherDataSource() throws NamingException {
SomeDao dao = new SomeDaoImpl();
dao.setDataSource(otherDataSource());
return dao;
}
The name is basically an alias whereas the method name is used as the id of the bean. Could be that resolving isn't looking at aliases correctly. The same in xml would be
<bean id="getSomeDaoAnotherDataSource" name="someDaoAnotherDataSource" class="SomeDaoImpl">
<property name="dataSource" ref="otherDataSource" />
</bean>

Retrieving property/value as string from Spring bean

I have the following in my context.xml:
<bean id="myBean" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>file:${specific.dir}/file1.properties</value>
<value>file:${specific.dir}/file2.properties</value>
<value>file:${specific.dir}/file3.properties</value>
<value>file:${specific.dir}/file4.properties</value>
</list>
</property>
</bean>
I am retrieving this bean in a POJO through a static spring application context, and going through the debugger this does seem to work.
Is there anyway for me to retrieve the four values in the list, and the property name in this POJO?
my staticSpringApplicationContext is as follows :
public class StaticSpringApplicationContext implements ApplicationContextAware {
private static ApplicationContext CONTEXT;
public void setApplicationContext(ApplicationContext context) throws BeansException {
CONTEXT = context;
}
public static Object getBean(String beanName) {
return CONTEXT.getBean(beanName);
}
}
and following this in my POJO I have:
StaticSpringApplicationContext.getBean("myBean");
Any help or guidance is greatly appreciated. I have had more trouble with Spring than I care to admit.
You can use spring #Value annotation, smth like this:
#Component
public MyClass {
#Value("${some.prop.name1}")
private String myProp1;
}
file1.properties:
some.prop.name1=value1
I hope it will be helpful. Good luck.
Whether you can do this will depend on the bean definition. It must have a setLocations() method (or be correctly annotated) via which Spring will inject the values.
You would retrieve the values using a getter method on the bean if one exists. If not you will need to modify the bean.

injecting ConversionService into a custom Converter

Using Spring mvc-3. I am writing a custom Converter which needs access to other Converters registered to a ConversionService.
How can I accomplish this? I tried writing my custom converter as:
class CustomConverter<X, Y>{
#Autowired ConversionService service;
//+getter & setters of service
public Y convert(X input){
// I need access to service to lookup simple conversions such as
// String array to Long array etc..
}
}
And I registered my custom converter via applicationContext.xml
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name = "converters">
<list>
<bean class="CustomConverter"/>
</list>
</property>
</bean>
However, spring refuses to inject service into my CustomConverter(its always null). How can I accomplish this?
Thank you!
I have come across same problem. There's an issue SPR-6415 in Spring JIRA covering this problem. I've giving here my solution based on discussion in this issue. It's the same principle like answer of #nmervaillie but you don't have to implement your own ConversionServiceFactoryBean.
/**
* Base class of #{code Converter} that need to use {#code ConversionService}.
* Instances of implementing classes must be spring-managed to inject ConversionService.
*
* #author Michal Kreuzman
*/
public abstract class CoversionServiceAwareConverter<S, T> implements Converter<S, T> {
#Inject
private ConversionService conversionService;
protected ConversionService conversionService() {
return conversionService;
}
/**
* Add this converter to {#code ConverterRegistry}.
*/
#SuppressWarnings("unused")
#PostConstruct
private void register() {
if (conversionService instanceof ConverterRegistry) {
((ConverterRegistry) conversionService).addConverter(this);
} else {
throw new IllegalStateException("Can't register Converter to ConverterRegistry");
}
}
}
#Component
public class SampleConverter extends CoversionServiceAwareConverter<Object, Object> {
#Override
public String convert(Object source) {
ConversionService conversionService = conversionService();
// Use conversionService and convert
}
}
I have used something like this recently to solve this problem.
Use a custom factory :
public class MyConversionServiceFactoryBean extends ConversionServiceFactoryBean {
#Override
public void afterPropertiesSet() {
super.afterPropertiesSet();
ConversionService conversionService = getObject();
ConverterRegistry registry = (ConverterRegistry) conversionService;
// register converters that need a nested conversion service
registry.addConverter(new MyCustomConverter(conversionService));
}
}
which is declared like this :
<bean id="conversionService"
class="com.company.MyConversionServiceFactoryBean">
<property name="converters">
<list>
... declare standard converters here ...
</list>
</property>
</bean>
I solved this problem in spring-ws centric application. The main components of this solutions are:
declaring Converter implementations as spring beans
using #Lazy from spring-context on the injection points in the converters
inject all discovered converters in a ConversionServiceFactoryBean
SampleConverter
#Component
public class SampleConverter implements Converter<Source, Target> {
private ConversionService conversionService;
#Inject
#Lazy
public SampleConverter(ConversionService conversionService){
this.conversionService = conversionService;
}
#Override
public Target convert(Source source){
Target target = new Target();
...
target.setTargetDetails(conversionService.convert(source.getSourceDetails, TargetDetails.class);
...
and the Configuration:
#Configuration
public class ConversionServiceConfig {
#Bean
public ConversionService conversionService(Set<Converter<?,?>> converters){
ConversionServiceFactoryBean csfb = new ConversionServiceFactoryBean();
csfb.setConverters(converters);
csfb.afterPropertiesSet();
return csfb.getObject();
}
...
The #Lazy annotations circumvents the egg-chicken problem by injecting a proxy and thus delaying the resolution of the conversionservice bean until it is really used.
Main problem (that i've encountered) is when you use ConversionServiceFactoryBean for building conversion service that includes converters that use conversion service as well is that you get error because of ConversionServiceFactoryBean.getObject method that provides instance of conversion service is being called prior to ConversionServiceFactoryBean.afterPropertiesSet where that conversion service instance is actually created.
So, to avoid this behavior, you just need to create conversion service prior to ConversionServiceFactoryBean.getObject is called. I've made it in constructor of class that extends ConversionServiceFactoryBean.
Example:
try {
Field serviceField = ConversionServiceFactoryBean.class.getDeclaredField("conversionService");
conversionServiceField.setAccessible(true);
conversionServiceField.set(this, createConversionService());
} catch (NoSuchFieldException | IllegalAccessException fieldAccessError) {
fieldAccessError.printStackTrace();
//or do some log output here, it's up to you
}
Than you can use converters that uses conversion service as well.
Hope it helps.

Spring JUnit4 manual-/auto-wiring dilemma

I ran into an issue that can only be explained with my fundamental lack of understanding of Spring's IoC container facilities and context setup, so I would ask for clarification regarding this.
Just for reference, an application I am maintaing has the following stack of technologies:
Java 1.6
Spring 2.5.6
RichFaces 3.3.1-GA UI
Spring framework is used for bean management with Spring JDBC module used for DAO support
Maven is used as build manager
JUnit 4.4 is now introduced as test engine
I am retroactively (sic!) writing JUnit tests for the application and what suprised me is that I wasn't able to inject a bean into a test class by using setter injection without resorting to #Autowire notation.
Let me provide set up an example and accompanying configuration files.
The test class TypeTest is really simple:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration
public class TypeTest {
#Autowired
private IType type;
#Test
public void testFindAllTypes() {
List<Type> result;
try {
result = type.findAlltTypes();
assertNotNull(result);
} catch (Exception e) {
e.printStackTrace();
fail("Exception caught with " + e.getMessage());
}
}
}
Its context is defined in TestStackOverflowExample-context.xml:
<context:property-placeholder location="classpath:testContext.properties" />
<context:annotation-config />
<tx:annotation-driven />
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="${db.connection.driver.class}" />
<property name="url" value="${db.connection.url}" />
<property name="username" value="${db.connection.username}" />
<property name="password" value="${db.connection.password}" />
</bean>
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="beanDAO" class="com.example.BeanDAOImpl">
<property name="ds" ref="dataSource"></property>
<property name="beanDAOTwo" ref="beanDAOTwo"></property>
</bean>
<bean id="beanDAOTwo" class="com.example.BeanDAOTwoImpl">
<property name="ds" ref="dataSource"></property>
</bean>
<bean id="type" class="com.example.TypeImpl">
<property name="beanDAO" ref="beanDAO"></property>
</bean>
TestContext.properties is in classpath and contains only db-specific data needed for datasource.
This works like a charm but my question is - why doesn't it work when I try to manually wire beans and perform setter injection as in:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration
public class TypeTest {
private IType type;
public IType getType () {
return type;
}
public void setType(IType type) {
this.type= type;
}
#Test
public void testFindAllTypes(){
//snip, snip...
}
}
What am I missing here? What part of configuration is wrong here? When I try to manually inject beans via setters, test fails because this part
result = type.findAlltTypes();
is resolved as null in runtime. I've, of course, consulted the Spring reference manual and tried various combinations of XML configuration; all I could conclude is that Spring was unable to inject beans because it somehow fails to properly dereference Spring Test Context reference but by using #Autowired this happens "automagically" and I really can't see why is that because JavaDoc of both Autowired annotation and its PostProcessor class doesn't mention this.
Also worth adding is the fact that #Autowired is used in application only here. Elsewhere only manual wiring is performed, so this also brings forth question - why is it working there and not here, in my test? What part of DI configuration am I missing? How does #Autowired get reference of Spring Context?
EDIT:
I've also tried this but with same results:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration
public class TypeTest implements ApplicationContextAware{
private IType type;
private ApplicationContext ctx;
public TypeTest(){
super();
ctx = new FileSystemXmlApplicationContext("/TypeTest-context.xml");
ctx.getBean("type");
}
public IType getType () {
return type;
}
public void setType(IType type) {
this.type= type;
}
#Test
public void testFindAllTypes(){
//snip, snip...
}
}
Any other ideas, perhaps?
EDIT2:
I've found a way without resorting to writing own TestContextListener or BeanPostProcessor. It is suprisingly simple and it turns out that I was on the right track with my last edit:
1) Constructor-based context resolving:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration
public class TypeTest{
private IType type;
private ApplicationContext ctx;
public TypeTest(){
super();
ctx = new FileSystemXmlApplicationContext("/TypeTest-context.xml");
type = ctx.getBean("type");
}
public IType getType () {
return type;
}
public void setType(IType type) {
this.type= type;
}
#Test
public void testFindAllTypes(){
//snip, snip...
}
}
2) By implementing ApplicationContextAware interface:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration
public class TypeTest implements ApplicationContextAware{
private IType type;
private ApplicationContext ctx;
public IType getType () {
return type;
}
public void setType(IType type) {
this.type= type;
}
#Override
public void setApplicationContext(ApplicationContext ctx) throws BeansException {
this.ctx = ctx;
type = (Type) ctx.getBean("type");
}
#Test
public void testFindAllTypes(){
//snip, snip...
}
}
Both of these approaches properly instanced beans.
If you take a look at the source of org.springframework.test.context.support.DependencyInjectionTestExecutionListener, you will see the following method (formatted and commented for clarity):
protected void injectDependencies(final TestContext testContext)
throws Exception {
Object bean = testContext.getTestInstance();
AutowireCapableBeanFactory beanFactory = testContext.getApplicationContext()
.getAutowireCapableBeanFactory();
beanFactory.autowireBeanProperties(bean,
AutowireCapableBeanFactory.AUTOWIRE_NO,
// no autowiring!!!!!!!!
false
);
beanFactory.initializeBean(bean, testContext.getTestClass().getName());
// but here, bean post processors are run
testContext.removeAttribute(REINJECT_DEPENDENCIES_ATTRIBUTE);
}
So the test object is a bean without auto-wiring. However, #AutoWired, #Resource etc, don't use the autowiring mechanism, they use BeanPostProcessor. And so the dependencies are injected if and only if the annotations are used (or if you register some other BeanPostProcessor that does it).
(The above code is from Spring 3.0.x, but I bet it was the same in 2.5.x)

Categories

Resources