Jackson exception after Ajax call in Spring/hibernate web-app - ajax

in my spring web-app and behind an AJAX call the below exception fire :
com.fasterxml.jackson.databind.JsonMappingException: failed to lazily initialize a collection of role: com.domain.entities.Person.followerd, could not initialize proxy - no Session
Parent entity:
#Entity
public class Person {
#OneToMany(mappedBy="follower")
#JsonIgnore
private List<FollowerPerson> followerd;
....
#ElementCollection(fetch = FetchType.EAGER)
#CollectionTable(name="phone", joinColumns=#JoinColumn(name="person"))
protected List<Phone> phones;
}
FollowerPerson entity
#Entity
public class FollowerPerson implements Serializable {
#EmbeddedId
private FollowerPk id;
#MapsId("std")
#ManyToOne
private Person std;
#MapsId("follower")
#ManyToOne
private Person follower;
....
}
in My AppConfig i use this txManager spring + hibernate (JPA-based):
#Bean
public PlatformTransactionManager txManager() {
JpaTransactionManager jpaTransactionManager = new JpaTransactionManager(
getEntityManagerFactoryBean().getObject());
return jpaTransactionManager;
}
the exception occur when the ajax call try to recognise the list after findAll dao method execution that looks for all persons
When i annotate this attribute with fetch=FetchType.EAGER
an other exception instead will appear :
cannot simultaneously fetch multiple bags: [com.domain.entities.Person.followerd, com.domain.entities.Person.phones]
please help

change list to set if you can. LinkedHashSet if you still need an order.

Related

Why does Spring MVC controller method ignore FetchType.LAZY behaviour and act like FetchType.EAGER?

My Film model explicitly states it should fetch its children Actors lazily.
#Entity
#Getter
#Setter
public class Film {
...
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(
name = "film_actor",
joinColumns = #JoinColumn(name = "film_id"),
inverseJoinColumns = #JoinColumn(name = "actor_id")
)
private List<Actor> cast = new ArrayList<>();
This actually works perfectly when using the service/repository in any other context:
#Override
public void run(String... args) throws Exception {
List<Film> films = filmService.getAllFilms();
System.out.println(films);
}
But then for some mysterious reason, ONLY when used in a Spring MVC controller method (using typical annotations like #Controller and #RequestMapping), it always comes back eagerly loaded...Why and how do I change this? If I have 1000 films I want to display at once, I don't want to load in a million actors!
#GetMapping("")
public String filmsPage(Model model){
List<Film> allMyFilms = filmService.getAllFilms();
model.addAttribute("films", allMyFilms);
return "film/film-list";
}
Incidentally, for completeness, here are my service/repository layers:
#Service
#RequiredArgsConstructor
public class FilmServiceImpl implements FilmService {
private final FilmRepository filmRepo;
...
#Override
public List<Film> getAllFilms() {
List<Film> films = filmRepo.findAll();
return films;
}
Repository layer:
#Repository
public interface FilmRepository extends JpaRepository<Film, Long> {
List<Film> findAll();
}
How do you verify that the association is eager? Spring MVC has something enabled by default which is called "open session in view", which allows lazy loading until the request is finished. If you "check" whether data is loaded through your debugger, the debugger will invoke the toString method of PersistentBag which will initialize the lazy collection.

Mybatis dao pattern not autowiring field

Trying to make a dao pattern for mybatis and spring. Want to use this sql queries anywhere i want, just using dependency injection.
When i try to use this method (.getMaxId()) it gives me "Null pointer exception".
Why field SqlSession is not autowiring(gives null)? Intellige idea shows this field as a canditate for
autowiring.
I think there is 3 steps to achieve:
1) Autowire session
2) get mapper from session
3) execute queries from this mapper
I do this
#Autowired
private Student_mapper sm;
sm.getMaxId();
Service
#Service
#Transactional
public class Student_mapperImpl {
#Autowired
private SqlSession session;
#Autowired
Student_mapper mapper = session.getMapper(Student_mapper.class);
public Integer getMaxId() {
Integer value = mapper.getMaxId();
return value;
}
}
Bean configuration file
#org.springframework.context.annotation.Configuration
#EnableTransactionManagement
#ComponentScan
public class DataSourceStudent_Mapper {
#Bean
public SqlSession getDataSource() {
String user = "postgres";
String password = "postgres";
String databasenameURL = "jdbc:postgresql://localhost:5432/postgres";
String dbDriver = "org.postgresql.Driver";
DataSource dataSource = new org.apache.ibatis.datasource.pooled.PooledDataSource(
dbDriver, databasenameURL, user, password);
TransactionFactory transactionFactory = new JdbcTransactionFactory();
Environment environment = new Environment("development",
transactionFactory, dataSource);
Configuration configuration = new Configuration(environment);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder()
.build(configuration);
SqlSession session = sqlSessionFactory.openSession();
session.getConfiguration().addMapper(Student_mapper.class);
return session;
}
}
Student_mapper - interface with a queries
#Repository
public interface Student_mapper {
#Select("select max(id) from student")
#Result(property = "id", column = "ID")
Integer getMaxId();
}
Entity
public class Student {
private int id;
private String name;
private String branch;
private int percentage;
private int phone;
private String email;
//(setters,getters, allArgs constructor are ommited)
}
I don't understand what's wrong. There is any examples how to realise this? I would like to execute my queries anywhere i want without constantly initializing the session, datasource etc. Thanks in advance
mybatis-spring Getting Started should be useful.

Populate #Transient field within Spring Data Jpa Repository

Is possible to populate transient field in entity class with Spring Data REST api somehow (by projection or something) - to get that value in JSON response ? I need to populate for example info field with value got from second datasource (i had Spring repo bean for this datasource and need inject it in something like "interceptor" and fill that field).
#Entity
public class User {
#Id
private Long id;
#Transient
private String info;
// getters & setters
}
public interface UserRepository extends JpaRepository<User, Long> {
}
I found solution using PostLoadEventListener, but it is for Hibernate, not exactly what i was looking for, but works. I think it should be more general Spring-ly solution.
#Component
public class UserInterceptor implements PostLoadEventListener {
#Autowired
private SecondRepository repo;
#Autowired
#Qualifier("prmiaryEntityManagerFactory")
private EntityManagerFactory entityManagerFactory;
#PostConstruct
private void init() {
HibernateEntityManagerFactory hibernateEntityManagerFactory = (HibernateEntityManagerFactory) this.entityManagerFactory;
SessionFactoryImpl sessionFactoryImpl = (SessionFactoryImpl) hibernateEntityManagerFactory.getSessionFactory();
EventListenerRegistry registry = sessionFactoryImpl.getServiceRegistry().getService(EventListenerRegistry.class);
registry.appendListeners(EventType.POST_LOAD, this);
}
#Override
public void onPostLoad(PostLoadEvent event) {
final Object entity = event.getEntity();
if(entity != null && entity instanceof User) {
User user = (User) entity;
// populate using another repo bean
Info s = repo.findOne(user.getInfoId());
user.setInfo(s.getName());
}
}
}

Spring Data JPA findOne returns null

I'm using Spring Data JPA and I'm facing a very weird issue with findOne method which is returning null even though the row is present in DB.
I have a consumer thread which takes an id from a queue and tries to fetch the entity from DB which always returns null, however if I pause thread (by putting a breakpoint before method call) then it fetches the entity from DB but returns null in normal execution of program, I know it sounds weird with breakpoint stuff but it is what it is, may be I'm missing something. My code looks like below:-
if (id > 0) {
employee = employeeService.get(id);
if (employee == null) {
logger.error(String.format("No employee found for id : %d",
id));
return;
}
I'm not using any transaction in "employeeService" as it is not required as it is a read operation.
My service looks like
public Employee get(long id) {
return employeeDao.findOne(id);
}
And my model looks like:-
#Entity
#Table(name = "employee")
#JsonInclude(JsonInclude.Include.NON_NULL)
public class Employee implements Serializable {
private static final long serialVersionUID = 1681182382236322985L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#Column(name = "name")
private String name;
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinColumn(name = "emplopyee_id")
#Fetch(FetchMode.SELECT)
private List<Address> addresses;
// getter/setter and few fields have been omitted
}
Can somebody point me where I'm mistaking.
The Spring 4.2 way to do this would be to introduce a #TransactionEventListener annotated method on a spring component to handle the callback. You then simply need to publish an event and let the event framework do its thing:
// Spring component that handles repository interactions
#Component
public class ProducerService implements ApplicationContextAware {
private ApplicationContext applicationContext;
#Transactional
public void doSomeThingAwesome(String data) {
MyAwesome awesome = new MyAwesome( data );
myAwesomeRepository.save( awesome );
applicationContext.publishEvent( new MyAwesomeSaved( awesome.getId() ) );
}
}
// Spring component that handles the AFTER_COMMIT transaction callback
// This component only fires when a MyAwesomeSaved event is published and
// the associated transaction it is published in commits successfully.
#Component
public class QueueIdentifierHandler {
#TransactionalEventListener
public void onMyAwesomeSaved(MyAwesomeSaved event) {
Long entityId = event.getId();
// post the entityId to your queue now
}
}

Play Framework + Spring Data JPA : LazyInitializationException

These are the following classes:
#Entity
public class Question {
#Id
public Long id;
public String name;
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
#JoinColumn(name = "OWNER_ID", referencedColumnName = "QUES_ID")
public List<Choice> choices = new ArrayList<>();
}
#Named
#Singleton
public interface QuestionRepository extends CrudRepository<Question , Long> {
Question findByName(String name);
}
And in the Controller file I have this following File
#Transactional
public Result getQuestion() {
List<Choices> list = this.questionRepository.findByName("name").choices;
list.size();
return ok();
}
list.size() in getQuestion() throws me a LazyInitializationException because there is not open sessions
I know that changing the fetch type to EAGER or using a JPQL query above the function definition in QuestionRepository might solve it, but there are part in my application where those wont help and I would require to lazy fetch.
How would make the entire code in getQuestion() function use a single session/transaction or even better my entire request to take place in an single session/transaction?
From Spring Data JPA reference documentation
4.7.1. Transactional query methods
To allow your query methods to be transactional simply use #Transactional at the repository interface
you define.
Example 100. Using #Transactional at query methods
#Transactional(readOnly = true)
public interface UserRepository extends JpaRepository<User, Long> {
List<User> findByLastname(String lastname);
#Modifying
#Transactional
#Query("delete from User u where u.active = false")
void deleteInactiveUsers();
}
Typically you will want the readOnly flag set to true as most of the query methods will only read data. In contrast to that deleteInactiveUsers() makes use of the #Modifying annotation and overrides the transaction configuration. Thus the method will be executed with readOnly flag set to false.
So just add #Transactional annotation to your repository interfaces.

Resources