How can I get #JsonIgnore to work I have a class. And even if I put the annotation there it has no effect on the output. I am using Jackson.
public class QuestionBlock implements ComparableByID{
int ID;
String title;
String description;
boolean deleted;
boolean isDraft;
boolean visible;
Timestamp modifiedDate;
String modifiedBy;
private List<Question> questions = new ArrayList<>();
#JsonIgnore
private List<Survey> surveys = new ArrayList<>();
...
#JsonIgnore
public List<Survey> getSurveys() {
return surveys;
}
#JsonIgnore
public void setSurveys(List<Survey> surveys) {
this.surveys = surveys;
}
}
This is my Controller method:
#RequestMapping(value = "/questionBlock/{id}",produces = "application/json;charset=UTF-8")
#ResponseBody
public QuestionBlock getQuestionBlock(#PathVariable("id") int id) {
return surveyService.getQuestionBlock(id);
}
Here is my servlet-context.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:mvc="http://www.springframework.org/schema/mvc"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd">
<mvc:annotation-driven />
<mvc:resources mapping="/resources/**" location="/resources/" />
<mvc:resources location="/, classpath:/META-INF/web-resources/"
mapping="/resources/**" />
<context:property-placeholder location="classpath*:META-INF/*.properties" />
<context:component-scan base-package="com.adam.czibere" />
<bean class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" id="myDataSource" name="dataSource">
<property name="driverClassName" value="${database.driverClassName}" />
<property name="url" value="${database.url}" />
<property name="username" value="${database.username}" />
<property name="password" value="${database.password}" />
<property name="testOnBorrow" value="true" />
<property name="testOnReturn" value="true" />
<property name="testWhileIdle" value="true" />
<property name="timeBetweenEvictionRunsMillis" value="1800000" />
<property name="numTestsPerEvictionRun" value="3" />
<property name="minEvictableIdleTimeMillis" value="1800000" />
<property name="validationQuery" value="SELECT 1" />
</bean>
<bean id="mySessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="myDataSource" />
<property name="packagesToScan">
<array>
<value>com.adam.czibere</value>
</array>
</property>
<property name="hibernateProperties">
<value>
hibernate.dialect=org.hibernate.dialect.MySQLDialect
</value>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="mySessionFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean
class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="mediaTypes">
<map>
<entry key="html" value="text/html" />
<entry key="json" value="application/json" />
</map>
</property>
<property name="viewResolvers">
<list>
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/" />
<property name="suffix" value=".jsp" />
</bean>
</list>
</property>
<property name="defaultViews">
<list>
<bean
class="org.springframework.web.servlet.view.json.MappingJacksonJsonView">
<property name="prefixJson" value="false" />
<property name="objectMapper" ref="jacksonObjectMapper" />
</bean>
</list>
</property>
</bean>
<bean id="jacksonObjectMapper" class="org.codehaus.jackson.map.ObjectMapper" />
<bean
class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<bean
class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
<property name="prefixJson" value="false" />
<property name="supportedMediaTypes" value="application/json" />
</bean>
</list>
</property>
</bean>
</beans>
I have finally found a solution. I changed the import statement from
import com.fasterxml.jackson.annotate.JsonIgnore; // com. instead of org.
to
import org.codehaus.jackson.annotate.JsonIgnore;
Basically you have to make sure you are using the same class everywhere.
The annotation should only be on the 'get' methods. You seem to have #Json... annotations on your private fields.
If you are using an implementation of Jackson and its annotations are not working it's probably because you have another dependency of jackson with better precedence. Hence if you want to assure that certain implementation of jackson prevales (IMHO the best choice is the one that you have all classes already annotated with, because probably it came with other dependencies) specify this dependency in the pom of the application module. So if you have in multiple modules all your entities annotated with
import com.fasterxml.jackson.annotate.JsonIgnore; // note: com. instead of org.
Instead of replacing all imports just specify the corresponding dependency in the application pom:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
This will clarify to Spring Boot that this is the implementation you want to use.
Putting #JsonProperty(access = JsonProperty.Access.WRITE_ONLY) before the field declaration solved the problem for me.
#JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
private List<Survey> surveys = new ArrayList<>();
I'm using jackson version 2.11.3
I added #Getter(onMethod_=#JsonIgnore) for boolean.
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
#Data
#Builder
#NoArgsConstructor
#AllArgsConstructor
#JsonIgnoreProperties(ignoreUnknown = true)
public class TestClass {
#JsonIgnore
private String name;
#Getter(onMethod_=#JsonIgnore)
private boolean isValid;
}
I faced this issue in my project and finally I got the solution.
Replace the dependency...
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-jaxrs</artifactId>
<version>1.9.13</version>
</dependency>
Import : com.fasterxml.jackson.annotation.JsonIgnore;
I hope, It will work.
In my case JsonIgnore was not working only on dates. Then I understood that was because of #JsonFormat() that I was using to define the format of date. Removing that solved the issue.
You Need to change your org.codehaus.jackson version.
I am currently using 1.1.1 version in which #JsonIgonre
is not working.
I changed it with 1.9.13 then #JsonIgnore is working fine.
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-jaxrs</artifactId>
<version>1.1.1</version>
</dependency>
Change to
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-jaxrs</artifactId>
<version>1.9.13</version>
</dependency>
And Java Code is :-
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import org.codehaus.jackson.annotate.JsonIgnore;
#Entity
#Table(name="users")
public class Users implements Serializable{
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;
private String username;
private String firstname;
#JsonIgnore
private String lastname;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getFirstname() {
return firstname;
}
public void setFirstname(String firstname) {
this.firstname = firstname;
}
public String getLastname() {
return lastname;
}
public void setLastname(String lastname) {
this.lastname = lastname;
}
}
I faced the same issue while working with spring and hibernate. The reason for this was that in entity class I was using org.codehaus.jackson.JsonIgnore and in spring I was using com.fasterxml.jackson.jaxrs.JsonIgnore. Fix to any one library in both layers and problem will disappear.
If #JsonProperty("fieldName") is also present on the field along with #JsonIgnore, the latter is ignored. This could happen, for instance, in generated code.
#Generated("jsonschema2pojo")
public MyGeneratedClass {
// ...
#JsonProperty("label") // This overrides #JsonIgnore
#JsonIgnore(true) // Doesn't work
#Field(name = "label")
private java.lang.String label;
// ...
}
From the documentation of JsonIgnore:
... if only particular accessor is to be ignored ..., this can be done by annotating other not-to-be-ignored accessors with JsonProperty (or its equivalents).
Related
I am new to Hibernate and while creating a small app using it I got following exception (error is related with persist of EntityManager):
java.lang.IllegalArgumentException: Unknown entity: com.nataniel.api.domain.User
at org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:840)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:240)
at com.sun.proxy.$Proxy993.persist(Unknown Source)
at com.nataniel.api.services.UserService.createUser(UserService.java:29)
Can anybody please help me out?
The Entity class is as follows:
Entity User:
package com.nataniel.api.domain;
import org.hibernate.annotations.Entity;
import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
#Entity
#Table(name="USER")
public class User {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
#Column(name = "LOGIN")
private String login;
#Column(name = "NAME")
private String name;
#Column(name = "EMAIL")
private String email;
#Column(name = "PASSWORD")
private String password;
#Column(name = "CITY")
private String city;
#Column(name = "REGION")
private String region;
#Column(name = "BIRTHDATE")
private String birthDate;
public User() {
}
public User(String login, String name, String email, String password, String city, String region, String birthDate) {
this.login = login;
this.name = name;
this.email = email;
this.password = password;
this.city = city;
this.region = region;
this.birthDate = birthDate;
}
// getters and setters
}
DAO file:
package com.nataniel.api.services;
import org.apache.camel.Exchange;
import org.json.JSONObject;
import org.springframework.stereotype.Service;
import com.nataniel.api.domain.User;
import org.springframework.transaction.annotation.Transactional;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.PersistenceContext;
#Service("userService")
public class UserService {
#PersistenceContext
transient EntityManager entityManager;
#Transactional
public String createUser(Exchange exchange) {
JSONObject userAccountJSON = (JSONObject) exchange.getIn().getHeader("jsonRequest");
User user = new User();
user.setLogin(userAccountJSON.getString("login"));
user.setEmail(userAccountJSON.getString("email"));
user.setPassword(userAccountJSON.getString("password"));
user.setName(userAccountJSON.getString("name"));
user.setCity(userAccountJSON.getString("city"));
user.setRegion(userAccountJSON.getString("region"));
user.setBirthDate(userAccountJSON.getString("birthdate"));
entityManager.persist(user);
return userAccountJSON.toString();
}
}
persistence.xml
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
version="1.0">
<persistence-unit name="service-provider" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>com.nataniel.api.domain.User</class>
<properties>
<!-- propriedades do hibernate -->
<property name="hibernate.dialect"
value="org.hibernate.dialect.MySQL5InnoDBDialect" />
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.format_sql" value="true" />
<!-- atualiza o banco, gera as tabelas se for preciso -->
<property name="hibernate.hbm2ddl.auto" value="update" />
</properties>
</persistence-unit>
</persistence>
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:cxf="http://camel.apache.org/schema/cxf"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://camel.apache.org/schema/spring
http://camel.apache.org/schema/spring/camel-spring.xsd
http://camel.apache.org/schema/cxf
http://camel.apache.org/schema/cxf/camel-cxf.xsd
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/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">
<!-- CXF -->
<cxf:rsServer id="user" address="/userservice"
serviceClass="com.nataniel.api.UserServiceRest"></cxf:rsServer>
<context:component-scan base-package="com.nataniel"/>
<!-- Camel -->
<bean id="routeBuilder" class="com.nataniel.api.camel.MailServiceRouteBuilder"/>
<camelContext xmlns="http://camel.apache.org/schema/spring">
<routeBuilder ref="routeBuilder"/>
</camelContext>
<!-- Persistence -->
<bean id="mysqlDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://192.168.0.140:3306/service-provider"/>
<property name="username" value="root"/>
<property name="password" value="123"/>
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="mysqlDataSource"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
<property name="dataSource" ref="mysqlDataSource"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"
proxy-target-class="false"/>
try to add this in your Entity User.
#Entity
#javax.persistence.Entity; // add this <--
#Table(name="USER")
I think your User Entity is not located because it reaches the hibernate API Entity and not the persistence Entity.
I am trying to create two join tables ConceptModelDetails and Instructions using a foreign key. Following are my model classes:
ConceptModelDetails:
package com.assignment.model;
#Entity
#Table(name="conceptModelDetails")
public class ConceptModelDetails {
#Id #GeneratedValue(strategy=GenerationType.AUTO)
private int instructionsId;
private String operationType;
private String conceptModelID;
private String requestor;
private String status;
private Timestamp requestDateTime;
private Timestamp lastExecutedDateTime;
private Timestamp completedDateTime;
#OneToMany(cascade=CascadeType.ALL, mappedBy="conceptModelDetails")
private Set<Instructions> instructions;
public ConceptModelDetails() {}
}
and Instuctions:
package com.assignment.model;
#Entity
#Table(name="instructions")
public class Instructions {
#Id
#GeneratedValue
private int Sno;
private String instruction;
#ManyToOne
#JoinColumn(name="instructionsId")
private ConceptModelDetails conceptModelDetails;
}
Following is applicationContext.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.1.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.1.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd">
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.postgresql.Driver" />
<property name="url" value="jdbc:postgresql://192.168.1.79:5432/test" />
<property name="username" value="postgres" />
<property name="password" value="admin" />
</bean>
<bean id="objDAO" class="com.assignment.dao.impl.ConceptModelDAOImpl">
<property name="sessionFactory" ref="sessionfactory" />
</bean>
<bean id="sessionfactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="packagesToScan" value="com.assignment.model"></property>
<property name="annotatedClasses">
<list>
<value>com.assignment.model.ConceptModelDetails</value>
<value>com.assignment.model.Instructions</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.cache.use_second_level_cache">false</prop>
</props>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionfactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
</beans>
and Controller:
#RequestMapping(value = "/myCntrl", method = RequestMethod.POST)
public String handler(HttpServletRequest request) {
System.out.println("handler");
// System.out.println(request.getParameter("conceptID"));
// System.out.println(request.getParameter("operationType"));
String[] operations = request.getParameterValues("operations");
Date date = new Date();
Timestamp time = new Timestamp(date.getTime());
ConceptModelDetails conceptModelDetails = new ConceptModelDetails();
conceptModelDetails
.setConceptModelID(request.getParameter("conceptID"));
conceptModelDetails.setOperationType(request
.getParameter("operationType"));
conceptModelDetails.setRequestor(request.getParameter("requestor"));
conceptModelDetails.setRequestDateTime(time);
ApplicationContext context = new ClassPathXmlApplicationContext(
"applicationContext.xml");
System.out.println("yo");
ConceptModelDAO obj = (ConceptModelDAO)context.getBean("objDAO");
System.out.println("no");
Instructions instructions = new Instructions();
for(int i = 0; i < operations.length; i++){
instructions.setInstruction(operations[i]);
obj.addInstructions(instructions);
}
obj.add(conceptModelDetails);
return "success";
}
Problems when I run this code are:
Same hibernate_sequence is used for both the tables.
Foreign key is not mapped in the Instruction table as seen in the following screenshot.
Please guide what is wrong with the code. I am new to hibernate and spring, so I'd appreciate a detailed explanation. Thanks in advance.
1) You are using the Global sequence generator that hibernate provide by default when no generator is provided as specifed by the JPA Spec.
Change it as follows. Do this to the both of the classes with different sequences for each class.
#Entity
#SequenceGenerator(name="PRIVATE_SEQ", sequenceName="private_sequence")
public class ConceptModelDetails {
#Id #GeneratedValue(strategy = GenerationType.SEQUENCE, generator="PRIVATE_SEQ")
private int instructionsId;
2) Here Instructions class owns the relationship and
therefore you should set ConceptModelDetails object to the Instructions object before saving the Instructions object.
ConceptModelDetails cmd1 = new ConceptModelDetails();
Instructions i = new Instructions()
i.setConceptModelDetails(cmd1);
....
Then save the Instructions object i
Hope this helps.
I have three entities (there're also getters and setters for every field):
public class IndicatorSet {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
#NaturalId
#Column(unique=true, nullable=false)
private String code;
#Column(nullable=false)
private String name;
#OneToMany(fetch = FetchType.LAZY, cascade = {CascadeType.ALL})
#JoinTable(
name = "indicator_set_indicators",
joinColumns = #JoinColumn(name = "indicator_set_id"),
inverseJoinColumns = #JoinColumn(name = "indicator_id")
)
private List<Indicator> indicators;
}
public class Indicator {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
#Column(nullable=false, unique=true)
private String code;
}
public class IndicatorSetIndicator {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
#ManyToOne
#JoinColumn(name="indicator_id", nullable=false)
private Indicator indicator;
#ManyToOne
#JoinColumn(name="indicator_set_id", nullable=false)
private IndicatorSet indicatorSet;
}
I put in database an IndicatorSet, Indicators and connect it with IndicatorSetIndicator table on my server and in junit test before running the following code.
IndicatorSet set = indicatorSetDAO.get(idOfSet);
List<Indicator> indicators = set.getIndicators();
When I invoke this code on server it works and I see my Indicators in list.
When I try to invoke this code in junit test, I see in list null reference.
And that's strange.
Also when I invoke the following code in junit test, it works perfect and indicators appears in list:
IndicatorSet set = indicatorSetDAO.get(idOfSet);
List<Indicator> indicators = indicatorSetIndicatorDAO.getIndicatorsBySet(set);
DAO uses Criteria API to get list of indicators.
There're this set of annotations on class with tests:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration("classpath:TestContext.xml")
#Transactional
#TestExecutionListeners({ DependencyInjectionTestExecutionListener.class, DirtiesContextTestExecutionListener.class,
TransactionalTestExecutionListener.class, SessionRequestTestExecutionListener.class })
TestContext.xml:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans [schemes]>
<tx:annotation-driven transaction-manager="transactionManager" />
<context:component-scan base-package="org.example.monitoring" />
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<jdbc:embedded-database id="dataSource" type="HSQL" />
<bean id="liquibase" class="liquibase.integration.spring.SpringLiquibase">
<property name="dataSource" ref="dataSource" />
<property name="changeLog" value="classpath:db-changelog.xml" />
<property name="contexts" value="test" />
<!-- <property name="dropFirst" value="true" /> -->
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name='packagesToScan' value='pro.sisit.etalon.monitoring.entities' />
<property name="dataSource" ref="dataSource" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.HSQLDialect</prop>
<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.connection.autocommit">true</prop>
</props>
</property>
</bean>
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
<property name="scopes">
<map>
<entry key="request">
<bean class="org.springframework.web.context.request.RequestScope" />
</entry>
<entry key="session">
<bean class="org.springframework.web.context.request.SessionScope" />
</entry>
</map>
</property>
</bean>
</beans>
Configuration of Hibernate not in test enviroment:
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/jdbc/monitoring" />
</bean>
<bean id='sessionFactory'
class='org.springframework.orm.hibernate4.LocalSessionFactoryBean'>
<property name='dataSource' ref='dataSource' />
<property name='packagesToScan' value='pro.sisit.etalon.monitoring.entities'/>
<property name='hibernateProperties'>
<props>
<prop key='hibernate.dialect'>org.hibernate.dialect.PostgreSQLDialect</prop>
<prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory</prop>
<prop key='hibernate.show_sql'>false</prop>
<prop key="hibernate.connection.charSet">UTF-8</prop>
<prop key="hibernate.connection.characterEncoding">UTF-8</prop>
<prop key="hibernate.connection.useUnicode">true</prop>
<prop key="hibernate.cache.use_query_cache">true</prop>
</props>
</property>
</bean>
How can I make my code work in JUint test?
This is my POJO, a simple student class.
#Proxy(lazy = false)
#Entity(name = "Students")
public class Student implements Serializable {
private static final long serialVersionUID = -9182600037012718128L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#Column
private String name;
private List<Homework> homework; // <-- the problematic line
public Student(){
}
public getId(){return id;}
public setId(long id){this.id = id;}
public getName(){return name;}
public setName(String name){this.name = name;}
public getHomework(){return homework;}
public setHomework(List<Homework> homework){this.homework = homework;}
}
Unfortunately, even though the homework field is not annotated (since I currently do not want to map it to my DB), I get this exception when running my application:
org.hibernate.MappingException: Could not determine type for: java.util.List, at table: Students, for columns: [org.hibernate.mapping.Column(homework)]
This is my hibernate-config.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-3.0.xsd">
<bean id="dataSource" class="org.apache.tomcat.dbcp.dbcp.BasicDataSource">
<property name="username" value="root" />
<property name="password" value="root" />
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://127.0.0.1:3306/test" />
<property name="testOnBorrow" value="true" />
<property name="validationQuery" value="select 1" />
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="hibernateProperties">
<value>
hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
hibernate.hbm2ddl.auto=update
hibernate.show.sql=true
</value>
</property>
<property name="annotatedClasses">
<list>
<value>com.test.entity.Student</value>
</list>
</property>
</bean>
Any help is appreciated!
Thanks!
You can make non mapped field as transient, to make hibernate not try to map it with DB
private transient List<Homework> homework;
or you can annotate it with #javax.persistence.Transient annotation
#Transient
private List<Homework> homework;
One feature of hibernate is, it tries to map all the fields of Entity class with the corresponding columns of the table. So for the variable homework, it searches for the corresponding column with the same name "homework" (case -insensitive) in the mapped table.
See the documentation here, and it says
Every non static non transient property (field or method depending on
the access type) of an entity is considered persistent, unless you
annotate it as #Transient. Not having an annotation for your property
is equivalent to the appropriate #Basic annotation.
I am currently having an issue with lazy loading not working on a bidirectional entity relationship due to the following exception:
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: sample.Person.sent, no session or session was closed
at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:394)
at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:386)
at org.hibernate.collection.internal.AbstractPersistentCollection.readElementExistence(AbstractPersistentCollection.java:161)
at org.hibernate.collection.internal.PersistentBag.contains(PersistentBag.java:256)
at sample.EmailTest.testTest(EmailTest.java:47)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:80)
at org.testng.internal.MethodInvocationHelper$1.runTestMethod(MethodInvocationHelper.java:169)
at org.springframework.test.context.testng.AbstractTestNGSpringContextTests.run(AbstractTestNGSpringContextTests.java:158)
I have the following sample entity classes:
Email
#Entity
public class Email {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String subject;
#ManyToOne(fetch = FetchType.EAGER)
private Person sender;
#ManyToMany(fetch = FetchType.EAGER)
private List<Person> recipients;
... setters/getters/constructors/equals/hashcode
Person
#Entity
public class Person {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(unique = true)
private String name;
#OneToMany(mappedBy = "sender")
private List<Email> sent;
#ManyToMany(mappedBy = "recipients")
private List<Email> received;
... setters/getters/constructors/equals/hashcode
The following repositories:
EmailRepository
import org.springframework.data.repository.CrudRepository;
public interface EmailRepository extends CrudRepository<Email, Long> {
}
PersonRepository
import org.springframework.data.repository.CrudRepository;
public interface PersonRepository extends CrudRepository<Person, Long> {
}
persistence.xml:
<persistence-unit name="unit_test">
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect" />
<property name="hibernate.connection.url" value="jdbc:hsqldb:mem:spring" />
<property name="hibernate.connection.driver_class" value="org.hsqldb.jdbcDriver" />
<property name="hibernate.connection.username" value="sa" />
<property name="hibernate.connection.password" value="" />
<property name="hibernate.hbm2ddl.auto" value="create-drop" />
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.format_sql" value="true" />
<property name="hibernate.use_sql_comments" value="true" />
<property name="hibernate.cache.use_second_level_cache" value="false"/>
<property name="hibernate.cache.use_query_cache" value="false"/>
</properties>
</persistence-unit>
Spring application_context.xml
<jpa:repositories base-package="sample" />
<jdbc:embedded-database id="dataSource" type="HSQL" />
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="generateDdl" value="true" />
<property name="database" value="HSQL" />
</bean>
</property>
<property name="persistenceUnitName" value="unit_test" />
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
Here is the test code that produces the exception:
#ContextConfiguration(locations={"/application_context.xml"})
public class EmailTest extends AbstractTestNGSpringContextTests{
#Autowired
private EmailRepository emailRespository;
#Autowired
private PersonRepository personRepository;
private Long fredId;
#BeforeMethod
public void setUp() {
Person john = new Person("John");
john = personRepository.save(john);
Person fred = new Person("Fred");
fred = personRepository.save(fred);
Person julio = new Person("Julio");
julio = personRepository.save(julio);
Email mail = new Email("subject", john, Lists.newArrayList(john, fred, julio));
emailRespository.save(mail);
fredId = fred.getId();
}
#Test
#Transactional
public void testTest() throws Exception{
Person fred = personRepository.findOne(fredId);
List<Email> sent = fred.getSent();
List<Email> received = fred.getReceived();
sent.contains(null);
received.contains(null);
int i = 0;
}
}
Saving and finding seems to work fine, but the lazy loaded collections do not work, seemingly because the session is closed, even though the method is #Transactional. Obviously I am missing something, as I see other nearly identical samples.
Edit: Added fetch = FetchType.EAGER to Email entity, no change.
I'm not sure what's closing the Hibernate session, but you could try to add fetch=FetchType.EAGER to the mappings below:
#ManyToOne
private Person sender;
#ManyToMany
private List<Person> recipients;