I got another problem when working on my current Spring and Hibernate application. I have built my DAO interfaces/classes, as well as my Service interfaces/classes and of course the Entities.
Everything is being deployed well but as soon as I add the #Transactional annotation to my XXXServiceImpl classes, I get the following exception during deployment (tested on Glassfish AND Tomcat):
Caused by: java.lang.IllegalStateException: Cannot convert value of type [com.sun.proxy.$Proxy25 implementing net.dreamcode.bleevle.persistence.service.IntranetService,org.springframework.aop.SpringProxy,org.springframework.aop.framework.Advised] to required type [net.dreamcode.bleevle.persistence.service.impl.IntranetServiceImpl] for property 'intranetService': no matching editors or conversion strategy found
Of course, I tried to find something about that and I guess it's basically because interface and class are not matching when adding the annotation. But I also tried adding the annotation on my interfaces, which didn't help along to solve the problem, producing the same error as stated above.
Here's some example code from my project (BasicService, UserService and UserServiceImpl):
BasicService (Interface):
public interface BasicService<T> {
T findById(String id);
void create(T entity);
void delete(T entity);
void update(T entity);
}
UserService (Interface):
import net.dreamcode.bleevle.data.User;
public interface UserService extends BasicService<User> {
User findByName(String name);
}
UserServiceImpl (Class):
public class UserServiceImpl implements UserService {
#Autowired
UserDao userDao;
#Override
public User findByName(String name) {
return userDao.findByName(name);
}
#Override
public User findById(String id) {
return userDao.findById(id);
}
#Override
public void create(User entity) {
userDao.create(entity);
}
#Override
public void delete(User entity) {
userDao.delete(entity);
}
#Override
public void update(User entity) {
userDao.update(entity);
}
public UserDao getUserDao() {
return userDao;
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}
Is there a specific thing to do when working with this kind of pattern (I guess it's some kind of design pattern with Service and Dao stuff)?
Any kind of help is greatly appreciated. Thanks in advance!
You have a property
#Autowired private IntranetServiceImpl intranetService;
(or an equivalent thereof, such as an annotated constructor parameter or a setter) whose type is the implementation type of your service. This is wrong: you should always use the interface type for your properties.
The reason why it fails as soon, but no earlier than, you annotate with #Transactional is that this annotation causes Spring to create a dynamic proxy of your interface where otherwise there would be the naked implementation class instance. This dynamic proxy fails to be downcast into your implemantation type, but would be successfully cast into the interface type.
Related
I have inherited a Spring Java codebase where it seems pretty much every method from the business service down to the low level DAOs are tagged with #Transactional. It has some severe performance issues that I noticed are mitigated somewhat when certain annotations are changed from #Transactional(readOnly=false) to #Transactional(readOnly=true). It also seems to have periodic calls to EntityManager.flush() that can't be explained except that certain objects do not get written to the DB without them.
My hunch is that the original developers are misusing/overusing transactions, but I'm not sure of the best approach to clean this up. I would appreciate advice from those more well-versed in Spring Transactions than me.
A reduced example of just one segment of the code follows. There are others much more complex than this with 5-6 levels of nested transactions.
// MVC Controller REST Service
#Controller
#RequestMapping("/service")
public class Group {
#Inject private GroupService groupService;
public #ResponseBody Object update(#RequestBody Group group) {
return groupService.update(group);
}
}
// Business service
#Service
public class GroupService {
#Inject private GroupDAO groupDao;
#Inject private AuditService auditService;
#Transactional(readOnly=false)
public Group update(Group group) {
Group groupToUpdate = groupDao.get(group.getId());
// Do magic
groupDao.persist(groupToUpdate); // Shorthand to call EntityManager.persist()
auditService.logUpdate(group);
return groupToUpdate;
}
}
// DAO
#Repository
public class GroupDAO extends AbstractDAO {
#Transactional(readOnly=true)
public Group get(Long id) {
return entityManager.find(Group.class,id);
}
}
// Auditing service
#Component
public class AuditService {
#Inject AlertDAO alertDao;
#Transactional(readOnly=false)
public void logUpdate(Object o) {
Alert alert = alertDao.getFor(o);
// Do magic
alertDao.update(alert);
alertDao.flush() // Shorthand for EntityManager.flush() but WHY???
}
}
// DAO
#Repository
public class AlertDAO extends AbstractDAO {
#Transactional(readOnly=true)
public Alert getFor(Object forObj) {
// Magic here
return entityManager.find(Alert.class,foundId);
}
#Transactional(readOnly=false)
public void update(Alert a) {
// Magic here
entityManager.merge(a);
}
}
Given that the question is "how to clean up transaction annotations?" the answer would be - based on the above comments;
Do not use transaction annotations in DAOs, only in Services
(#Components)
Make sure DAOs are only called through the
service-layer.
I understand that interface in Java will have only skeleton or signature of methods. In below example interface does not have any method defined, but still the operations are being executed without any issue. Can anyone explain how does it work?
AlbumRepository interface extends from another one. It also should be having skeleton only no method definitions.
import org.cloudfoundry.samples.music.domain.Album;
import org.springframework.data.repository.CrudRepository;
#Repository
public interface AlbumRepository extends CrudRepository<Album, String> {
}
AlbumController , here the .save or .findall works perfectly. How does it work since the original interface methods are not defined anywhere.
public class AlbumController {
private AlbumRepository repository;
#Autowired
public AlbumController(AlbumRepository repository) {
this.repository = repository;
}
#ResponseBody
#RequestMapping(method = RequestMethod.GET)
public Iterable<Album> albums() {
return repository.findAll();
}
#ResponseBody
#RequestMapping(method = RequestMethod.PUT)
public Album add(#RequestBody #Valid Album album) {
logger.info("Adding album " + album.getId());
return repository.save(album);
}
}
I am new to Java hibernate and trying to understand how does it work. Sorry if I am missing anything...
Welcome to the magic of Spring Data.
You are correct that interfaces on their own don't do anything. However, here Spring Data JPA is automatically creating an implementation of that interface for you when you run the application.
I am newbie to spring and I face problem in Transaction.
I have created two Model as below:
UserDto - Stored user information
RoleDto - Stored user's role information
Service respected to both models are as below (both are annotated with #Transactional):
UserService - void saveUser(UserDto userDto) throws Exception;
RoleService - void saveRole(RoleDto roleDto) throws Exception;
now when user create account in the application at that time I called "add" method of the controller, which has the code snippet as below:
userService.saveUser(userDto);
roleService.saveRole(roleDto);
now in this code if exception occurred in Roleservice than it still insert user data into database table. but I want to rollback that too if roleService throws any exception. I tried to find the solution but could not get any good tutorial. any help will be appreciated.
The way you're calling the method makes each of it has its own transaction. Your code can be understood like this:
Transaction t1 = Spring.createTransaction();
t1.begin();
try {
//your first service method marked as #Transactional
userService.saveUser(userDto);
t1.commit();
} catch (Throwable t) {
t1.rollback();
} finally {
t1.close();
}
Transaction t2 = Spring.createTransaction();
t2.begin();
try {
//your second service method marked as #Transactional
roleService.saveRole(roleDto);
t2.commit();
} catch (Throwable t) {
t2.rollback();
} finally {
t2.close();
}
An option to solve this would be to create another service class where its implementation has RoleService and UserService injected, is marked as #Transactional and calls these two methods. In this way, both methods will share the same transaction used in this class:
public interface UserRoleService {
void saveUser(UserDto userDto, RoleDto roleDto);
}
#Service
#Transactional
public class UserRoleServiceImpl implements UserRoleService {
#Autowired
UserService userService;
#Autowired
RoleService roleService;
#Override
public void saveUser(UserDto userDto, RoleDto roleDto) {
userService.saveUser(userDto);
roleService.saveRole(roleDto);
}
}
A better design would be to make RoleDto a field of USerDto and that implementation of USerService has a RoleService field injected and perform the necessary calls to save each. Note that service classes must provide methods that contains business logic, this also means business logic rules. Service classes are not just wrappers for Dao classes.
This could be an implementation of the above explanation:
#Service
public class UserServiceImpl implements UserService {
#Autowired
RoleService roleService;
public void saveUSer(UserDto userDto) {
//code to save your userDto...
roleService.saveRole(userDto.getRoleDto());
}
}
I'm trying to create a simple REST service with JAX-RS (Jersey), without using Spring. I want to have the typical structure of: Resource, that use a Service (typical interface with method findById, findAll...), and that Service injected in the Resource.
It seems that CDI automatically scans beans and injects them (having a empty beans.xml in the project) but... it doesn't work for me.
This is my Resource class:
#Path("users")
#ManagedBean
public class UserController {
#Inject
private UserService userService;
#GET()
#Path("/{id}")
#Produces(MediaType.APPLICATION_JSON)
public User getUserById(#PathParam("id") Long id) {
return userService.findById(id);
}
}
And this is my Service and its impl class (it´s a mock...):
public interface UserService {
User findById(Long id);
List<User> findAll();
User save(User user);
User update(User user);
void delete(Long id);
}
public class UserServiceMock implements UserService {
// omitted constants
#Override
public User findById(Long id) {
return new User()
.setId(id)
.setName(NAME_GANDALF)
.setPhone(PHONE_666554433)
.setType(TYPE_1)
.setBirthDate(LocalDate.parse(STRING_DATE_19110102));
}
#Override
public List<User> findAll() {
return Arrays.asList(
new User()
.setId(USER_ID_12)
.setName(NAME_GANDALF)
.setPhone(PHONE_666554433)
.setType(TYPE_1)
.setBirthDate(LocalDate.parse(STRING_DATE_19110102)),
new User()
.setId(USER_ID_140)
.setName(NAME_ARAGORN)
.setPhone(PHONE_661534411)
.setType(TYPE_1)
.setBirthDate(LocalDate.parse(STRING_DATE_19230716)),
new User()
.setId(USER_ID_453321)
.setName(NAME_FRODO)
.setPhone(PHONE_666222211)
.setType(TYPE_2)
.setBirthDate(LocalDate.parse(STRING_DATE_19511124))
);
}
#Override
public User save(User user) {
return user.setId(USER_ID_453321);
}
#Override
public User update(User user) {
return user;
}
#Override
public void delete(Long id) {
// delete user by id
}
}
And I'm using a "no web.xml" configuration, with this class:
#ApplicationPath("api")
public class RestApplication extends ResourceConfig {
}
The only workaround I found is to "register" the service in the RestApplication class:
#ApplicationPath("api")
public class RestApplication extends ResourceConfig {
public RestApplication() {
register(UserController.class);
register(new AbstractBinder() {
#Override
protected void configure() {
bind(new UserServiceMock()).to(UserService.class);
}
});
}
}
Is there another solution to this problem? I'd rather not to register all my services and other stuff in this class manually...
I tried with annotations like #Default, #Qualifier and more (in the service), and no one works...
Tomcat is a servlet container only. It's not a full Java EE enterprise stack, nor does it contain a CDI container. Apache TomEE, on the other hand, is Tomcat with EE capabilities.
Bauke Scholtz, the infamous BalusC, wrote an excellent blog on installing CDI on Tomcat. This might help you. Otherwise, an alternative approach will be to install Apache TomEE and run your application from there. After all, it's still Tomcat anyway.
So I have a number of generics in Spring 3.2 and ideally my architecture would look something like this.
class GenericDao<T>{}
class GenericService<T, T_DAO extends GenericDao<T>>
{
// FAILS
#Autowired
T_DAO;
}
#Component
class Foo{}
#Repository
class FooDao extends GenericDao<Foo>{}
#Service
FooService extends GenericService<Foo, FooDao>{}
Unfortunately with multiple implementations of the generics the autowiring throws an error about multiple matching bean definitions. I assume this is because #Autowired processes before type erasure. Every solution I've found or come up with looks ugly to me or just inexplicably refuses to work. What is the best way around this problem?
How about adding a constructor to the GenericService and move the autowiring to the extending class, e.g.
class GenericService<T, T_DAO extends GenericDao<T>> {
private final T_DAO tDao;
GenericService(T_DAO tDao) {
this.tDao = tDao;
}
}
#Service
FooService extends GenericService<Foo, FooDao> {
#Autowired
FooService(FooDao fooDao) {
super(fooDao);
}
}
Update:
As of Spring 4.0 RC1, it is possible to autowire based on generic type, which means that you can write a generic service like
class GenericService<T, T_DAO extends GenericDao<T>> {
#Autowired
private T_DAO tDao;
}
and create multiple different Spring beans of it like:
#Service
class FooService extends GenericService<Foo, FooDao> {
}
Here is a closest solution. The specialized DAOs are annotated at the business layer. As in the question from OP, the best effort would be having an annotated DAO in the EntityDAO generic template itself. Type erasure seems to be not allowing the specialized type information to get passed onto the spring factories [resulting in reporting matching beans from all the specialized DAOs]
The Generic Entity DAO template
public class EntityDAO<T>
{
#Autowired
SessionFactory factory;
public Session getCurrentSession()
{
return factory.getCurrentSession();
}
public void create(T record)
{
getCurrentSession().save(record);
}
public void update(T record)
{
getCurrentSession().update(record);
}
public void delete(T record)
{
getCurrentSession().delete(record);
}
public void persist(T record)
{
getCurrentSession().saveOrUpdate(record);
}
public T get(Class<T> clazz, Integer id)
{
return (T) getCurrentSession().get(clazz, id);
}
}
The Generic Entity Based Business Layer Template
public abstract class EntityBusinessService<T>
implements Serializable
{
public abstract EntityDAO<T> getDAO();
//Rest of code.
}
An Example Specialized Entity DAO
#Transactional
#Repository
public class UserDAO
extends EntityDAO<User>
{
}
An Example Specialized Entity Business Class
#Transactional
#Service
#Scope("prototype")
public class UserBusinessService
extends EntityBusinessService<User>
{
#Autowired
UserDAO dao;
#Override
public EntityDAO<User> getDAO()
{
return dao;
}
//Rest of code
}
You can remove the #autowire annotation and perform delayed “autowire” using #PostConstruct and ServiceLocatorFactoryBean.
Your GenericService will look similar to this
public class GenericService<T, T_DAO extends GenericDao<T>>{
#Autowired
private DaoLocator daoLocatorFactoryBean;
//No need to autowried, autowireDao() will do this for you
T_DAO dao;
#SuppressWarnings("unchecked")
#PostConstruct
protected void autowireDao(){
//Read the actual class at run time
final Type type;
type = ((ParameterizedType) getClass().getGenericSuperclass())
.getActualTypeArguments()[1];
//figure out the class of the fully qualified class name
//this way you can know the bean name to look for
final String typeClass = type.toString();
String daoName = typeClass.substring(typeClass.lastIndexOf('.')+1
,typeClass.length());
daoName = Character.toLowerCase(daoName.charAt(0)) + daoName.substring(1);
this.dao = (T_DAO) daoLocatorFactoryBean.lookup(daoName);
}
daoLocatorFactoryBean does the magic for you.
In order to use it you need to add an interface similar to the one below:
public interface DaoLocator {
public GenericDao<?> lookup(String serviceName);
}
You need to add the following snippet to your applicationContext.xml
<bean id="daoLocatorFactoryBean"
class="org.springframework.beans.factory.config.ServiceLocatorFactoryBean">
<property name="serviceLocatorInterface"
value="org.haim.springframwork.stackoverflow.DaoLocator" />
</bean>
This is a nice trick and it will save you little boilerplate classes.
B.T.W I do not see this boilerplate code as a big issue and the project I working for uses matsev approach.
Why do you want a generic service ? Service classes are meant for specific units of work involving multple entities. You can just inject a repository straight into a controller.
Here is an example of generic repository with constructor argument, you could also make each method Generic instead and have no constructor argument. But each method call would require class as parameter:
public class DomainRepository<T> {
#Resource(name = "sessionFactory")
protected SessionFactory sessionFactory;
public DomainRepository(Class genericType) {
this.genericType = genericType;
}
#Transactional(readOnly = true)
public T get(final long id) {
return (T) sessionFactory.getCurrentSession().get(genericType, id);
}
Example of bean definition for the generic repository - you could have multple different beans, using different contstructor args.
<bean id="tagRepository" class="com.yourcompnay.data.DomainRepository">
<constructor-arg value="com.yourcompnay.domain.Tag"/>
</bean>
Depdncy injection of bean using resource annotation
#Resource(name = "tagRepository")
private DomainRepository<Tag> tagRepository;
And this allows the Domainreposiroty to be subclassed for specific entities/methods, which woul dallow autowiring :
public class PersonRepository extends DomainRepository<Person> {
public PersonRepository(){
super(Person.class);
}
...
You should use autowiring in classes which extends these generics
For this question one needs to understand about what autowire is. In common terms we can say that through autowire we create a object instance/bean at the time of deployment of the web app. So now going with the question if you are declaring autowiring in multiple places with the same name. Then this error comes. Autowiring can be done in multiple ways so if you are using multiple type of autowiring technique, then also one could get this error.
Complete Generic Solution using Spring 4:
Domain Class
#Component
class Foo{
}
#Component
class Bar{
}
DAO Layer
interface GenericDao<T>{
//list of methods
}
class GenericDaoImpl<T> implements GenericDao<T>{
#Autowired
SessionFactory factory;
private Class<T> domainClass; // Get Class Type of <T>
public Session getCurrentSession(){
return factory.getCurrentSession();
}
public DaoImpl() {
this.domainClass = (Class<T>) GenericTypeResolver.resolveTypeArgument(getClass(), DaoImpl.class);
}
//implementation of methods
}
interface FooDao extends GenericDao<Foo>{
//Define extra methods if required
}
interface BarDao extends GenericDao<Bar>{
//Define extra methods if required
}
#Repository
class FooDao extends GenericDaoImpl<Foo> implements FooDao{
//implementation of extra methods
}
#Repository
class BarDao extends GenericDaoImpl<Bar> implements BarDao{
//implementation of extra methods
}
Service Layer
interface GenericService<T>{
//List of methods
}
class GenericServiceImpl<T> implements GenericService<T>{
#Autowire
protected GenericDao<T> dao; //used to access DAO layer
}
class FooService extends GenericService<Foo>{
//Add extra methods of required
}
class BarService extends GenericService<Bar>{
//Add extra methods of required
}
#Service
class FooServiceImpl extends GenericServiceImpl<Foo> implements GenericService<Foo>{
//implementation of extra methods
}
#Service
class BarServiceImpl extends GenericServiceImpl<Bar> implements GenericService<Bar>{
//implementation of extra methods
}