spring rest lazy loading with hibernate - json

I am trying to develop spring rest api with hibernate.
after searching in google, I have not find solution to lazy loading.
I have two entity like below:
University.java
#Entity()
#Table(schema = "core", name = "university")
public class University extends BaseEntity {
private String uniName;
private String uniTelephon;
#LazyCollection(LazyCollectionOption.FALSE)
#OneToMany(fetch = FetchType.LAZY, mappedBy = "university", cascade = CascadeType.ALL)
#JsonManagedReference
private List<Student> students;
//setter and getter
}
Student.java
#Entity
#Table(schema = "core",name = "student")
public class Student {
#Id
#GeneratedValue
private long id;
private String firstName;
private String lastName;
private String section;
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name = "UNIVERSITY_ID",nullable = false)
#JsonBackReference
private University university;
// setter and getter
}
any my rest end point
#GetMapping("/list")
public ResponseEntity list() throws Exception {
// I need to return just Universities But it return it eagerly with their students
return new ResponseEntity(this.universityService.findAll(), HttpStatus.OK);
}
after calling the rest api, it return university with all students.
There is a way to tell Jackson to not serialize the unfetched objects or collections?
Can somebody help me with a proved solution?

Try adding the following dependancy (depending on your hibernate version):
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-hibernate5</artifactId>
<version>${jackson.version}</version>
</dependency>
And then (assuming you have a Java based configuration) add the following in the WebMvcConfigurerAdapter class:
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(jackson2HttpMessageConverter());
}
#Bean
public MappingJackson2HttpMessageConverter jackson2HttpMessageConverter() {
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setObjectMapper(this.jacksonBuilder().build());
return converter;
}
public Jackson2ObjectMapperBuilder jacksonBuilder() {
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
Hibernate5Module hibernateModule = new Hibernate5Module();
hibernateModule.configure(Feature.FORCE_LAZY_LOADING, false);
builder.modules(hibernateModule);
// Spring MVC default Objectmapper configuration
builder.featuresToDisable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
builder.featuresToDisable(MapperFeature.DEFAULT_VIEW_INCLUSION);
return builder;
}
It should force the Jackson's objectMapper to not fetch lazy-loaded values.

Related

In #SpringBootTest, how do I get a fasterxml objectMapper to include a field from my model?

I'm using Spring Boot 2.1 with Java 11. I have annotated my User model with fasterxml annotations so that my password can be accepted for POST requests, but not returned for other REST requests ...
#Data
#Entity
#Table(name = "Users")
public class User implements UserDetails {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private UUID id;
private String firstName;
private String lastName;
#NotBlank(message = "Email is mandatory")
#Column(unique=true)
private String email;
#JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
private String password;
private boolean enabled;
private boolean tokenExpired;
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(
name = "users_roles",
joinColumns = #JoinColumn(
name = "user_id", referencedColumnName = "id"),
inverseJoinColumns = #JoinColumn(
name = "role_id", referencedColumnName = "id"))
private Collection<Role> roles;
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
// TODO Auto-generated method stub
return null;
}
#Override
public String getUsername() {
return email;
}
#Override
public boolean isAccountNonExpired() {
// TODO Auto-generated method stub
return false;
}
#Override
public boolean isAccountNonLocked() {
// TODO Auto-generated method stub
return false;
}
#Override
public boolean isCredentialsNonExpired() {
// TODO Auto-generated method stub
return false;
}
#PrePersist #PreUpdate
private void prepare(){
this.email = this.email.toLowerCase();
}
}
However, when trying to run an integration test, the password is not getting translated by "objectMapper.writeValueAsString". Here is my test ...
#SpringBootTest(classes = CardmaniaApplication.class,
webEnvironment = WebEnvironment.RANDOM_PORT)
public class UserControllerIntegrationTest {
#Autowired
private TestRestTemplate restTemplate;
#Autowired
private ObjectMapper objectMapper;
#Autowired
private IUserRepository userRepository;
#Test
#WithUserDetails("me#example.com")
void registrationWorksThroughAllLayers() throws Exception {
final String email = "newuser#test.com";
final String firstName = "first";
final String lastName = "last";
final String password = "password";
User user = getTestUser(email, password, firstName, lastName, Name.USER);
ResponseEntity<String> responseEntity = this.restTemplate
.postForEntity("http://localhost:" + port + "/api/users", user, String.class);
assertEquals(201, responseEntity.getStatusCodeValue());
final User createdUser = userRepository.findByEmail(email);
assertNotNull(createdUser);
assertNotNull(createdUser.getPassword());
}
#Test
#WithUserDetails("me#example.com")
void getDetailsAboutMyself() throws JsonProcessingException, JSONException {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
UserDetails user = (UserDetails) authentication.getPrincipal();
final User foundUser = userRepository.findByEmail(user.getUsername());
ResponseEntity<String> responseEntity = this.restTemplate
.getForEntity("http://localhost:" + port + "/api/users/" + foundUser.getId(), String.class);
assertEquals(200, responseEntity.getStatusCodeValue());
// assert proper response
final String userAsJson = objectMapper.writeValueAsString(user);
assertEquals(userAsJson, responseEntity.getBody());
JSONObject object = (JSONObject) new JSONTokener(userAsJson).nextValue();
// Verify no password is returned.
assertNull(object.getString("password"));
}
...
}
The JSON from the objectMapper.writeValueAsString call is
{"id":null,"firstName":"first","lastName":"last","email":"newuser#test.com","enabled":true,"tokenExpired":false,"roles":null,"username":"newuser#test.com","authorities":null,"accountNonExpired":false,"accountNonLocked":false,"credentialsNonExpired":false}
What's the proper way to get my password included as part of the mapping as well as suppressing the password when requesting my entity from read endpoints?
This is a common misunderstanding, there was even a bug report for it and they clarified the documentation.
"READ" and "WRITE" are to be understood from the perspective of the Java Property, i.e., when you serialize an Object, you have to read the property and when you deserialize it, you have to write it.
In your case, you want #JsonProperty(access = JsonProperty.Access.READ_ONLY)
Using WRITE_ONLY or READ_ONLY will not work in your case. The reason is one call over http needs both. Lets take this.restTemplate.postForEntity as an example. In the sending side, your User java object need to serialised to json so it needs the READ and when the rest endpoint receives the json, it need to deserialise the json into User java object so needs the WRITE. It will be the same scenario for this.restTemplate.getForEntity too
One solution is to set the password field of User on the GET endpoint to null before returning
Another solution is create a separate UserDto without password field and return it from GET endpoint
Another solution is to create two JsonViews where one is with password and other one is without password. Then annotate your endpoints with correct #JsonView

Lazy collection in Spring JPA with Jackson and elasticsearch wihtout jsonignore

We have spring boot with elasticsearch and mysql. We have a feature for reindexing all data from the mysql into elasticsearch, which is simple as:
#Service
#Transactional
public class SearchIndexer {
public void reindex(){
elasticsearchRepository.save(jpaRepository.findAll());
}
}
Now we have an entity called invoice, which has a lazy loaded collection with a "derived" calculation:
#Entity
#Table(name = "invoice")
#Document(indexName = "invoice")
public class Invoice implements Serializable {
//... other props
#OneToMany(fetch = FetchType.LAZY, mappedBy = "invoice")
#JsonIgnore
private Set<InvoiceItem> invoiceItems = new LinkedHashSet<>();
// getter and setters for invoiceItems
public boolean isAllSimple() {
if(getInvoiceType()==null){
return false;
}
if(getInvoiceItems()==null){
return false;
}
for(InvoiceItem item : getInvoiceItems()){
if(!item.isSimple()){
return false;
}
}
return true;
}
}
When the rest-controller is used, the resulting json contains correctly a property "allSimple". This is, because we run that with hibernate5module in one transaction.
However, when we call elasticsearchRepository.save(jpaRepository.findAll()) (also in a transaction), the objectmapper for elasticsearch cannot serialize the "allSimple" property, beacause of a LazyInitializationException. The elasticsearch-objectmapper is configured as follows:
#Bean
public ElasticsearchTemplate elasticsearchTemplate(Client client, Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder, Hibernate5Module hibernate5Module) {
return new ElasticsearchTemplate(client, new CustomEntityMapper(jackson2ObjectMapperBuilder.createXmlMapper(false).modulesToInstall(hibernate5Module).build()));
}
public class CustomEntityMapper implements EntityMapper {
private ObjectMapper objectMapper;
public CustomEntityMapper(ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
objectMapper.configure( DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
objectMapper.configure( DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
}
#Override
public String mapToString(Object object) throws IOException {
return objectMapper.writeValueAsString(object);
}
#Override
public <T> T mapToObject(String source, Class<T> clazz) throws IOException {
return objectMapper.readValue(source, clazz);
}
}
The hibernate5module is loaded and registered, but did not solve the problem.
Normally we would add a "JsonIgnore" to that property, but we need that value, so this is no option.
Any ideas?!
I had a project configurated with this.
#EnableWebMvc
#Configuration
#ComponentScan(basePackages = "com.sagasoftware.tracker.*")
public class WebConfiguration extends WebMvcConfigurerAdapter {
#Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
ObjectMapper objectMapper = new ObjectMapper();
Hibernate5Module hibernate5Module = new Hibernate5Module();
objectMapper.registerModule(hibernate5Module);
objectMapper.configure(FAIL_ON_UNKNOWN_PROPERTIES, false);
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
messageConverter.setObjectMapper(objectMapper);
return messageConverter;
}
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(mappingJackson2HttpMessageConverter());
super.configureMessageConverters(converters);
}
}
If you are using spring boot, declaring the bean MappingJackson2HttpMessageConverter and registering the hibernate5module should fix your problem.
I could render a entity throught a rest controller.

Using Multiple Database in Spring boot

I encounted a problem when I wanted to work between two database, I wanted to use the table 1 in database 1 and the table 2 in database 2, I tried so many ways, but all seems not work.
spring.datasource.primary.url = jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=UTF-8
spring.datasource.primary.username = root
spring.datasource.primary.password = xxxx
spring.datasource.primary.driverClassName=com.mysql.jdbc.Driver
spring.datasource.secondary.url = jdbc:mysql://localhost:3306/testdb?useUnicode=true&characterEncoding=UTF-8
spring.datasource.secondary.username = root
spring.datasource.secondary.password = xxxx
spring.datasource.secondary.driverClassName=com.mysql.jdbc.Driver
above is my application.properties. Then I used #Primary setting spring.datasource.primary as the primary database in config file.
#Entity
#Table(name = "User")
public class User {
#Id
#NotNull
#Column(name = "phoneid")
private String phoneid;
}
public interface UserDAO extends CrudRepository<User, String> {
public User findByPhoneid(String phoneid);
}
I want to connect to database spring.datasource.primary and use the table User in it.
#Entity
#Table(name = "Favorite_Restaurant")
public class FavoriteRestaurant {
#Id
#NotNull
#Column(name = "favorite_restaurantid")
private int favoriteRestaurantId;
}
public interface FavoriteRestaurantDAO extends JpaRepository<FavoriteRestaurant, Integer> {
public List<FavoriteRestaurant> findAll(Sort sort);
}
I want to connect to database spring.datasource.secondary and use the table FavoriteRestaurant in it.
However when I Autowired UserDAo and FavoriteRestaurantDAO in My Service, It seems just like it autowired both userdao and favoriterestaurantdao from primary database. How can I inject FavoriteRestaurantDAO from secondary database!!!!! help!!!!!!
To be able to use several datasources you need to have several persistent unit configurations.
I will assume that you've got datasourceA and datasourceB to configure.
We have one configuration class for each of our persistent units. The listing contains the class for datasourceA (you will have to copy and adjust the configuration for datasourceB).
It's also a good idea not to mix the entities from different persistent units.
So we have separated them based on the package. We have created an empty class
SpringRootPackageMarker so that it tells spring which packages to scan.
Note! the SpringRootPackageMarker class is used in both #EnableJpaRepositories and in getDatasourceAEntityManagerFactoryBean method
So this is our way how to do it:
#DependsOn("transactionManager")
#EnableJpaRepositories(
basePackageClasses = SpringRootPackageMarker.class,
entityManagerFactoryRef = "datasourceAEntityManager",
transactionManagerRef = "transactionManager")
public class DatasourceAPersistenceUnitConfiguration {
private static final String DATASOURCE_A_PERSISTENT_UNIT_NAME = "datasourceAPU";
#DependsOn("transactionManager") // for unit tests
#Bean(name = "datasourceAEntityManager")
public LocalContainerEntityManagerFactoryBean getDatasourceAEntityManagerFactoryBean() {
final LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setPersistenceUnitName(DATASOURCE_A_PERSISTENT_UNIT_NAME);
factory.setDataSource(getDatasourceA());
factory.setJpaVendorAdapter(getDatasourceAJpaVendorAdapter());
factory.setPackagesToScan(SpringRootPackageMarker.class.getPackage().getName());
Properties jpaProperties = getDatasourceAJpaProperties();
factory.setJpaProperties(jpaProperties);
return factory;
}
#Bean
public DataSource getDatasourceA() {
DataSource datasource = null;
// prepare datasource A;
return datasource;
}
private JpaVendorAdapter getDatasourceAJpaVendorAdapter() {
final HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
//custom configuration for datasource A
return vendorAdapter;
}
private Properties getDatasourceAJpaProperties() {
Properties jpaProperties = new Properties();
//custom properties
return jpaProperties;
}
}
}
if you plan to inject the entityManager into your application you'll have to do it this way:
#PersistenceContext(unitName= DatasourceAPersistenceUnitConfiguration.DATASOURCE_A_PERSISTENT_UNIT_NAME)
private EntityManager manager;
Finally, I solved this problem by adding #EnableAutoConfiguration above my config class
#Configuration
#EnableJpaRepositories(basePackages = "datamodel.dao", entityManagerFactoryRef = "localEntityManagerFactory", transactionManagerRef = "localTransactionManager")
#EnableTransactionManagement
#EnableAutoConfiguration ///the key to make spring boot know your config!!!!!!!!!!!!!
public class MainDataConfig {
#Bean
#ConfigurationProperties(prefix = "datasource.main")
#Primary
public DataSource localDataSource() {
return DataSourceBuilder.create().build();
}
#Bean
#Primary
public LocalContainerEntityManagerFactoryBean localEntityManagerFactory(final EntityManagerFactoryBuilder builder) {
return builder.dataSource(localDataSource()).packages("datamodel.domain")
.persistenceUnit("mainPersistenceUnit").build();
}
#Bean
#Primary
public JpaTransactionManager localTransactionManager(#Qualifier("localEntityManagerFactory") final EntityManagerFactory factory) {
return new JpaTransactionManager(factory);
}
}

JsonIgnore and JsonBackReference are being Ignored

i'm using spring 4.0.1 , hibernate 4.3.5 ,jackson 1.9.2 and STS IDE
I'm creating a RESTful webservice that returns a data in JSON format
when i use Hibernate code generator it generates getters and setter of associated entities annotated by #OneToMany(fetch = FetchType.LAZY, mappedBy = "user") for the source
and #ManyToOne(fetch = FetchType.LAZY) for the reference
which causes an infinite recursion during serialization. I tried using Jackson's #JsonIgnore and #JsonBackReference annotations to fix the problem but it seems as if they are being totally ignored and the infinite recursion is still occurring.
Caused by: com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion (StackOverflowError)
This is my entity classes
User.class
//i get that suggestion from some sites
#JsonIgnoreProperties({ "hibernateLazyInitializer", "handler" })
#Entity
#Table(name = "user", catalog = "someSchema")
public class User implements java.io.Serializable {
private String name;
private String password;
private String username;
private Set<Telephone> telephones = new HashSet<Telephone>(0);
#JsonManagedReference
#OneToMany(fetch = FetchType.LAZY, mappedBy = "user")
public Set<Telephone> getTelephones() {
return this.telephones;
}
public void setTelephones(Set<Telephone> telephones) {
this.telephones = telephones;
}
}
Telephone.class
#Entity
#Table(name = "telephone", catalog = "someSchema")
public class Telephone implements java.io.Serializable {
private User user;
private String telephone;
#ManyToOne(fetch = FetchType.LAZY)
//tried #JsonIgnore only and both
#JsonIgnore
//tried #JsonBackReference only and both
#JsonBackReference
#JoinColumn(name = "user_id", nullable = false)
public User getUser() {
return this.user;
}
#JsonIgnore
#JsonBackReference
public void setUser(User user) {
this.user = user;
}
}
concerning registering jackson to my application, i used xml config
<mvc:annotation-driven>
<mvc:message-converters>
<bean
class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper">
<bean
class="web.jsonConverters.HibernateAwareObjectMapper" />
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
and mapper class
public class HibernateAwareObjectMapper extends ObjectMapper {
public HibernateAwareObjectMapper() {
Hibernate4Module hm = new Hibernate4Module();
registerModule(hm);
}
}
Do you have any idea why the Jackson annotations are being ignored?
any help will be appreciated...
use
import com.fasterxml.jackson.annotation.JsonBackReference;
instead of
import org.codehaus.jackson.annotate.JsonBackReference;
i found a way by annotating the setter by #Transient
idont know why but it works fine
User.class
//i get that suggestion from some sites
#JsonIgnoreProperties({ "hibernateLazyInitializer", "handler" })
#Entity
#Table(name = "user", catalog = "someSchema")
public class User implements java.io.Serializable {
private String name;
private String password;
private String username;
private Set<Telephone> telephones = new HashSet<Telephone>(0);
#OneToMany(fetch = FetchType.LAZY, mappedBy = "user")
public Set<Telephone> getTelephones() {
return this.telephones;
}
public void setTelephones(Set<Telephone> telephones) {
this.telephones = telephones;
}
}
Telephone.class
#Entity
#Table(name = "telephone", catalog = "someSchema")
public class Telephone implements java.io.Serializable {
private User user;
private String telephone;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "user_id", nullable = false)
public User getUser() {
return this.user;
}
#Transient
public void setUser(User user) {
this.user = user;
}
}
Another Naive Solution
I solved it manually in my RESTful Controller
by loop over the set of telephones and set user to null
#RestController
#RequestMapping("/user")
public class UserController extends ParentController {
static final Logger logger = Logger.getLogger(UserController.class.getName());
#Autowired
IUserDao iuserdao;
#RequestMapping(value = "/signin", method = RequestMethod.POST)
public ResponseEntity<User> signin(#RequestBody LoginWrapper login) {
System.out.println("==============GET USER==============");
try {
User user = iuserdao.signin(login);
if (user == null) {
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.set(ERR_HEADER_NAME, "user not exist");
return new ResponseEntity<User>(httpHeaders, HttpStatus.NOT_FOUND);
} else {
List<Telephone> tels=user.getTelephones();
for (Telephone telephone : tels) {
telephone.setUser(null);
}
return new ResponseEntity<User>(user, HttpStatus.OK);
}
} catch (Exception e) {
System.out.println(e.getMessage());
return null;
}
}
still need a better answer concerning Jackson problem..

#JsonIgnore and #JsonBackReference are being Ignored

I'm working with RestEasy, Jboss 7 and EJB 3.1. I'm creating a RESTful web service that returns data in JSON format.
The problem is that I have a #ManyToOne relationship on one of my entities which causes an infinite recursion during serialization. I tried using Jackson's #JsonIgnore and #JsonBackReference annotations to fix the problem but it seems as if they are being totally ignored and the infinite recursion is still occurring.
This is my User Class:
class User {
private String userId;
private Role role;
#Id
#Column(name = "\"UserId\"", unique = true, nullable = false, length = 30)
public String getUserId() {
return this.UserId;
}
public void setUserId(String UserId) {
this.UserId = UserId;
}
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "\"RoleId\"", nullable = false)
//I have tried #JsonIgnore without #JsonBackReference
#JsonIgnore
//I have tried #JsonBackReference without #JsonIgnore
//Also I have tried #JsonBackReference and #JsonIgnore together
#JsonBackReference("role-User")
public Role getRole() {
return this.role;
}
}
This is a part of my Role Class:
#JsonManagedReference("role-User")
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "role")
public Set<User> getUsers() {
return this.users;
}
I have read somewhere that I should register Jackson with my application to be able to use regular Jaxb annotation so I created a class
#Provider
#Produces(MediaType.APPLICATION_JSON)
public class JacksonContextResolver implements ContextResolver<ObjectMapper> {
public JacksonContextResolver() {
ObjectMapper mapper = new ObjectMapper();
AnnotationIntrospector introspector = new JaxbAnnotationIntrospector();
mapper.getDeserializationConfig().setAnnotationIntrospector(
introspector);
mapper.getSerializationConfig().setAnnotationIntrospector(introspector);
}
public ObjectMapper getContext(Class<?> objectType) {
return objectMapper;
}
}
The problem with the above being that JaxbAnnotationIntrospector() is deprecated.
Please:
Do you have any idea why the Jackson annotations are being ignored?
How can I use the regular JAXB XML annotations instead of Jackson's?
What can I use instead of JaxbAnnotationIntrospector()?
An answer to any of these question is appreciated, thanks.
Update:
For now I have excluded resteasy-jackson-provider using jboss-deployment-structure.xml and I am using Jettison instead. I still want to know how could I use Jackson!
The problem here seems to be related to using Set<User> instead of List<User>. I had exactly the same problem and changing from Set<User> to List<User> fixed this, otherwise I always got Infinite recursion error from Jackson. I don't know if this is really a bug in Jackson or do you have to provide some other annotations etc. when using Set.
use import com.fasterxml.jackson.annotation.JsonBackReference; instead of import org.codehaus.jackson.annotate.JsonBackReference;.
It was the problem for me.
I had this problem and got the same code to work by updating the version of the Jackson library in my build (pom.xml) from 1.8.x to 1.9.13. If you are using maven, edit your pom.xml to contain:
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.13</version>
</dependency>
Documentation doesn't help, but it seems that back references for Sets were not supported in the 1.8.x versions.
Look, I have something similar to you and is working just fine for me...
#JsonBackReference("promotion-travel")
#ManyToOne(cascade = CascadeType.ALL)
#JoinTable(name="PROMOTION_TRAVEL_REL",
joinColumns = #JoinColumn(name="TRAVEL_ID"),
inverseJoinColumns = #JoinColumn(name="PROMOTION_ID")
)
public Promotion getPromotion(){...
And this is what I have on Entity1
#JsonManagedReference("promotion-travel")
#OneToMany(mappedBy="promotion")
public List<Travel> getTravelList(){...
I don't know if moving the annotation to the top will change anything, but that's the only thing that I can see...
Cheers,
I had a similar problem where my getter function was not named based on the field name, so the json parsing was still happening for the getter. Changing the getter name solved the issue.
i'm using spring 4.0.1 , hibernate 4.3.5 ,jackson 1.9.2 and STS IDE
i had the same exception but solved by annotating the setter by #Transient
idont know why but it works fine
This is my entity classes
User.class
//i get that suggestion from some sites
#JsonIgnoreProperties({ "hibernateLazyInitializer", "handler" })
#Entity
#Table(name = "user", catalog = "someSchema")
public class User implements java.io.Serializable {
private String name;
private String password;
private String username;
private Set<Telephone> telephones = new HashSet<Telephone>(0);
#OneToMany(fetch = FetchType.LAZY, mappedBy = "user")
public Set<Telephone> getTelephones() {
return this.telephones;
}
public void setTelephones(Set<Telephone> telephones) {
this.telephones = telephones;
}
}
Telephone.class
#Entity
#Table(name = "telephone", catalog = "someSchema")
public class Telephone implements java.io.Serializable {
private User user;
private String telephone;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "user_id", nullable = false)
public User getUser() {
return this.user;
}
#Transient
public void setUser(User user) {
this.user = user;
}
}
concerning registering jackson to my application, i used xml config
<mvc:annotation-driven>
<mvc:message-converters>
<bean
class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper">
<bean
class="web.jsonConverters.HibernateAwareObjectMapper" />
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
and mapper class
public class HibernateAwareObjectMapper extends ObjectMapper {
public HibernateAwareObjectMapper() {
Hibernate4Module hm = new Hibernate4Module();
registerModule(hm);
}
}