The project I am working on has a similar structure for the DAOs to the one bellow:
/**
* Base DAO class
*/
#Transactional
public class JPABase {
#PersistenceContext
private EntityManager entityManager;
public void persist(Object entity) {
entityManager.persist(entity);
}
//some more methods in here
}
and
/**
* Generic DAO class implementation
*/
#Transactional
public abstract class GenericDao extends JpaBase {
//some methods in here
}
and
/**
* Specialized DAO class
*/
#Repository
#Transactional
public class PersonDao extends GenericDao {
//some methods in here
}
Until now, the project used compile time weaving, but the configuration has changed to use <context:load-time-weaver/> with -javaagent:/opt/tomcat7-1/lib/spring-instrument.jar.
Since this change has been applied, the JpaBase's and GenericDao's #Transactional annotations are not weaved anymore. Each time a service class calls the persist method on a PersonDao object, no transaction is started.
Noteworthy:
this used to work in the past, when using compile time weaving.
all the methods that are defined in the PersonDao are weaved correctly, but the ones inherited (e.g. persist(Object entity)) are NOT weaved.
Compile time weaving and load time weaving are supposed to do the same thing, just at different moments in time. Why has the weaving behaviour changed?
Tomcat default classlLoader is WebappClassLoader, but you need `TomcatInstrumentableClassLoader.
There are two solutions:
Modify WebappLoader.class
Change WebappLoader.java
private String loaderClass = "org.apache.catalina.loader.WebappClassLoader";
Replaceļ¼
private String loaderClass = "org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader";
Compile it and replaced the class file(catalina.jar), then it works.
Here is required dependency jars: catalina.jar,tomcat-coyote.jar,tomcat-util.jar(/bin),tomcat-juli.jar
Modify context.xml:
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<Loader loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader"/>
</Context>
You probably missing the public constructor chaining inside these classes, #Transactional will work only if classes are having public constructors and public methods.
Related
It seems to be a simple question but yet i couldn't find clear answer while searching documentation and forums. I'm migrating from xml to java-based config (Spring 5.1.9). Due to some legacy restrictions in xml config i need to create a bean from some side library's non public class:
SampleClass.class
package side.library
class SampleClass {
//... some code here
}
context.xml
...
<bean id = "sampleId" class "side.library.SampleClass">
...
And this works fine since Spring uses reflection inside and it creates bean without any problems at compile/runtime, but in java-based config usage of such class leads to an access error:
package my.configuration;
import side.library.SampleClass; // 'side.library.SampleClass' is not public in 'side.library'. Cannot be accessed from outside package
#Configuration
public class JavaConfiguration{
#Bean
public SampleClass sampleClass() {
return new SampleClass(); // same error text
}
}
So, what is the proper way to deal with this sutiation? Using reflection libs in #Configuration class to reach this class seems to be a bad idea.
just a workaround: create a wrapper class in the outer project in the same package and use this class in your configuration.
package com.legacy;
public class Wrapper {
private LegacyImpl legacyImpl;
public Wrapper()
this.legacyImpl = new LegacyImpl();
}
public void wrappedMethod() {
this.legacyImpl.wrappedMethod();
}
}
I have a projected checked into GitHub here
https://github.com/romeoopk/demo
Please note that this is not a "complete" working project but in progress!
I have two data sources (h2 mem DB and Cassandra)
The aim of the project is to hide the implementation behind the Service.
there are two profiles I am looking against
dev - goes against h2
test - goes against Cassandra
when I run against test, it runs fine as expected but when I run against dev, I get the following message
Parameter 0 of constructor in com.example.demo.service.H2HotelServiceImpl required a bean of type 'com.example.demo.repository.HotelRepository' that could not be found.
Action:
Consider defining a bean of type 'com.example.demo.repository.HotelRepository' in your configuration.
I am unsure, how to have a proper injection so that the H2HotelRepository and H2HotelByLetterRepository get used for querying towards H2
any help is highly appreciated!!!
Your repository classes under cassandra folder is like this
#Repository
#Profile("test")
public class CassandraHotelRepository implements HotelRepository<Hotel> {
....
}
#Repository
#Profile("test")
public class CassandraHotelByLetterRepository implements HotelByLetterRepository<HotelByLetter, HotelByLetterKey> {
....
}
But in your h2 folder you have declared as
#Repository
#Profile("dev")
public abstract class H2HotelRepository implements CrudRepository<Hotel, String>, HotelRepository<Hotel> {
...
}
#Repository
#Profile("dev")
public abstract class H2HotelByLetterRepository implements CrudRepository<HotelByLetter, HotelByLetterKey>, HotelByLetterRepository<HotelByLetter, HotelByLetterKey> {
.....
}
As you can clearly see in h2 folder i.e. for profile dev, there is no concrete class. Both of your repositories under h2 are abstract.
Remove abstract and it should work fine.
Is it possible to have a bean interface in a project and the implementation of that bean in another project that includes the previous project as a dependency?
I have the following interface:
package com.proj1.util;
import .....;
public interface Notification {
addNotification();
addError();
}
In the same project (i.e. Proj1) I have also the following class:
package com.proj1.util.exception;
import .....;
public class ExceptionHandler extends RuntimeException ... {
private String errorMessage;
#Override
public void handle() {
Util.getBeanInstance(Notification.class).addError(errorMessage);
}
}
Now in the second project I have the actual implementation of Notification that is as follows:
package com.proj2.beans;
#Named
#ConversationScoped
public class NotificationBean implements Notification, Serializable {
private static final long serialVersionUID = 1L;
...
}
This situation leads to an exception in Tomcat with the message "WebBeans context with scope type annotation #ConversationScoped does not exist within current thread"
My proposal was to add a Factory that produces my NotificationBean but it doesn't seem to change much.
package com.proj2.beans.cdi;
import javax.enterprise.inject.New;
import javax.enterprise.inject.Produces;
import com.proj1.util.Notification;
public class NotificationBeanFactory {
#Produces
public Notification create(#New NotificationBean notificationBean) {
return notificationBean;
}
}
The question is how can I use a bean in a project in which I have only it's interface while the bean implementation is in another project. Is it possible?
The exception suggests there is no running conversation so I would start by determining when do you attempt to use #ConversationScoped bean and from which class.
Your code pieces indicate that ExceptionHandler class calls a magical formula which we do not know anything else about:
Util.getBeanInstance(Notification.class).add(...);
Trying to use this when there is no active conversation might lead to the exception you see. Therefore you could #Inject ExceptionHandler into NotificationBean so that you only ever use it while there is active conversation.
As for the Weld question regarding interface and impl in different projects; it is possible. in your proj2 Weld will simply identify a bean NotificationBean and amongst it's types there will also be Notification hence you can then #Inject Notification.
It might not work the other way round though - in proj1 you cannot #Inject Notification because proj1 itself does not have any bean which would implement that interface.
Imagine the following:
#MyAnnotation
public class A { ... };
#MyOtherAnnotation
public class B { ... };
If a class is annotated with #MyAnnotation, an extra #MyExtraAnnotation should be added before annotation processing. So, after that step, we should have:
#MyExtraAnnotation
#MyAnnotation
public class A { ... };
#MyOtherAnnotation
public class B { ... };
Is this possible? If yes how? Thanks.
You should look at the process-sources phase of the lifecycle, or possibly the annotationProcessors configuration of the maven compiler plugin.
I've not found a plugin that "adds annotations", but is certainly should be possible to create one to do just that.
In my project there's a common base class that all client classes extend. This has an #Autowired field that needs to be injected by Hibernate. These are all grouped together in another class that has an #Autowired collection of the base class.
In order to reduce boilerplate for client code I'm trying to get #Component inherited. With #Component not doing this by default (apparently it used to though), I created this workaround annotation
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
#Component
#Inherited
public #interface InheritedComponent {
}
... and annotated the base class with it. Its not pretty but I hoped it would work. Unfortunately it didn't, which really confuses me as #Inherited should make it work
Is there any other way to get #Component inherited? Or do I just have to say that any class that extends the base class needs this boilerplate?
The problem is that the Component annotation type itself needs to be marked with #Inherited.
Your #InheritedComponent annotation type is correctly inherited by any classes that extend a superclass which is marked with #InheritedComponent - but it does not inherit #Component. This is because you have #Component on the annotation, not the parent type.
An example:
public class InheritedAnnotationTest {
#InheritedComponent
public static class BaseComponent {
}
public static class SubClass extends BaseComponent {
}
public static void main(String[] args) {
SubClass s = new SubClass();
for (Annotation a : s.getClass().getAnnotations()) {
System.out.printf("%s has annotation %s\n", s.getClass(), a);
}
}
}
Output:
class brown.annotations.InheritedAnnotationTest$SubClass has annotation #brown.annotations.InheritedComponent()
In other words, when resolving what annotations a class has, the annotations of the annotations are not resolved - they do not apply to the class, only the annotation (if that makes sense).
I've dealt with this issue by creating my own annotation (heritable) and then customizing classpath scanning:
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
#Component
#Inherited
public #interface BusinessService {
}
Spring configuration look likes this:
<context:component-scan base-package="io.bar">
<context:include-filter type="annotation"
expression="io.bar.core.annotations.BusinessService" />
</context:component-scan>
from Spring doc 5.10.3 Using filters to customize scanning