Spring equivalent for CDI Instance - spring

I am new to Spring and i need to convert a CDI class to Spring.
I have the below code in CDI
#Inject
private Instance<HealthCheck> healthChecks;
I then iterate over healthChecks.
I found a similar question What is the Spring equivalent for CDI's Instance, or Guices Provider , where it was advised to use
#Inject
Provider<MyObject> myObjectInstance;
//...
MyObject myObjectInstance.get();
However, since provider does not implements iterable, I am not able to iterate.
Can someone please help me on how can I convert the CDI code block to spring.

create a new file spring.factories inside META-INF with following content:
org.springframework.context.ApplicationContextInitializer=package_name.CustomApplicationContextInitializer
or you can use it in your junit test like:
#SpringApplicationConfiguration(initializers = CustomApplicationContextInitializer.class)
And now you can use like:
#Autowired
private Instance<HealthCheck> healthChecks;
CustomApplicationContextInitializer.class
public class CustomApplicationContextInitializer implements
ApplicationContextInitializer<ConfigurableApplicationContext> {
#Override
public void initialize(ConfigurableApplicationContext applicationContext) {
// Configure custom CustomAutowireCandidateResolver to handle CDI
// Instance<T> dependency requests
DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) applicationContext.getBeanFactory();
beanFactory.setAutowireCandidateResolver(new CustomAutowireCandidateResolver());
}
}
CustomAutowireCandidateResolver.class
import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.annotation.Priority;
import javax.enterprise.inject.Instance;
import javax.enterprise.util.TypeLiteral;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.config.DependencyDescriptor;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ContextAnnotationAutowireCandidateResolver;
import org.springframework.core.annotation.Order;
import org.springframework.util.ClassUtils;
public class CustomAutowireCandidateResolver extends ContextAnnotationAutowireCandidateResolver {
static final boolean IS_CDI_INSTANCE_CLASS_PRESENT = ClassUtils.isPresent("javax.enterprise.inject.Instance", null);
#Override
public Object getLazyResolutionProxyIfNecessary(DependencyDescriptor descriptor, String beanName) {
if (IS_CDI_INSTANCE_CLASS_PRESENT && Instance.class.equals(descriptor.getDependencyType())) {
// TODO refactor getLazyResolutionProxyIfNecessary to allow to
// customize lazy dependency resolution for Instance<T>
return getInstanceAdapterFor(descriptor);
}
return super.getLazyResolutionProxyIfNecessary(descriptor, beanName);
}
#SuppressWarnings({ "unchecked", "rawtypes" })
private Object getInstanceAdapterFor(DependencyDescriptor descriptor) {
ListableBeanFactory listableBeanFactory = (ListableBeanFactory) getBeanFactory();
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) listableBeanFactory;
// Instance<TargetType>
Class targetType = descriptor.getResolvableType().getGeneric(0).getRawClass();
Map<String, Object> beansOfType = listableBeanFactory.getBeansOfType(targetType);
List<Bean> beansInstances = beansOfType.entrySet().stream() //
.map(e -> new Bean(e.getValue(), registry.getBeanDefinition(e.getKey()).isPrimary()))//
.collect(Collectors.toList());
Annotation[] qualifiers = retainQualifierAnnotations(descriptor.getAnnotations());
Beans beans = new Beans(targetType, beansInstances);
return qualifiers.length == 0 ? beans : beans.select(qualifiers);
}
private Annotation[] retainQualifierAnnotations(Annotation[] annotations) {
return Arrays.stream(annotations) //
.filter(a -> a.annotationType().isAnnotationPresent(Qualifier.class)) //
.toArray(Annotation[]::new);
}
static class Beans<T> implements Instance<T> {
private final List<Bean> beans;
private final Class<?> type;
public Beans(Class<?> type, List<Bean> beans) {
this.type = type;
this.beans = beans;
}
protected List<Bean> getBeans() {
return beans;
}
#Override
public T get() {
return (T) findDefaultInstance();
}
protected Object findDefaultInstance() {
List<Bean> beans = getBeans();
if (beans.size() == 1) {
return beans.get(0).getInstance();
}
Object highestPrioBean = returnPrimaryOrHighestPriorityBean(beans);
if (highestPrioBean != null) {
return highestPrioBean;
}
// TODO figure out a sane default to use here - maybe throw an
// exception?
return beans.get(0).getInstance();
}
private Object returnPrimaryOrHighestPriorityBean(List<Bean> beans) {
long highestPriority = Integer.MIN_VALUE;
Object highestPrioBean = null;
for (Bean bean : beans) {
if (bean.isPrimary()) {
return bean.getInstance();
}
// TODO figure out to retrieve order from BeanDefinition /
// BeanDeclaration
Object instance = bean.getInstance();
Order order = instance.getClass().getAnnotation(Order.class);
if (order != null) {
if (order.value() > highestPriority) {
highestPriority = order.value();
highestPrioBean = instance;
}
}
Priority priority = instance.getClass().getAnnotation(Priority.class);
if (priority != null) {
if (priority.value() > highestPriority) {
highestPriority = priority.value();
highestPrioBean = instance;
}
}
}
return highestPrioBean;
}
#Override
#SuppressWarnings("unchecked")
public Instance<T> select(Annotation... qualifiers) {
return select((Class<T>) type, qualifiers);
}
#Override
public <U extends T> Instance<U> select(Class<U> subtype, Annotation... qualifiers) {
return new Beans<U>(subtype, filterBeans(subtype, qualifiers));
}
protected List<Bean> filterBeans(Class<?> subtype, Annotation... qualifiers) {
List<Annotation> requiredQualifiers = Arrays.asList(qualifiers);
return getBeans().stream() //
.filter(bean -> subtype.isInstance(bean.getInstance())) //
.filter(bean -> bean.getAnnotations().containsAll(requiredQualifiers)) //
.collect(Collectors.toList());
}
#Override
public <U extends T> Instance<U> select(TypeLiteral<U> subtype, Annotation... qualifiers) {
// TODO implement (Class<U> subtype, Annotation... qualifiers) via
// select(TypeLiteral<U> subtype, Annotation... qualifiers)
return select(subtype.getRawType(), qualifiers);
}
#Override
public Iterator<T> iterator() {
return getBeans().stream().map(bean -> (T) bean.getInstance()).iterator();
}
#Override
public boolean isUnsatisfied() {
return getBeans().isEmpty();
}
#Override
public boolean isAmbiguous() {
return getBeans().size() > 1;
}
#Override
public void destroy(Object bean) {
if (bean instanceof DisposableBean) {
try {
((DisposableBean) bean).destroy();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
}
static class Bean {
private final boolean primary;
private final Object instance;
private final List<Annotation> annotations;
public Bean(Object instance, boolean primary) {
this.primary = primary;
this.instance = instance;
this.annotations = Arrays.asList(instance.getClass().getAnnotations());
}
public Object getInstance() {
return instance;
}
public boolean isPrimary() {
return primary;
}
public List<Annotation> getAnnotations() {
return annotations;
}
}
}
here is full source link: https://github.com/thomasdarimont/spring-boot-cdi-instance-example

Related

Can not configuring a Global Date and Time Format

I wrote a DateTimeFormatAnnotationFormatterFactory to use for global conversion of LocalDateTime, imitating LocalDateTimeFormatAnnotationFormatterFactory
package com.taimi.localdatetimedemo.format.date;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import org.springframework.format.AnnotationFormatterFactory;
import org.springframework.format.Formatter;
import org.springframework.format.Parser;
import org.springframework.format.Printer;
/**
* LocalDateTimeFormatAnnotationFormatterFactory
*/
public class LocalDateTimeFormatAnnotationFormatterFactory implements AnnotationFormatterFactory<LocalDateTimeFormat> {
private static final Set<Class<?>> FIELD_TYPES;
static {
Set<Class<?>> fieldTypes = new HashSet<>(1);
fieldTypes.add(LocalDateTime.class);
FIELD_TYPES = Collections.unmodifiableSet(fieldTypes);
}
#Override
public Set<Class<?>> getFieldTypes() {
return FIELD_TYPES;
}
#Override
public Printer<?> getPrinter(LocalDateTimeFormat annotation, Class<?> fieldType) {
return getFormatter(annotation, fieldType);
}
#Override
public Parser<?> getParser(LocalDateTimeFormat annotation, Class<?> fieldType) {
return getFormatter(annotation, fieldType);
}
protected Formatter<LocalDateTime> getFormatter(LocalDateTimeFormat annotation, Class<?> fieldType) {
LocalDateTimeFormater localDateTimeFormater=new LocalDateTimeFormater(annotation.pattern());
return localDateTimeFormater;
}
}
public #interface LocalDateTimeFormat {
String pattern() default "";
}
package com.taimi.localdatetimedemo.format.date;
import java.text.ParseException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
import org.springframework.format.Formatter;
import org.springframework.util.StringUtils;
/**
* LocalDateFormater
*/
public class LocalDateTimeFormater implements Formatter<LocalDateTime> {
private String pattern;
public LocalDateTimeFormater(String pattern) {
if (StringUtils.isEmpty(pattern)) {
throw new IllegalArgumentException("Pattern can't be empty.", null);
}
this.pattern = pattern;
}
#Override
public String print(LocalDateTime localDateTime, Locale locale) {
return createDateTimeFormatter(locale).format(localDateTime);
}
#Override
public LocalDateTime parse(String text, Locale locale) throws ParseException {
return LocalDateTime.parse(text, createDateTimeFormatter(locale));
}
private DateTimeFormatter createDateTimeFormatter(Locale locale) {
return DateTimeFormatter.ofPattern(pattern, locale);
}
}
The configuration is
#Configuration
public class TimeConfig extends WebMvcConfigurationSupport {
#Override
public FormattingConversionService mvcConversionService() {
// DefaultFormattingConversionService conversionService = new DefaultFormattingConversionService(false);
FormattingConversionService conversionService=new FormattingConversionService();
conversionService.addFormatterForFieldAnnotation(new LocalDateTimeFormatAnnotationFormatterFactory());
return conversionService;
}
}
But it always failed in conversion because converterCache can not find a suitable converter or is empty.
The source code of finding converter is showing down below from GenericConversionService
#Nullable
protected GenericConverter getConverter(TypeDescriptor sourceType, TypeDescriptor targetType) {
ConverterCacheKey key = new ConverterCacheKey(sourceType, targetType);
GenericConverter converter = this.converterCache.get(key);
if (converter != null) {
return (converter != NO_MATCH ? converter : null);
}
converter = this.converters.find(sourceType, targetType);
if (converter == null) {
converter = getDefaultConverter(sourceType, targetType);
}
if (converter != null) {
this.converterCache.put(key, converter);
return converter;
}
this.converterCache.put(key, NO_MATCH);
return null;
}
I've found out where I was wrong, the #Interface should be
#Target(ElementType.FIELD)
#Retention(RetentionPolicy.RUNTIME)
public #interface LocalDateTimeFormat {
String pattern() default "";
}

SpringBootTest not loading applicationcontext when overriding its value dynamically

I ma using #SpringBootTest for my IT and what I want to do is load a new ApplicationContext for every IT. For this I am overriding the SpringBootTest annotation dynamically and I am providing the same value for classes. But its throwing an exception saying could not load ApplicationContext. Is there an issue if we override the impl for SpringBootTest?
#RunWith(SpringRunner.class)
#ActiveProfiles("test")
#Slf4j
public abstract class OrchestratorBootIT extends BaseIT {
private static final String ANNOTATIONS = "annotations";
public static final String ANNOTATION_DATA = "annotationData";
public static Class<? extends OrchestratorBootIT> runningTestClassType;
public OrchestratorBootIT() {
if(runningTestClassType != null) return;
StepsConfigDAOCacheIT.class.toString());
try {
SpringBootTest annotation = StepsConfigDAOCacheIT.class.getAnnotation(SpringBootTest.class);
//In JDK8 Class has a private method called annotationData().
//We first need to invoke it to obtain a reference to AnnotationData class which is a private class
Method method = Class.class.getDeclaredMethod(ANNOTATION_DATA, null);
method.setAccessible(true);
//Since AnnotationData is a private class we cannot create a direct reference to it. We will have to
//manage with just Object
Object annotationData = method.invoke(StepsConfigDAOCacheIT.class);
//We now look for the map called "annotations" within AnnotationData object.
Field annotations = annotationData.getClass().getDeclaredField(ANNOTATIONS);
annotations.setAccessible(true);
Map<Class<? extends Annotation>, Annotation> map =
(Map<Class<? extends Annotation>, Annotation>) annotations.get(annotationData);
map.put(SpringBootTest.class, new SpringBootTestImpl());
SpringBootTest annotation1 = StepsConfigDAOCacheIT.class.getAnnotation(SpringBootTest.class);
log.info("test");
} catch (Exception e) {
e.printStackTrace();
}
}
#BeforeClass
public static void beforeClass() {
BaseIT.beforeClass();
}
#AfterClass
public static void afterClass() {
runningTestClassType = null;
}
#After
public void cleanup() {
super.cleanup();
}
private boolean setDynamicSpringBootTestAnnotation(final Object annotationData) throws Exception {
Field annotations = annotationData.getClass().getDeclaredField("annotations");
annotations.setAccessible(true);
Map<Class<? extends Annotation>, Annotation> map = (Map<Class<? extends Annotation>, Annotation>) annotations.get(annotationData);
map.put(SpringBootTest.class, getSpringBootTest());
return true;
}
protected SpringBootTest getSpringBootTest() {
return new SpringBootTestImpl();
}
static class SpringBootTestImpl implements SpringBootTest {
#Override
public String[] value() {
return new String[0];
}
#Override
public String[] properties() {
return new String[0];
}
#Override
public Class<?>[] classes() {
return new Class[] {CacheConfig.class};
}
#Override
public WebEnvironment webEnvironment() {
return WebEnvironment.MOCK;
}
#Override
public Class<? extends Annotation> annotationType() {
return SpringBootTestImpl.class;
}
}

Spring boot configure MessageInterpolator #Bean

I am using Spring boot v1.4 and hibernate v4.3.5.finall in my application
I have writen my own ResourceBundle and MessageInterpolator to save messages in database and have configured them as bean in my project. It seems ResourceBundle works fine and returns my custom message but parameters don't pass,for example for this validation :
#Size(min=5,max = 10)
private String lastName;
I expect : size must be between 5 and 10 bla bla.....
but the result is : size must be between {min} and {max} bla bla.....
any Idea? Thanks..
my ResourceBundle class:
package ir.pt.core.bundles;
import ir.pt.common.bean.ResourceEntity;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import java.io.IOException;
import java.util.*;
public class DatabaseResourceBundle extends ResourceBundle {
#PersistenceContext
protected EntityManager em;
private Map<String, String> cache = new HashMap<String, String>();
protected final static String BUNDLE_NAME = "ir.pt.core.bundles";
protected Control DB_CONTROL = new DBControl();
public DatabaseResourceBundle() {
setParent(ResourceBundle.getBundle(BUNDLE_NAME, DB_CONTROL));
}
public DatabaseResourceBundle(Locale locale) {
setParent(ResourceBundle.getBundle(BUNDLE_NAME, locale, DB_CONTROL));
}
#Override
protected Object handleGetObject(String key) {
return cache != null ? cache.get(key) : parent.getObject(key);
}
#Override
public Enumeration<String> getKeys() {
return parent.getKeys();
}
protected class DBControl extends Control {
#Override
public ResourceBundle newBundle(String baseName, Locale locale, String format, ClassLoader loader, boolean reload)
throws IllegalAccessException, InstantiationException, IOException {
return new CustomizedLocaleResources(locale);
}
protected class CustomizedLocaleResources extends ListResourceBundle {
private Locale locale;
public CustomizedLocaleResources(Locale locale) {
this.locale = locale;
}
#Override
protected Object[][] getContents() {
String sql = "FROM ResourceEntity re WHERE re.locale = '"+locale.getLanguage()+"'";
TypedQuery<ResourceEntity> query =
em.createQuery(sql, ResourceEntity.class);
List<ResourceEntity> resources = query.getResultList();
Object[][] all = new Object[resources.size()][2];
int i = 0;
for (Iterator<ResourceEntity> it = resources.iterator(); it.hasNext();) {
ResourceEntity resource = it.next();
all[i] = new Object[]{resource.getKey(), resource.getMessage()};
cache.put(resource.getKey(), resource.getMessage());
i++;
}
return all;
}
}
}
}
my MessageInterpolator class:
package ir.pt.core.bundles;
import org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator;
import org.springframework.beans.factory.annotation.Autowired;
import javax.validation.MessageInterpolator;
import java.util.Locale;
import java.util.Map;
public class DatabaseMessageInterpolator extends ResourceBundleMessageInterpolator implements MessageInterpolator{
protected final String BRACE_OPEN = "\\{";
protected final String BRACE_CLOSE = "\\}";
#Autowired
DatabaseResourceBundle databaseResourceBundle;
#Override
public String interpolate(String message, Context context) {
return interpolate(message, context, databaseResourceBundle.getLocale());
}
#Override
public String interpolate(String message, Context context, Locale locale) {
String messageKey = context.getConstraintDescriptor().getAttributes().get("message").toString();
message = databaseResourceBundle.getString(messageKey.replaceAll(BRACE_OPEN, "").replaceAll(BRACE_CLOSE, ""));
Map<String, Object> attributes = context.getConstraintDescriptor().getAttributes();
for (String key : attributes.keySet()) {
String value = attributes.get(key).toString();
key = BRACE_OPEN + key + BRACE_CLOSE;
message = message.replaceAll(key, value);
}
return message;
}
}
my bean configuration:
#Configuration
#EnableWebMvc
public class WebConfig extends WebMvcConfigurationSupport {
#Override
public Validator getValidator() {
LocalValidatorFactoryBean factory = new LocalValidatorFactoryBean();
factory.setMessageInterpolator(messageInterpolator());
return factory;
}
#Bean
public MessageInterpolator messageInterpolator() {
return new DatabaseMessageInterpolator();
}
#Bean
ResourceBundle resourceBundle() {
return new DatabaseResourceBundle(new Locale("fa"));
}
}

Spring/JSF2 and #ViewScoped

I want to use spring managed beans for my JSF2 controllers so that autowiring works. I know that there is no #ViewScoped in spring and I know a few implementations of #ViewScoped floating around various blogs (one from the primefaces lead).
Is any of them used in a real application and considered stable? Maybe one of them is recommended or widely used and I'm just not able to find it.
There is one :) Without memory leaks and with #PreDestroy support. Tested in production. Here.
package org.nkey.primefaces.scopes.test.spring.scope;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.config.Scope;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.faces.event.PreDestroyViewMapEvent;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionBindingListener;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
/**
* #author m.nikolaev Date: 21.11.12 Time: 0:37
*/
public class ViewScope implements Scope, Serializable, HttpSessionBindingListener {
private static final Logger LOGGER = LoggerFactory.getLogger(ViewScope.class);
private final WeakHashMap<HttpSession, Set<ViewScopeViewMapListener>> sessionToListeners = new WeakHashMap<>();
#Override
public Object get(String name, ObjectFactory objectFactory) {
Map<String, Object> viewMap = FacesContext.getCurrentInstance().getViewRoot().getViewMap();
//noinspection SynchronizationOnLocalVariableOrMethodParameter
synchronized (viewMap) {
if (viewMap.containsKey(name)) {
return viewMap.get(name);
} else {
LOGGER.debug("Creating bean {}", name);
Object object = objectFactory.getObject();
viewMap.put(name, object);
return object;
}
}
}
#Override
public Object remove(String name) {
throw new UnsupportedOperationException();
}
#Override
public String getConversationId() {
return null;
}
#Override
public void registerDestructionCallback(String name, Runnable callback) {
LOGGER.debug("registerDestructionCallback for bean {}", name);
UIViewRoot viewRoot = FacesContext.getCurrentInstance().getViewRoot();
ViewScopeViewMapListener listener =
new ViewScopeViewMapListener(viewRoot, name, callback, this);
viewRoot.subscribeToViewEvent(PreDestroyViewMapEvent.class, listener);
HttpSession httpSession = (HttpSession) FacesContext.getCurrentInstance().getExternalContext().getSession(true);
final Set<ViewScopeViewMapListener> sessionListeners;
synchronized (sessionToListeners) {
if (!sessionToListeners.containsKey(httpSession)) {
sessionToListeners.put(httpSession, new HashSet<ViewScopeViewMapListener>());
}
sessionListeners = sessionToListeners.get(httpSession);
}
//noinspection SynchronizationOnLocalVariableOrMethodParameter
synchronized (sessionListeners) {
Set<ViewScopeViewMapListener> toRemove = new HashSet<>();
for (ViewScopeViewMapListener viewMapListener : sessionListeners) {
if (viewMapListener.checkRoot()) {
toRemove.add(viewMapListener);
}
}
sessionListeners.removeAll(toRemove);
sessionListeners.add(listener);
}
if (!FacesContext.getCurrentInstance().getExternalContext().getSessionMap().containsKey("sessionBindingListener")) {
FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put("sessionBindingListener", this);
}
}
#Override
public Object resolveContextualObject(String key) {
return null;
}
#Override
public void valueBound(HttpSessionBindingEvent event) {
LOGGER.debug("Session event bound {}", event.getName());
}
#Override
public void valueUnbound(HttpSessionBindingEvent event) {
LOGGER.debug("Session event unbound {}", event.getName());
final Set<ViewScopeViewMapListener> listeners;
synchronized (sessionToListeners) {
if (sessionToListeners.containsKey(event.getSession())) {
listeners = sessionToListeners.get(event.getSession());
sessionToListeners.remove(event.getSession());
} else {
listeners = null;
}
}
if (listeners != null) {
for (ViewScopeViewMapListener listener : listeners) {
listener.doCallback();
}
}
}
public void clearFromListener(ViewScopeViewMapListener listener) {
LOGGER.debug("Removing listener from map");
HttpSession httpSession = (HttpSession) FacesContext.getCurrentInstance().getExternalContext().getSession(false);
if (httpSession != null) {
synchronized (sessionToListeners) {
if (sessionToListeners.containsKey(httpSession)) {
sessionToListeners.get(httpSession).remove(listener);
}
}
}
}
}

hibernate-envers RevisionListener spring integration as spring bean

I need to do some database processing in revision listener of hibernate-envers. For that I need inejction capabilities of Spring Framework. How can this be implemented? Here is the code representing the need but CustomRevisionListener is instantiated by a constructor in Envers code. Spring has only SecurityContextHolder as static service locator. How to inject other beans?
#Service
public class CustomRevisionListener implements EntityTrackingRevisionListener {
#Resource
private PersistenceManagerHibernate persistenceManagerHibernate;
public void newRevision(Object revisionEntity) {
CustomRevisionEntity revision = (CustomRevisionEntity) revisionEntity;
revision.setUsername(getUsername());
}
public String getUsername() {
final SecurityContext context = SecurityContextHolder.getContext();
if (context != null) {
if (context.getAuthentication() != null) {
return context.getAuthentication().getName();
} else {
return "anonymous";
}
}
return "anonymous";
}
#Override
public void entityChanged(#SuppressWarnings("rawtypes") Class entityClass, String entityName, Serializable entityId, RevisionType revisionType, Object revisionEntity) {
CustomRevisionEntity revision = (CustomRevisionEntity) revisionEntity;
revision.setEntityId(entityId.toString());
revision.setEntityName(entityName);
revision.setRevisionType((int)revisionType.getRepresentation());
Auditable auditable = null;
if (entityId instanceof Long) {
auditable = persistenceManagerHibernate.findById(entityClass, (Long)entityId);
}
revision.setGroupName(auditable.getAuditGroupName());
revision.setGroupEntityId(auditable.getAuditGroupId());
}
}
Since CustomRevisionListener is instantiated by a constructor in Envers, you have to find another way to retrieve a handle to a Spring managed bean.
You could create a utility class to achieve this:
/**
* Utility class which provides lookup services for Spring managed beans from
* within unmanaged beans.
*/
#Component
public class ContextLookup implements ApplicationContextAware {
private static ApplicationContext sApplicationContext;
#Override
public void setApplicationContext( ApplicationContext aApplicationContext )
throws BeansException {
setContext( aApplicationContext );
}
public static void setContext( ApplicationContext aApplicationContext ) {
sApplicationContext = aApplicationContext;
}
protected static ApplicationContext getApplicationContext() {
return sApplicationContext;
}
public static Object getBean( String aName ) {
if ( sApplicationContext != null ) {
return sApplicationContext.getBean( aName );
}
return null;
}
public static <T> T getBean( Class<T> aClass ) {
if ( sApplicationContext != null ) {
return sApplicationContext.getBean( aClass );
}
return null;
}
}
and in your CustomRevisionListener
public class CustomRevisionListener {
public void myMethod() {
..
// get a handle to your spring managed bean
Foo foo = (Foo)ContextLookup.getBean( "mySpringManagedBean" );
..
}
}

Resources