I created a Spring project and I would like to create multiple queries on a single file. After googling, I found this link https://www.petrikainulainen.net/programming/spring-framework/spring-data-jpa-tutorial-creating-database-queries-with-named-queries/
So, I should create the file orm.xml:
<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings
xmlns="http://java.sun.com/xml/ns/persistence/orm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/xml/ns/persistence/orm_2_0.xsd"
version="2.0">
<named-query name="Todo.findByTitleIs">
<query>SELECT t FROM Todo t WHERE t.title = 'title'</query>
</named-query>
</entity-mappings>
Then, the interface TodoRepository.java
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.Repository;
import java.util.List;
interface TodoRepository extends Repository<Todo, Long> {
#Query(nativeQuery = true)
public List<Todo> findByTitleIs();
}
The spring.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="employeeDAO" class="com.journaldev.spring.jdbc.dao.EmployeeDAOImpl">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="employeeDAOJDBCTemplate" class="com.journaldev.spring.jdbc.dao.EmployeeDAOJDBCTemplateImpl">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="todoRepositoryBean" class="com.journaldev.spring.jdbc.dao.TodoRepositoryBeanImpl">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/springdb" />
<property name="username" value="root" />
<property name="password" value="root" />
</bean>
</beans>
The class SpringMain.java is:
public class SpringMain {
public static void main(String[] args)
{
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("spring.xml");
EmployeeDAO employeeDAO = ctx.getBean("todoRepositoryBean", EmployeeDAO.class);
List<Employee> les = employeeDAO.getAll();
System.out.println("The list size is: + les.size()");
ctx.close();
}
}
I think it was useful but I found a problem: How can I use the named query Todo.findByTitleIs on main class?
The tutorials of Petri Kainulainen are really good and you should achieve your goal by reading this one:
https://www.petrikainulainen.net/programming/spring-framework/spring-data-jpa-tutorial-part-eight-adding-functionality-to-a-repository/
He explaines how to implement the TodoRepository class.
To use queries defined in your repository, if you are developing a rest web app, you could use a #Controller class to handle the single functionalities (e.g. TodoController). In the controller you can autowire the repository:
#Autowired
private TodoRepository todoRepository;
and then use it in your methods:
public void doSomething() {
List<Todo> todoList = todoRepository.findByTitleIs();
}
Remember that you can autowire beans only in spring managed classes (Repository, Service, Controller, Component, Configuration ecc)
Otherwise you could get the repository directly from the ApplicationContext, but it's not recommended:
Why is Spring's ApplicationContext.getBean considered bad?
Personally i use this method only for testing purpose (to create a main test class).
Then i suggest you to write your queries directly in the repository interface, to me it's much simplier (this way you can avoid using the orm.xml file). For example:
#Repository
public interface TodoRepository extends JpaRepository<Todo, Long> {
// define your custom query
#Query("SELECT t FROM Todo t WHERE t.title = :title")
public List<Todo> findByTitleIs(#Param("title") String title);
// write here all the Todo queries
}
You can also use the query creation from method names mechanism, and write the previous query like this:
public List<Todo> findByTitle(String title);
http://docs.spring.io/spring-data/jpa/docs/1.4.3.RELEASE/reference/html/jpa.repositories.html
Related
Using Spring Framework, I want to create a bean object of type Person, and this bean object have a queue property of type Queue<Integer>, how to inject value to the property through XML?
The spring version is 4.3
The reference document is https://docs.spring.io/spring/docs/4.3.25.RELEASE/spring-framework-reference/htmlsingle/#beans-factory-class-ctor
but I can't find queue.
I try to use <bean> element, but the property queue of the bean is empty.
The Object is as follow
public class People {
private int id;
private Queue<Integer> queue;
// add constructor
// add get and set
}
The applicationContext.xml is as follow
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="..." class="...">
<property name="queue">
<bean class="java.util.ArrayDeque">
//How should I add values to the queue object
</bean>
</property>
</bean>
</beans>
By referring to Spring support on collection, the List, Set and Map interface can be injected by <list/>, <set/> and <map/> elements. The Queue interface is not supported. However, since ArrayDeque has a constructor for Collection, we can inject values from a List to ArrayDeque through <constructor-arg/> elements.
The following example demonstrates how to add value to the ArrayDeque.
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="people" class="spring.People">
<property name="queue">
<bean class="java.util.ArrayDeque">
<constructor-arg>
<list value-type="java.lang.Integer">
<value>1</value>
<value>2</value>
<value>3</value>
</list>
</constructor-arg>
</bean>
</property>
</bean>
</beans>
Main Class
package spring;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class InjectQueueApplication {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
People people = context.getBean("people", People.class);
System.out.println(people.getQueue().toString());
}
}
I use JPA + Hibernate + Spring for simple job.
I wrote next modules:
Service:
#Autowired
private VolMng volMng;
#Service
public class Dist {
#Transactional(readOnly = false, propagation = Propagation.REQUIRED)
public void gen() {
MeterLog mLog = em.find(MeterLog.class, 3625190);
Lst volTp = lstMng.findByCD("Fact Vol");
Vol vol = new Vol((MeterLog) mLog, volTp, 7777.77d);
volMng.add(vol);
//point-1:
for (Vol a : mLog.getVol()) {
System.out.println("found="+a.getId()+" vol="+a.getVol1());
}
...
...
Service:
#Service
public class VolMngImpl implements VolMng {
#Autowired
private VolDAO vDao;
public void add(Vol vol) {
vDao.add(vol);
}
}
DAO:
#Repository
public class VolDAOImpl implements VolDAO {
#PersistenceContext
private EntityManager em;
public void add(Vol vol) {
em.persist(vol);
}
}
I am trying to add some records to child entity Vol.
But after volMng.add(vol) at point-1 I don't see any added records (child entities).
Why?
upd
Of course I see these records after end of transaction, but why I can't do it before??? They must be in memory cache...
upd2
My spring.xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:cache="http://www.springframework.org/schema/cache"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-3.2.xsd">
<!-- *******************************
***** CACHE CONFIGURATION *****
******************************* -->
<cache:annotation-driven cache-manager="cacheManager" />
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
<property name="cacheManager" ref="ehcache"/>
</bean>
<bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation" value="classpath:ehcache.xml"/>
<property name="shared" value="true"/>
</bean>
<bean id="dataSource" class="oracle.jdbc.pool.OracleDataSource" destroy-method="close">
<property name="URL" value="jdbc:oracle:thin:#192.168.1.1:1521:DEV" />
<property name="user" value="ora"/>
<property name="password" value="ora"/>
<property name="connectionCachingEnabled" value="true"/>
</bean>
<bean
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
id="entityManagerFactory">
<property name="dataSource" ref="dataSource" />
</bean>
<context:component-scan base-package="com.ric.bill" />
<context:component-scan base-package="com.ric.bill.dao.impl" />
<context:component-scan base-package="com.ric.bill.mm.impl" />
<bean class="org.springframework.orm.jpa.JpaTransactionManager"
id="transactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:annotation-driven mode="proxy" transaction-manager="transactionManager"/>
<context:spring-configured />
<context:annotation-config />
</beans>
Collections are not automatically updated in the session.
It will appear once you reload everything, but you have to manually add it to the children collection of the owning object in case you need it in the current session.
To solve this problem I have to add children entity to the parent, like this:
MeterLog mLog = em.find(MeterLog.class, 3625190);
Lst volTp = lstMng.findByCD("Fact Vol");
Vol vol = new Vol((MeterLog) mLog, volTp, 7777.77d);
mLog.getVol().add(vol);
//point-1:
for (Vol a : mLog.getVol()) {
System.out.println("found="+a.getId()+" vol="+a.getVol1());
}
To answer the actual question -- why can't you see the newly added entity...
You run a select statement and put the results in a java object:
MeterLog mLog = em.find(MeterLog.class, 3625190);
The find ultimately creates the select statement and the result set is transformed into the MeterLog object via hibernate according to the jpa annotations you've used to define the mapping. From this point on your code doesn't change this object. You create a new entity with this code:
volMng.add(vol);
which directly persists the new entity in the database. But, this is after the select has already returned the data you asked for. You don't do anything to change or refresh the result set you've already acquired. The underlying datastore (oracle, mysql, whatever) doesn't remember that you've queried it and are holding a copy of its data, so it can do nothing to alert you to the fact that the underlying data has changed.
As you mention in your answer, you can add the new entity directly to the object's collection:
mLog.getVol().add(vol);
And this will, in certain circumstances, persist the new entity to the database when the transaction successfully completes, but also allows you to see the entity when you're looping through the collection, hence your observation. You have broken the law of Demeter by doing this here however -- it should be Vol's responsibility to add itself to the collection of volumes of the given MeterLog when it is created.
I am newbie in Spring and now I am trying to deal with #Value annotation. I have two classes. One has annotation:
public class RssHandler {
#Value("${theTopic}")
private String theTopic;
...
And the other one:
public class RestCallImpl implements RestCall {
#Value("${senderUrl}")
private String senderUrl;
...
My properties file is:
theTopic=mytopic
senderUrl=http://localhost:8080/
My beans xml has all things that I found here in the same issues like propertyConfigurer and beans declaration (as I understand):
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:feed="http://www.springframework.org/schema/integration/feed"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration
http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/feed
http://www.springframework.org/schema/integration/feed/spring-integration-feed.xsd">
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:application.properties</value>
<value>file:/Users/Projects/Java/TestNotifier/resources/application.properties</value>
</list>
</property>
<property name="ignoreUnresolvablePlaceholders" value="true"/>
<property name="ignoreResourceNotFound" value="true"/>
</bean>
<!-- RSS Stuff -->
<int:channel id="inputRssFeedChannel"/>
<feed:inbound-channel-adapter id="news"
channel="inputRssFeedChannel"
url="http://feeds.feedburner.com/Techcrunch">
<int:poller fixed-rate=5000 max-messages-per-poll=100/>
</feed:inbound-channel-adapter>
<int:service-activator input-channel="inputRssFeedChannel"
ref="rssPrintOutService"
method="printRss"/>
<bean id="rssPrintOutService" class="TestNotifier.RssHandler"/>
<bean id="SnsRestCall" class="TestNotifier.RestCallImpl"/>
</beans>
When I run my app I perfectly get "theTopic", but "senderUrl" is alway null. Why so? What did I miss? Thanks in advance!
Can you try #PropertySource annotation to your class as below
#Configuration
#PropertySource(value="classpath:application.properties")
public class RestCallImpl implements RestCall {
#Value("${senderUrl}")
private String senderUrl;
}
Try using the following :
public class RestCallImpl implements RestCall {
#Value("#{senderUrl}")
private String senderUrl;
...
Basically just changing the '$' to '#'.
I'm trying to run some tests for my controller but somehow the #Autowire annotation is not working.
Here is what I'm trying to do:
#WebAppConfiguration
#ContextConfiguration("/WEB-INF/spring/app-config.xml")
public class ClientsTest {
private Client client = new Cliente();
#Test
public void test() {
BindingResult result = mock(BindingResult.class);
ClientController clientController = new ClientController();
ModelAndView model = clientController.regClient(client, result);
Assert.assertEquals("success", model.getViewName());
}
}
#Controller
public class ClientController {
#Autowired private ClientService clientService;
#RequestMapping(value="/regClient.html", method = RequestMethod.POST)
public ModelAndView regClient(#ModelAttribute("client") #Valid Client client, BindingResult result){
ModelAndView model = new ModelAndView();
if(result.hasErrors())
{
model.setViewName("error");
}
else
{
model = clientService.regClient(client);
model.setViewName("success");
}
return model;
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- Scans the classpath of this application for #Components to deploy as beans -->
<context:component-scan base-package="com.app.app_v2.web" />
<!-- Configures the #Controller programming model -->
<mvc:annotation-driven conversion-service="conversionService"/>
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basenames">
<list>
<value>client</value>
</list>
</property>
</bean>
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="formatters">
<set>
<ref bean="clientFormatter"/>
</set>
</property>
</bean>
<bean id="clientFormatter" class="com.app.app_v2.spring.ClientFormatter"/>
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"></property>
<property name="prefix" value="/WEB-INF/views/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<bean id="clientService" class="com.app.app_v2.services.ClientService"/>
</beans>
As far as I know the clientService is null and this is why I'm getting the exception.
Because I don't know much about running test I'm asking for your help.
Your immediate problem about #Autowire not working is related to the fact that you're explicitly instantiating the clientController, and not through Spring framework. If you want the class to be a Spring bean you need to let the Spring framework manage its lifecycle, only than the dependency injection will kick-in, and all the spring beans annotated with #Autowire will be injected. Moreover, the test should be run with spring runner SpringJUnit4ClassRunner
Note that this is not necessary, cause with your test you can go two ways. More towards unit testing, by mocking your clientService e.g. via EasyMock or Mockito. Your currently posted test looks more geared towards that way. To learn how to complete your test take a look at this blog post
On the other hand, you can go for an integration test. Since version 3.2 Spring MVC offers test module which should really be the way to write integration test against Spring MVC. You can follow a great blog series backed with source code to learn how to do it.
I'm getting a null pointer when I try to access and use a SimpleJdbcDaoSupport. This is how I'm working it out:
In the main class
#Override
public void start(final Stage primaryStage) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("spring.xml");
SimpleJdbcDaoImpl dao = ctx.getBean("simpleJdbcDaoImpl", SimpleJdbcDaoImpl.class);
In some other stage controller class
public class HomeController implements Initializable {
#Autowired
private SimpleJdbcDaoImpl simpleJdbcDaoImpl;
// Initializes the controller class.
#Override
public void initialize(URL url, ResourceBundle rb) {
// Stage and the rest called
}
#FXML
public void showNewCalendarStage() throws Exception {
System.out.println(simpleJdbcDaoImpl.getCircleCount());
}
The SimpleJdbcDaoSupport class
import org.springframework.jdbc.core.simple.SimpleJdbcDaoSupport;
public class SimpleJdbcDaoImpl extends SimpleJdbcDaoSupport {
public int getCircleCount() {
String sql = "SELECT COUNT(*) FROM KIWI_TABLE";
return this.getJdbcTemplate().queryForInt(sql);
}
}
The spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.h2.Driver"/>
<property name="url" value="jdbc:h2:file:C:/WAKILI/WAKILIdb"/>
<property name="username" value="sa"/>
<property name="password" value=""/>
</bean>
<bean id="simpleJdbcDaoImpl" class="wakiliproject.dao.SimpleJdbcDaoImpl">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="configLocation">
<value>
classpath:/hibernate.cfg.xml
</value>
</property>
<property name="hibernateProperties">
<props>
<prop key="dialect">org.hibernate.dialect.H2Dialect</prop>
</props>
</property>
</bean>
<context:annotation-config/>
<context:component-scan base-package="wakiliproject"/>
</beans>
The error:
Caused by: java.lang.NullPointerException
at HomeController.showNewCalendarStage(HomeController.java:283)
... 42 more
I'm trying to teach myself Spring and would like to, for example, populate a Label in another Controller class (other than the main class) with text retrieved from the database.
For simplicity, in this case, lets print some text from the database to the console. What am I doing wrong with the above code? Thank you all.
In order for a Spring bean to be injected with its collaborators, it has to be managed by Spring. The HomeController is actually managed by FXML, which knows nothing about Spring annotations (#Autowired) and will ignore them. Even worse, assuming that the HomeController is under the wakiliproject package (or one of its subpackages), Spring will indeed create another instance of the HomeController that will have the #Autowired stuff injected but NOT the #FXML stuff.
Depending on how you load the controller you may be able to set the instance of the HomeController retrieved from Spring as the controller of the .fxml view. So:
Make sure Spring actually sees the HomeController (this will give you an instance of HomeController with the #Autowired stuff injected).
Load the FXML document as:
HomeController homeController = springContext.getBean(HomeController.class);
FXMLLoader fxmlLoader = new FXMLLoader(xxx.getResource("HomeController.fxml"));
fxmlLoader.setController(homeController);
try {
fxmlLoader.load();
} catch...
The above is almost pseudo-code, adapt as necessary!
If the load() is successful, the the #FXML fields of the controller will be populated too and its initialization method will be called.
Check out the VERY helpful answer to this question.