I have a spring MVC (4.1.6) app, using Hibernate ORM (5.3.7) on top of a MySQL 8 Database.
I have a view with a form that should create a row in the DB when it is submitted, but it does not. I can tell the information gets to my #Service bean and DAO #Repository bean. I can also successfully query data from the DB and display it on a view, if I update the DB directly through SQL.
I have read a number of posts and tried to reconfigure my application context and servlet context XMLs with no luck. Can anyone tell me where I am going wrong?
Below are some snippets.
Web_XML
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring/applicationContext-dao.xml
/WEB-INF/spring/applicationContext-security.xml
</param-value>
</context-param>
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/applicationContext-web.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
applicationContext-web.xml
<context:component-scan base-package="edu.neu.snowfinder">
<context:include-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
</context:component-scan>
<interceptors>
<beans:bean class= "org.springframework.orm.hibernate4.support.OpenSessionInViewInterceptor">
<beans:property name="sessionFactory" ref="sessionFactory"/>
</beans:bean>
</interceptors>
applicationContext-dao.xml
<bean id="sessionFactory" class = "org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name = "dataSource" ref = "dataSource"/>
<property name = "configLocation">
<value> classpath:hibernate.cfg.xml</value>
</property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id = "transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref = "sessionFactory"/>
<property name="dataSource" ref = "dataSource"/>
</bean>
UserServiceImpl
#Service
public class UserServiceImpl implements UserService {
#Autowired
#Qualifier("userHibernateDAO")
private UserDAO userDAO;
#Override
#Transactional
public void createUser(User user) {
System.out.println("Does the Sevice have the user?"+user.getFirstname());
userDAO.createUser(user);
}
#Override
#Transactional
public Collection<User> listUsers() {
return userDAO.listUsers();
}
}
UserHibernateDAO
#Repository
public class UserHibernateDAO implements UserDAO {
#Autowired
private SessionFactory sessionFactory;
#Override
public void createUser(User user) {
Session session = sessionFactory.getCurrentSession();
session.beginTransaction();
System.out.println("Does the DAO have the user?"+user.getFirstname());
System.out.println("Does the DAO have a session?"+sessionFactory.getCurrentSession().toString());
Serializable id = sessionFactory.getCurrentSession().save(user);
session.getTransaction().commit();
System.out.println("Whats the saved User's ID??"+id.toString());
}
hibernate.cfg.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration SYSTEM
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name = "hibernate.dialect">org.hibernate.dialect.MySQL8Dialect</property>
<property name = "hibernate.showsql">true</property>
<property name = "hibernate.formatsql">true</property>
<property name = "hibernate.hbm2ddl.auto">create</property>
<mapping class = "edu.neu.snowfinder.model.User"/>
</session-factory>
</hibernate-configuration>
Related
I have a problem when I insert data in my MySQL database with Spring Data Jpa Module.
The problem is the following:
When I startup my Springapplication I create the database and initialize the data with SpringdataJPA and I see the data inserted in the table. Afterwards i wanna insert some data related to inserted data and only 1 of the 3 records inserted before were found. When i restard the server and i dont recreate the data and search for it with the same method every single record is found. I search for 2 weeks for a solution but didnt find anything. I hope you can help me.
NEWS
I think only in words is hard to understand, so I insert the code behind. jpa.xml with all spring jpa configuration. The 2 entities and the initmethods. hopefully you can find my error.
jpa.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:p="http://www.springframework.org/schema/p"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
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">
<context:property-placeholder location="classpath:properties/database/database.properties" />
<!-- Declare a datasource that has pooling capabilities-->
<!-- BoneCP configuration -->
<bean id="SoopDataSource" class="com.jolbox.bonecp.BoneCPDataSource" destroy-method="close" >
<property name="driverClass" value="${database.driver}" />
<property name="jdbcUrl" value="${database.url}" />
<property name="username" value="${database.user}"/>
<property name="password" value="${database.password}"/>
<property name="idleConnectionTestPeriod" value="60"/>
<property name="idleMaxAge" value="240"/>
<property name="maxConnectionsPerPartition" value="30"/>
<property name="minConnectionsPerPartition" value="5"/>
<property name="partitionCount" value="2"/>
<property name="acquireIncrement" value="5"/>
<!-- <property name="statementsCacheSize" value="100"/> -->
<!-- <property name="releaseHelperThreads" value="2"/> -->
</bean>
<!-- Declare a JPA entityManagerFactory-->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" >
<property name="persistenceUnitName" value="SoopDbProvider" />
<property name="dataSource" ref="SoopDataSource"/>
<property name="persistenceProviderClass" value="org.hibernate.ejb.HibernatePersistence"/>
<property name="jpaProperties">
<props>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.temp.use_jdbc_metadata_defaults">false</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLInnoDBDialect</prop>
<prop key="hibernate.hbm2ddl.auto">create</prop>
</props>
</property>
<property name="packagesToScan">
<list>
<value>com.soopproject.main.db</value>
</list>
</property>
</bean>
<!-- Db initialization bean -->
<bean id="databaseinit" class="com.soopproject.main.db.init.DatabaseInitialization" init-method="init"/>
<!-- Declare a transaction manager-->
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
Entities:
BaseEntityWithPrimary
#MappedSuperclass
#Data
#EqualsAndHashCode(callSuper = false)
public class SoopBaseEntityWithPrimary implements
Serializable {
#Id
#GeneratedValue
private long id;
}
Language:
#Entity
#Data
#EqualsAndHashCode(callSuper = true)
public class Language extends BaseEntityWithPrimary {
#Column(nullable = false, unique = true)
private String shortname;
#Column(nullable = false)
private String longname;
#ManyToMany(cascade = CascadeType.ALL)
private List<TranslationsShort> languageTranslationsShorts;
}
InitMethods
#Autowired
private UserRepository userrep;
#Autowired
private LanguageRepository langrep;
#Autowired
private ErrorCodesRepository errorrep;
private void initLanguage() {
User systemuser = null;
try {
systemuser = userrep.findUserByUsername("system");
} catch (Exception ex) {
DatabaseException exception = new DatabaseReadException(ex);
exception.writeLog();
}
List<Language> languages = new LinkedList<>();
Language deutsch = new Language();
deutsch.setCreateUser(systemuser);
deutsch.setShortname("DE");
deutsch.setLongname("Deutsch");
Language english = new Language();
english.setCreateUser(systemuser);
english.setShortname("EN");
english.setLongname("English");
Language italiano = new Language();
italiano.setCreateUser(systemuser);
italiano.setShortname("IT");
italiano.setLongname("Italiano");
languages.add(deutsch);
languages.add(italiano);
languages.add(english);
for (Language lang : languages) {
Language l_help = null;
try {
l_help = langrep.findLanguageByShortname(lang.getShortname());
} catch (Exception ex) {
DatabaseException exception = new DatabaseReadException(ex);
exception.writeLog();
}
if (l_help == null)
try {
langrep.saveAndFlush(lang);
} catch (Exception e) {
DatabaseException exception = new DatabaseWriteException(e);
exception.writeLog();
}
}
}
private void initErrorCodes() {
User systemuser = null;
Language de = null;
Language it = null;
Language en = null;
try {
systemuser = userrep.findUserByUsername("system");
} catch (Exception ex) {
DatabaseException exception = new DatabaseReadException(ex);
exception.writeLog();
}
try {
de = langrep.findLanguageByShortname("DE");
} catch (Exception ex) {
DatabaseException exception = new DatabaseReadException(ex);
exception.writeLog();
}
try {
it = langrep.findLanguageByShortname("IT");
} catch (Exception ex) {
DatabaseException exception = new DatabaseReadException(ex);
exception.writeLog();
}
try {
en = langrep.findLanguageByShortname("EN");
} catch (Exception ex) {
DatabaseException exception = new DatabaseReadException(ex);
exception.writeLog();
}
The problem is that after startup the springapplication and set <prop key="hibernate.hbm2ddl.auto">create</prop> in the method initErrorCodes only the line with it = langrep.findLanguageByShortname("IT"); finds the data in database. The other 2 calls return null (de = langrep.findLanguageByShortname("DE"); and en = langrep.findLanguageByShortname("EN");). Then i stop the application and look to the database and all data is inserted in the table Language. When i restart the server with <prop key="hibernate.hbm2ddl.auto">none</prop> then all 3 method calls return the data???!?!?! I dont get it. So for sure it's not a problem of the method call. But I cant find the error.
What do you mean by 1 of 3 were found? Are you querying the data, or accessing a relationship?
It sounds like some sort of caching is occurring. Some JPA providers enable caching by default, check you cache settings, and ensure you are maintaining bidirectional relationships correctly.
https://en.wikibooks.org/wiki/Java_Persistence/Caching
https://en.wikibooks.org/wiki/Java_Persistence/Relationships#Object_corruption.2C_one_side_of_the_relationship_is_not_updated_after_updating_the_other_side
I'm using Spring MVC 3 and MappingJacksonHttpMessageConverter in order to get the json data with #ResponseBody. With the default config works ok but now i need to transform the camelCase fields to Pascal casing. For this purpose, i've developed a custom naming strategy:
UpperCaseNamingStrategy.java
public class UpperCaseNamingStrategy extends PropertyNamingStrategy {
#Override
public String nameForField(MapperConfig config, AnnotatedField field, String defaultName){
return convert(defaultName);
}
#Override
public String nameForGetterMethod(MapperConfig config, AnnotatedMethod method, String defaultName){
return convert(defaultName);
}
#Override
public String nameForSetterMethod(MapperConfig config, AnnotatedMethod method, String defaultName){
return convert(defaultName);
}
public String convert(String defaultName){
char[] arr= defaultName.toCharArray();
if(arr.length != 0){
if(Character.isLowerCase(arr[0])){
arr[0] = Character.toUpperCase(arr[0]);
}
}
return new StringBuilder().append(arr).toString();
}
}
I set my custom strategy to the objectMapper and i set the objectMapper in the converter. These are the beans:
<bean id="jacksonMessageConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
<property name="objectMapper" ref="jacksonObjectMapper" />
</bean>
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<ref bean="jacksonMessageConverter"/>
</list>
</property>
</bean>
<bean id="jacksonObjectMapper" class="org.codehaus.jackson.map.ObjectMapper">
<property name="propertyNamingStrategy" ref="namingStrategy"/>
</bean>
<bean id="namingStrategy" class="es.unican.meteo.util.UpperCaseNamingStrategy"></bean>
The beans are registered properly because i can see it in the log but when i request the json data the behaviour is the same and the converter method is not called. Do I need more configs?
Following changes are suggested as compared to what I did in my project:
Change mapper bean class to "com.fasterxml.jackson.databind.ObjectMapper". I am using Spring 4.3
add #JsonProperty annotation to the property of class which is being serielized/deseralized
Create default constructors in class which is being serielized/deseralized
Best of Luck!
I built an example project for hibernate search and it works fine without any exception but when I search a string that I have some objects with that string, it returns empty. I don't know what should I do!!! Can somebody help me...
Project is maven based and I use hibernate annotation both for hibernate and hibernate search.
Here is my hibernate.cfg.xml file:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">
jdbc:mysql://localhost:3306/eprnews
</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">***</property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="hibernate.show_sql">true</property>
<property name="hibernate.bytecode.use_reflection_optimizer">false</property>
<!--
<property name="hibernate.hbm2ddl.auto">create-drop</property>
Hibernate Search -->
<!-- org.hibernate.search.store.FSDirectoryProvider -->
<!-- org.hibernate.search.store.RAMDirectoryProvider for test -->
<!--
<property name="hibernate.search.default.directory_provider">org.hibernate.search.store.FSDirectoryProvider</property>
-->
<property name="hibernate.search.default.directory_provider">filesystem</property>
<property name="hibernate.search.default.indexBase">./indexes</property>
<!--
-->
<property name="hibernate.search.worker.execution">async</property>
<property name="hibernate.search.default.optimizer.transaction_limit.max">100</property>
<!-- Mapped classes -->
<mapping class="net.leemoo.test.entity.NewsEntity"/>
</session-factory>
</hibernate-configuration>
and here is my entity:
#Entity
#Table(name="news")
#Indexed
#AnalyzerDef(
name = "PersianAnal",
charFilters = #CharFilterDef(factory = PersianCharFilterFactory.class),
tokenizer = #TokenizerDef(factory = StandardTokenizerFactory.class),
filters={
#TokenFilterDef(factory = ArabicNormalizationFilterFactory.class),
#TokenFilterDef(factory = PersianNormalizationFilterFactory.class)
}
)
public class NewsEntity {
#Id
#GeneratedValue
private Long id;
#Field
#Analyzer(definition="PersianAnal")
private String title;
#Field
#Analyzer(definition="PersianAnal")
private String newsAbstract;
#Field(index=Index.YES, analyze=Analyze.YES, store=Store.NO)
#Analyzer(definition="PersianAnal")
private String content;
#Field(index=Index.YES, analyze=Analyze.YES, store=Store.NO)
#DateBridge(resolution=Resolution.DAY)
private Date creationDate;
#Field(index=Index.YES, analyze=Analyze.YES, store=Store.NO)
#DateBridge(resolution=Resolution.DAY)
private Date modifiedDate;
private Integer viewsCounter;
#Field
#Analyzer(definition="PersianAnal")
private String keywords;
private Boolean jqueryNews;
private Boolean photoNews;
and setters and getters...
and this is the code that i use for searching:
Session session = HibernateUtil.getSessionFactory().openSession();
session.beginTransaction();
FullTextSession fullTextSession = Search.getFullTextSession(session);
try {
// fullTextSession.createIndexer().startAndWait();
QueryBuilder gb = fullTextSession.getSearchFactory().buildQueryBuilder().forEntity(NewsEntity.class).get();
Query query = gb.keyword().
onFields("title", "newsAbstract", "content").
matching("test").createQuery();
org.hibernate.Query hibQuery = fullTextSession.createFullTextQuery(query, NewsEntity.class);
List<NewsEntity> result = (List<NewsEntity>)hibQuery.list();
System.out.println(result.size());
} catch (Exception e) {
// e.printStackTrace();
}
session.getTransaction().commit();
session.close();
What should I do? Please help me....
I think I made a silly mistake in that I commented my index creator in last code phrase. I should run it once in the beginning for indexes to be created. I'm sorry again that I took your time.
I would know how works the configuration about Spring MVC rest services that returns JSON.
I have configurated the applicationContenxt.xml in this way:
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"/>
</list>
</property>
</bean>
<bean id="contentNegotiatingViewResolver" class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="mediaTypes">
<map>
<entry key="json" value="application/json"/>
</map>
</property>
<property name="defaultViews">
<list>
<bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView"/>
</list>
</property>
</bean>
<bean class="com.MyController"></bean>
And this is the code of my controller:
#Controller(value="MyController")
public class MyController {
#RequestMapping(value="/getValue", method=RequestMethod.GET)
public ModelAndView getValue() {
Map model = new HashMap();
model.put("asasa", "bbbbb");
model.put("cccc", "ddddd");
return new ModelAndView("jsonView",model);
}
}
I'm missing something about xml configuration or Java code? I have always error 404 while trying to invoke this resource: http://localhost:8080/fss/MyController/getValue
Just do:
#Controller
public class HelloController {
#RequestMapping(value="/hello", method=RequestMethod.GET)
public #ResponseBody String hello(#RequestParam String name) {
return "Hi " + name;
}
}
Change the return type to an object and include jackson in the classpath for an object response.
The request need to have a application/json header for the controller to return json.
Check out http://blog.springsource.com/2010/01/25/ajax-simplifications-in-spring-3-0/
And don't forget to add jackson converter to Spring context file.
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"></bean>
</mvc:message-converters>
</mvc:annotation-driven>
By the way - if your method accepts JSON, then use #RequestBody annotation with incoming data type:
#RequestMapping
public #ResponseBody OutgoingClass getJsonByJson(#RequestBody IncomingClass data) {...}
You can find nice examples of JSON and Spring MVC and more https://sites.google.com/site/upida4j/example
this is my signature of the POST method of my Spring MVC controller
#RequestMapping(value="/createNewGame", method=RequestMethod.POST)
public ModelAndView createNewGame(#RequestParam(value="phoneNumber") String param,#RequestBody final SampleDTO sampleDTO) {
Map model2 = new HashMap();
model2.put("firstname", "Peter");
model2.put("secondname", "Schmitt");
return new ModelAndView("jsonView", model2);
}
instead this is the definition of the SampleDTO class:
public class SampleDTO implements Serializable{
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
I'm not able to execute the request for this method. I have this error from the client:
org.springframework.http.converter.json.MappingJacksonHttpMessageConverter.supports(Ljava/lang/Class;)Z
after execute this POST request with RestClient app with these parameters:
http://localhost:8080/SpringExample5/createNewGame.json?phoneNumber=6 (POST)
Content-Type application/json (Header attribute)
{ "value": "a" } (Body)
This is also the configuration of Spring in my web app:
<bean name="/gameController.json"
class="com.alu.server.games.acquisition.controllers.GameController"/>
<bean class="org.springframework.web.servlet.view.BeanNameViewResolver" />
<bean id="jsonView" class="org.springframework.web.servlet.view.json.MappingJacksonJsonView"/>
<bean id="jsonHttpMessageConverter"
class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter" >
<property name="objectMapper">
<ref bean="JacksonObjectMapper" />
</property>
</bean>
<bean
class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<ref bean="jsonHttpMessageConverter" />
</list>
</property>
</bean>
<bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView">
<property name="objectMapper">
<ref bean="JacksonObjectMapper" />
</property>
</bean>
<bean id="JacksonObjectMapper" class="org.codehaus.jackson.map.ObjectMapper" />
Someone can help me in order to find the problem?
Thanks in advance !
In the setting I used I did specify the Media Type to be "application/json" both in the web service's annotation as well as the XML configuration for json message converter.
Please checkout my FAQ on the matter here for further details.