Weblogic jndi NameNotFoundException occur with java config - spring

I been searching again for this issue where I cannot locate the jndi database by using java config. Before this I use xml and its work perfectly but in java config it cause an issue;
Xml code:
<!-- Jndi database connection -->
<jee:jndi-lookup id="dbDataSource" jndi-name="${db.jndi}"
resource-ref="true" />
<beans:bean id="jdbcTemplate"
class="org.springframework.jdbc.core.JdbcTemplate" >
<beans:property name="dataSource" ref="dbDataSource"></beans:property>
</beans:bean>
Java config now:
#Bean(name = "dbDataSource")
public DataSource dataSource(#Value("${db.jndi}") String jndiName)
{
JndiDataSourceLookup lookup = new JndiDataSourceLookup();
return lookup.getDataSource(jndiName);
}
#Bean
public JdbcTemplate jdbcTemplate(DataSource ds) {
return new JdbcTemplate(ds);
}
Properties file:
db.jndi=jndi/myData
JNDI name in weblogic:
jndi/myData
After change to java config, sometimes the system can read the database but rarely occur, until I clean and restart my computer then it can find the database, but usually its always trigger:
javax.naming.NameNotFoundException: Unable to resolve 'jndi.myData'. Resolved 'jndi'; remaining name 'myData'
Why the application cannot find the database correctly?
Thanks!!!

I've had the same issue. If you're using 4.x version of spring that's probably the cause.
You should also check Weblogic's JNDI Tree. If your data source disapears from the tree after rebuilding the project, that's another symptom
If that's the case, what's happening is:
Your Datasource implements Closeable (and therefore AutoCloseable) and the context will always invoke the shutdown method regardless of your Bean definition
as seen here : SPR-12551: Document how to prevent a JNDI DataSource retrieved using JavaConfig to be removed on shutdown of the context
It's been marked as a documentation issue as this is the "expected" behaviour:
This issue was solely about documentation since we decided not to implement anything at the framework level
the solution, is to define the destroy method of the bean as empty, such as:
#Bean(name = "dbDataSource", destroyMethod="")
public DataSource dataSource(#Value("${db.jndi}") String jndiName)
{
JndiDataSourceLookup lookup = new JndiDataSourceLookup();
return lookup.getDataSource(jndiName);
}
#Bean
public JdbcTemplate jdbcTemplate(DataSource ds) {
return new JdbcTemplate(ds);
}
This is described in this issue (SPR-13022:Destroy callback cannot be disabled for AutoCloseable beans) .
PS: By the way, it seems like on early 4.x version of spring you couldn't override this behaviour by assingning destroyMethod. It apears that this bug was fixed on version 4.2 RC1.

I've had the same issue and I solved problem. I used to jndi datasource on weblogic. After I restart application, I notice my jndi datasource remove from Weblogic's JNDI Tree. Xml configuration works successfuly but java configuration don't work.
My old spring version: 4.1.6.RELEASE Upgrade to 4.3.9.RELEASE
Xml configuration like this;
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>${db-jndi.name}</value>
</property>
</bean>
Java configuration like this;
#Bean(name = "dataSource")
public DataSource dataSource() throws IllegalArgumentException, NamingException
{
JndiTemplate jndiTemplate = new JndiTemplate();
DataSource dataSource = (DataSource) jndiTemplate.lookup(env.getProperty("db-jndi.name"));
logger.info("DataSource initialized in jndi ");
return dataSource;
}
Then i changed
#Bean(name = "dataSource")
to
#Bean(name = "dataSource", destroyMethod = "")
And it's works successfuly.

It looks like your datasource hasn't been deployed. You should look for JNDI tree for the server you tried to deploy datasource. (https://docs.oracle.com/cd/E12839_01/apirefs.1111/e13952/taskhelp/jndi/ViewObjectsInTheJNDITree.html) If you don't see "jndi.myData" on JNDI tree, you can assume that your datasource haven't been deployed. So you can go to your datasource monitoring tab and test the datasource. (https://docs.oracle.com/cd/E17904_01/apirefs.1111/e13952/taskhelp/jdbc/jdbc_datasources/TestDataSources.html)

Related

Add Spring Boot to existing hibernate - embedded derby application

I already have an existing application with hibernate and embedded derby working.
My hibernate.cfg.xml has the following settings
<property name="connection.driver_class">org.apache.derby.jdbc.EmbeddedDriver</property>
<property name="connection.url">jdbc:derby:data;create=true</property>
<property name="connection.username">application</property>
<property name="connection.password">password</property>
<property name="hibernate.default_schema">my_application</property>
everything has been working fine but I wish to add spring boot to that project and I am getting
Failed to create sessionFactory
object.org.hibernate.service.spi.ServiceException: Unable to create
requested service [org.hibernate.engine.jdbc.env.spi.JdbcEnvironment]
when I am loading the sessionFactory from hibernate. Why can I not do that? Is loading embedded Derby from spring boot the only way? I don't want spring boot to have any relation to the database.
Also, after adding spring boot my log4j.properties file is not read anymore even if I do not run spring boot at all.
Found it. needed to set application.properties like this
spring.jpa.show-sql=true spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.DerbyDialect
spring.datasource.url=jdbc:derby:data;create=true
spring.datasource.username=application
spring.datasource.password=password
spring.datasource.driver-class-name=org.apache.derby.jdbc.EmbeddedDriver
spring.datasource.initialize=true
spring.jpa.properties.hibernate.current_session_context_class=org.springframework.orm.hibernate4.SpringSessionContext
my boot app needs a hibernate bean like this
#SpringBootApplication
#EntityScan("core.peristence.dtos")
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
#Bean
public HibernateJpaSessionFactoryBean sessionFactory() {
return new HibernateJpaSessionFactoryBean();
}
}
and my service can autowire the sessionFactory now like this:
#Service
public class MyService {
#Autowired
private SessionFactory sessionFactory;
...
}

Spring 4 (no boot) with custom jackson ObjectMapper

Secton 65.3 of the spring boot manual indicates that I can replace the default ObjectMapper by providing my own. I am not using boot, just a spring WebMVC application that builds to a .war and runs in tomcat.
It instantiates my ObjectMapper but doesn't use it. I used the debugger to trace through why timestamps still come out as numeric and found that it was using a different instance of ObjectMapper. It's not clear to me where it came from, or why this doesn't cause it to only use mine:
#Primary
#Bean
public ObjectMapper localObjectMapper() {
JodaMapper mapper = new JodaMapper();
mapper.setWriteDatesAsTimestamps(false);
mapper.getSerializationConfig().with(SerializationFeature.INDENT_OUTPUT)
.without(SerializationFeature.WRITE_DURATIONS_AS_TIMESTAMPS)
.without(SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS)
.without(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
return mapper;
}
The above is in a #Configure bean that's definitely getting loaded.
The approach I took above worked fine in Spring 3, just not when I ugpraded to 4.2.2. I have read Jackson Integration Improvements as well, and tried approaches listed there, to the same effect.
--Chris
The way I always did it was:
#Configuration
#EnableWebMvc
public class MyWebMvcConfigurer extends WebMvcConfigurerAdapter {
#Bean
public ObjectMapper localObjectMapper() {
JodaMapper mapper = new JodaMapper();
// ...
return mapper;
}
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(new MappingJackson2HttpMessageConverter (localObjectMapper())); // use your own ObjectMapper
}
}
One warning, to quote the JavaDoc of WebMvcConfigurer.html#configureMessageConverters:
Note that adding converters to the list, turns off default converter registration. To simply add a converter without impacting default registration, consider using the method extendMessageConverters(java.util.List) instead.
In Spring 4 I've solved with the following xml-configuration
<bean name="jacksonObjectMapper"
class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
<property name="featuresToDisable">
<array>
<util:constant
static-field="com.fasterxml.jackson.databind.SerializationFeature.WRITE_DATES_AS_TIMESTAMPS" />
</array>
</property>
</bean>
<mvc:annotation-driven>
<mvc:message-converters register-defaults="true">
<bean
class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper" ref="jacksonObjectMapper" />
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
putting it in the Servlet configuration file, usually under
/WEB-INF/spring/appServlet/*.xml

Database connections not being closed with jpaFlowExecutionListener

I'm using Spring Web Flow to build an application. I am making use of the Flow Managed Persistence Context so the entity manager is 'kept open' during the execution of my flow and I can access lazy loaded properties (similar to OpenEntityManagerInViewFilter or OpenSessionInViewFilter for Spring MVC). When I use this, every time I submit a form, the number of active database connections increases, if I don't use the FMPC, I have no problems with the number of open connections).
I'm working with the following setup.
TransactionManager:
#Bean
#Autowired
public JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
return new JpaTransactionManager(entityManagerFactory);
}
DataSource:
#Bean
public DataSource dataSource() {
final BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName(environment.getRequiredProperty(PROPERTY_DATABASE_DRIVER));
dataSource.setUrl(environment.getRequiredProperty(PROPERTY_DATABASE_URL));
dataSource.setUsername(environment.getProperty(PROPERTY_DATABASE_USERNAME, ""));
dataSource.setPassword(environment.getProperty(PROPERTY_DATABASE_PASSWORD, ""));
return dataSource;
}
EntityManagerFactory:
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
final LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
factoryBean.setDataSource(dataSource());
factoryBean.setPackagesToScan(environment.getRequiredProperty(PROPERTY_ENTITYMANAGER_PACKAGES_TO_SCAN));
final JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter() {
{
setDatabase(Database.valueOf(environment.getRequiredProperty(PROPERTY_DATABASE_TYPE)));
setDatabasePlatform(environment.getRequiredProperty(PROPERTY_HIBERNATE_DIALECT));
}
};
factoryBean.setJpaVendorAdapter(vendorAdapter);
final Properties jpaProperties = new Properties();
jpaProperties.put(PROPERTY_HIBERNATE_FORMAT_SQL, environment.getRequiredProperty(PROPERTY_HIBERNATE_FORMAT_SQL));
jpaProperties.put(PROPERTY_HIBERNATE_NAMING_STRATEGY, environment.getRequiredProperty(PROPERTY_HIBERNATE_NAMING_STRATEGY));
jpaProperties.put(PROPERTY_HIBERNATE_SHOW_SQL, environment.getRequiredProperty(PROPERTY_HIBERNATE_SHOW_SQL));
jpaProperties.put(PROPERTY_HIBERNATE_HB2DDL_SQL, environment.getRequiredProperty(PROPERTY_HIBERNATE_HB2DDL_SQL));
factoryBean.setJpaProperties(jpaProperties);
return factoryBean;
}
JpaFlowExecutionListener:
#Bean
#Autowired
public JpaFlowExecutionListener jpaFlowExecutionListener(EntityManagerFactory entityManagerFactory, JpaTransactionManager transactionManager) {
return new JpaFlowExecutionListener(entityManagerFactory, transactionManager);
}
The BasicDataSource has maxActive set to 8 by default and when I reach 8 active connections, the page just hangs. Why are the connections not being closed after the request is complete? I have used the Chrome debugging tools (the network pane) to make sure there are not AJAX requests running or anything, my page submit (an HTTP POST) triggers a 301 redirect which then gives me a new HTTP GET and that results in a status 200, so all good.
When going from one page to the next, a service layer is called but as you can see from my beans, I am using the JpaTransactionManager and the SWF documentation says the following:
Note: All data access except for the final commit will, by default, be non-transactional. However, a flow may call into a transactional service layer to fetch objects during the conversation in the context of a read-only system transaction if the underlying JPA Transaction Manager supports this. Spring's JPA TransactionManager does support this when working with a Hibernate JPA provider, for example. In that case, Spring will handle setting the FlushMode to MANUAL to ensure any in-progress changes to managed persistent entities are not flushed, while reads of new objects occur transactionally.
For the sake of completeness, my spring-web-flow config:
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:webflow="http://www.springframework.org/schema/webflow-config"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/webflow-config
http://www.springframework.org/schema/webflow-config/spring-webflow-config.xsd">
<!-- Flow executor, repsonsible for creating and executing flows -->
<webflow:flow-executor id="flowExecutor" flow-registry="flowRegistry">
<webflow:flow-execution-listeners>
<webflow:listener ref="jpaFlowExecutionListener"/>
</webflow:flow-execution-listeners>
</webflow:flow-executor>
<!-- Flow registry, responsible for loading all flows so executor can execute them -->
<webflow:flow-registry id="flowRegistry" base-path="/WEB-INF/webflow/flows" flow-builder-services="flowBuilderServices">
<webflow:flow-location-pattern value="/**/*-flow.xml"/>
</webflow:flow-registry>
<!-- Flow builder services -->
<webflow:flow-builder-services id="flowBuilderServices" view-factory-creator="mvcViewFactoryCreator"/>
<!-- MvcViewFactoryCreator -->
<bean id="mvcViewFactoryCreator" class="org.springframework.webflow.mvc.builder.MvcViewFactoryCreator">
<property name="viewResolvers">
<list>
<ref bean="viewResolver"/>
</list>
</property>
</bean>
<!-- Flow handler adapter, responsible for answering request for a flow -->
<bean class="org.springframework.webflow.mvc.servlet.FlowHandlerAdapter">
<property name="flowExecutor" ref="flowExecutor"/>
</bean>
<!-- Flow handler mapping, lets Spring MVCs DispatcherServlet know to send flow request to SWF -->
<bean class="org.springframework.webflow.mvc.servlet.FlowHandlerMapping">
<property name="flowRegistry" ref="flowRegistry"/>
<property name="order" value="0"/>
<property name="interceptors">
<list>
<ref bean="localeChangeInterceptor" />
</list>
</property>
</bean>
</beans>
My flow has <persistence-context /> defined at the top.
I have the following end-state (which restarts the flow), even when I invoke this and the URL params change to e2s1, the number of active connections is not reset:
<end-state id="restart" commit="true" view="redirect:/main"/>
So it seems that the default hibernate property for hibernate.connection.release_mode is on_close. Considering the EntityManager is kept open during the whole flow, it never closes and a new connection is fetched from the pool for every request within the flow.
Changing the property to after_transaction solves this issue. However, in the case of fetching lazily loaded collections, it still doesn't work, each lazy property will fetch a new connection from the pool. In order to solve this I extended the JpaFlowExecutionListener with this:
public class AvoidLeakJpaFlowExecutionListener extends JpaFlowExecutionListener {
public AvoidLeakJpaFlowExecutionListener(EntityManagerFactory entityManagerFactory, PlatformTransactionManager transactionManager) {
super(entityManagerFactory, transactionManager);
}
#Override
public void paused(RequestContext context) {
super.paused(context);
EntityManager entityManager = (EntityManager) context.getFlowScope().get(PERSISTENCE_CONTEXT_ATTRIBUTE);
if (entityManager != null && entityManager instanceof HibernateEntityManager) {
HibernateEntityManager hibernateEntityManager = (HibernateEntityManager) entityManager;
hibernateEntityManager.getSession().disconnect();
}
}
}
This approach solves the lazily loaded collections problem but will still leak connections when loading of lazy-initialized entities is done using WebFlow's persistence context and this loading is performed during the transition to subflow that does not have configured. as described in in this bug report (where I found this solution as well).

How to store static field?

In a redis java client,I found this:
To use it, init a pool:
JedisPool pool = new JedisPool(new JedisPoolConfig(), "localhost");
You can store the pool somewhere statically, it is thread-safe.
I just wondering,with spring,how can I store JedisPool statically.
You don't.
In spring it's preferable to define a JedisPool bean and autowire it wherever necessary.
For example, using xml config:
<bean id="jedisPool" class="redis.clients.jedis.JedisPool">
<constructor-arg>
<bean class="redis.clients.jedis.JedisPoolConfig" />
</consrtuctor-arg>
<constructor-arg value="localhost" />
</bean>
and then, inside your beans:
#Autowire
JedisPool jedisPool;
It's even simpler if you use spring java config - you can use exactly the code you posted to define the pool bean:
#Configuration
public class Configuration {
#Bean
public JedisPool createJedisPool() {
return new JedisPool(new JedisPoolConfig(), "localhost");
}
}
Also you might want to take a look at spring-data - redis

Another question on Spring 3, servlet, #autowired

I think I've read every question and answer on Spring and autowiring a servlet, both here and at springsource.org, and I still can't get it working.
All I want to do is have the datasource automatically set in my servlets. I understand that the container creates the servlet and not Spring.
Here is code from my test servlet:
package mypackage.servlets;
imports go here...
#Service
public class TestServlet extends HttpServlet
{
private JdbcTemplate _jt;
#Autowired
public void setDataSource(DataSource dataSource)
{
_jt = new JdbcTemplate(dataSource);
}
etc etc
In my applicationContext.xml I have:
<context:annotation-config />
<context:component-scan base-package="mypackage.servlets />
<import resource="datasource.xml" />
and in my datasource.xml:
<jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/db" />
If I can't get this working I'll just use WebApplicationContextUtils in the servlet's init method but I'd really like to make this work after all the reading I've been doing.
I'm using Spring 3, Java 1.6.
Thanks,
Paul
You need to replace your Servlets by Spring MVC contollers. Because Spring will not inject anything the classes (servlets) created by someone else then Spring itselfe (except #Configurable).
(To get an very simple example, take a look at the STS Spring Template Project: MVC).
What I wanted to do was get a DataSource reference in my Servlet for free, i.e. not calling a static getDatasource method on some class.
Here's what I learned and how I got it working:
Servlets cannot be configured or autowired by Spring. Servlets are created before Spring's app context is loaded. See issue SPR-7801: https://jira.springsource.org/browse/SPR-7801
What I did was create a DataSource in my applicationContext.xml and export that as a property:
<jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/db" />
<bean class="org.springframework.web.context.support.ServletContextAttributeExporter">
<property name="attributes">
<map>
<entry key="myDatasource">
<ref bean="dataSource"/>
</entry>
</map>
</property>
</bean>
In my servlet's init method I read the property:
public void init(ServletConfig config)
{
Object obj = config.getServletContext().getAttribute("myDatasource");
setDataSource((DataSource)obj);
}
public void setDataSource(DataSource datasource)
{
// do something here with datasource, like
// store it or make a JdbcTemplate out of it
}
If I'd been using DAOs instead of hitting the database from the servlets it would have been easy to wire them up for #Autowired by marking them #Configurable, and also be able to use #Transactional and other Spring goodies.

Resources