How do I get my dependencies inject using @Configurable in conjunction with readResolve()
The framework I am developing for my application relies very heavily on dynamically generated domain objects. I recently started using Spring WebFlow and now need to be able to serialize my domain objects that will be kept in flow scope.
I have done a bit of research and figured out that I can use writeReplace()
and readResolve()
. The only catch is that I need to look-up a factory in the Spring context. I tried to use @Configurable(preConstruction = true)
in conjunction with the BeanFactoryAware marker interface.
But beanFactory
is always null
when I try to use it in my createEntity()
method. Neither the default constructor nor the setBeanFactory()
injector are called.
Has anybody tried this or something similar? I have included relevant class below.
Thanks in advance, Brian
/*
* Copyright 2008 Brian Thomas Matthews Limited.
* All rights reserved, worldwide.
*
* This software and all information contained herein is the property of
* Brian Thomas Matthews Limited. Any dissemination, disclosure, use, or
* reproduction of this material for any reason inconsistent with the
* express purpose for which it has been disclosed is strictly forbidden.
*/
package com.btmatthews.dmf.domain.impl.cglib;
import java.io.InvalidObjectException;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.beanutils.PropertyUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.util.StringUtils;
import com.btmatthews.dmf.domain.IEntity;
import com.btmatthews.dmf.domain.IEntityFactory;
import com.btmatthews.dmf.domain.IEntityID;
import com.btmatthews.dmf.spring.IEntityDefinitionBean;
/**
* This class represents the serialized form of a domain object implemented
* using CGLib. The readResolve() method recreates the actual domain object
* after it has been deserialized into Serializable. You must define
* <spring-configured/> in the application context.
*
* @param <S>
* The interface that defines the properties of the base domain
* object.
* @param <T>
* The interface that defines the properties of the derived domain
* object.
* @author <a href="mailto:brian@btmatthews.com">Brian Matthews</a>
* @version 1.0
*/
@Configurable(preConstruction = true)
public final class SerializedCGLibEntity<S extends IEntity<S>, T extends S>
implements Serializable, BeanFactoryAware
{
/**
* Used for logging.
*/
private static final Logger LOG = LoggerFactory
.getLogger(SerializedCGLibEntity.class);
/**
* The serialization version number.
*/
private static final long serialVersionUID = 3830830321957878319L;
/**
* The application context. Note this is not serialized.
*/
private transient BeanFactory beanFactory;
/**
* The domain object name.
*/
private String entityName;
/**
* The domain object identifier.
*/
private IEntityID<S> entityId;
/**
* The domain object version number.
*/
private long entityVersion;
/**
* The attributes of the domain object.
*/
private HashMap<?, ?> entityAttributes;
/**
* The default constructor.
*/
public SerializedCGLibEntity()
{
SerializedCGLibEntity.LOG
.debug("Initializing with default constructor");
}
/**
* Initialise with the attributes to be serialised.
*
* @param name
* The entity name.
* @param id
* The domain object identifier.
* @param version
* The entity version.
* @param attributes
* The entity attributes.
*/
public SerializedCGLibEntity(final String name, final IEntityID<S> id,
final long version, final HashMap<?, ?> attributes)
{
SerializedCGLibEntity.LOG
.debug("Initializing with parameterized constructor");
this.entityName = name;
this.entityId = id;
this.entityVersion = version;
this.entityAttributes = attributes;
}
/**
* Inject the bean factory.
*
* @param factory
* The bean factory.
*/
public void setBeanFactory(final BeanFactory factory)
{
SerializedCGLibEntity.LOG.debug("Injected bean factory");
this.beanFactory = factory;
}
/**
* Called after deserialisation. The corresponding entity factory is
* retrieved from the bean application context and BeanUtils methods are
* used to initialise the object.
*
* @return The initialised domain object.
* @throws ObjectStreamException
* If there was a problem creating or initialising the domain
* object.
*/
public Object readResolve()
throws ObjectStreamException
{
SerializedCGLibEntity.LOG.debug("Transforming deserialized object");
final T entity = this.createEntity();
entity.setId(this.entityId);
try
{
PropertyUtils.setSimpleProperty(entity, "version",
this.entityVersion);
for (Map.Entry<?, ?> entry : this.entityAttributes.entrySet())
{
PropertyUtils.setSimpleProperty(entity, entry.getKey()
.toString(), entry.getValue());
}
}
catch (IllegalAccessException e)
{
throw new InvalidObjectException(e.getMessage());
}
catch (InvocationTargetException e)
{
throw new InvalidObjectException(e.getMessage());
}
catch (NoSuchMethodException e)
{
throw new InvalidObjectException(e.getMessage());
}
return entity;
}
/**
* Lookup the entity factory in the application context and create an
* instance of the entity. The entity factory is located by getting the
* entity definition bean and using the factory registered with it or
* getting the entity factory. The name used for the definition bean lookup
* is ${entityName}Definition while ${entityName} is used for the factory
* lookup.
*
* @return The domain object instance.
* @throws ObjectStreamException
* If the entity definition bean or entity factory were not
* available.
*/
@SuppressWarnings("unchecked")
private T createEntity()
throws ObjectStreamException
{
SerializedCGLibEntity.LOG.debug("Getting domain object factory");
// Try to use the entity definition bean
final IEntityDefinitionBean<S, T> entityDefinition = (IEntityDefinitionBean<S, T>)this.beanFactory
.getBean(StringUtils.uncapitalize(this.entityName) + "Definition",
IEntityDefinitionBean.class);
if (entityDefinition != null)
{
final IEntityFactory<S, T> entityFactory = entityDefinition
.getFactory();
if (entityFactory != null)
{
SerializedCGLibEntity.LOG
.debug("Domain object factory obtained via enity definition bean");
return entityFactory.create();
}
}
// Try to use the entity factory
final IEntityFactory<S, T> entityFactory = (IEntityFactory<S, T>)this.beanFactory
.getBean(StringUtils.uncapitalize(this.entityName) + "Factory",
IEntityFactory.class);
if (entityFactory != null)
{
SerializedCGLibEntity.LOG
.debug("Domain object factory obtained via direct look-up");
return entityFactory.create();
}
// Neither worked!
SerializedCGLibEntity.LOG.warn("Cannot find domain object factory");
throw new InvalidObjectException(
"No entity definition or factory found for " + this.entityName);
}
}
Asked by: Lucas393 | Posted: 28-01-2022
Answer 1
Are you using spring's ApplicationContext
, or BeanFactory
? If you are using ApplicationContext
, you can implement ApplicationContextAware instead and spring will supply you with the application context. I've never used spring's BeanFactory
before but I have used ApplicationContext
and it works.
Answer 2
Are you sure that your Configurable class has been properly weaved wither by compiling it with the ApsectJ compiler or with runtime weaving.
You also need to specify the attributes in you configuration file marking the bean as prototype. Something along the lines of:
<aop:spring-configured />
<bean class="package.name.SerializedCGLibEntity" scope="prototype">
<property name="beanFactory" value="whateverValue"/>
</bean>
Similar questions
java - Why does Spring's @Configurable sometimes work and sometimes not?
I'm trying to use automatic dependency injection via Spring's @Configurable annotation w/ @Resource on the fields needing injection. This involved some setup, like passing spring-agent.jar to my JVM. For the full details see here.
It works... mostly. When my Tomcat is booting up, I see the AspectJ init messages, my...
java - Why doesn't AspectJ compile-time weaving of Spring's @Configurable work?
Update 5: I've downloaded the latest Spring ToolsSuite IDE based on the latest Eclipse. When I import my project as a Maven project, Eclipse/STS appears to use the Maven goals for building my project. This means AspectJ finally works correctly in Eclipse.
Update 4: I have ended up just using Maven + AspectJ plugin for compile-time weaving, effectively bypassing Eclipse's mechanism....
java - Spring load time weaving not detecting class annotated with @configurable
I'm having trouble getting AspectJ to perform load time weaving on a class annotated with @configurable in my main project. No fields get set and none of the setters are touched.
I don't think there's trouble with the configuration itself, because I've extracted the configuration and tested it on a smaller sandbox project. Just for the sake of it, I'll include it in this question though.
So, I'm wondering...
java - Spring autowiring using @Configurable
I'm playing with the idea of using Spring @Configurable and @Autowire to inject DAOs into domain objects so that they do not need direct knowledge of the persistence layer.
I'm trying to follow http://static.springsource.org/spring/docs/3.0.x/spring-framew...
java - How do you dependency inject beans marked @Configurable after deserialized by Tomcat from SESSIONS.ser?
Note: this won't make any sense unless you're very familiar with Java, Spring AOP, and Tomcat.
The problem is that beans marked @Configurable are not injected when deserialized by Tomcat SESSIONS.ser.
I noticed this behavior on a Struts 1.2.9 based (legacy) application with Spring 2.5.4, spring-tomcat-weaver-2.5.4, Tomcat 6.0.14.
Code:
public class MyForm implements Serializable {
...
java - Slow down with combining @Scheduled and @Configurable
we just move our definition of cron jobs from xml based definitions to annotation driven with
<task:annotation-driven />
we did not configured it further as the defaults are just fine.
We have a few @Scheduled annotations. Everything worked fine. When we deployed it we saw a massive drop in response time from around 20-30 ms average response time to 40-60 average response time.
...
java - XML equivalent of @Configurable annotation in Spring
Is there any XML equivalent of @Configurable annotation?
For example for the bean:
<bean class="org.obliquid.sherd.domain.SalesDocument" scope ="prototype">
<property name="docType" ref="documentTypeProto"/>
</bean>
How can I tell that SalesDocument should be @Configurable?
java - @Configurable with unit test causes error
Classes are compile time weaved. I read in the documentation that weaved classes would warn on classes constructed outside the container context but not outright error, yet I get the following test error in the maven build:
testExecuteCommand(SportTimeExecutionCommandTest): Error creating bean with name 'SportTimeExecutionCommand': Injection of resource dependencies failed; nested exception...
spring - Inject Bean in Custom tag Java - @Configurable
I am having trouble injecting a service into a custom tag I created:
@Configurable
public MyTag extends BodyTagSupport{
@Autowired
private MyService service;
@Override
public int doStartTag(){
......
service.callServiceMethod(); // service is null
....
}
.......
}
Is there a way to inject beans using @Configurable in Custom Tags? I do not want to use following approach to injec...
java - @Autowired issue with @Configurable servlet
I am trying to autowire a class into a WebSocketServlet in the following way:
@Configurable(autowire=Autowire.BY_TYPE)
public class MyServlet extends WebSocketServlet {
@Autowired
public MyClass field;
// etc...
}
Here's what my configuration looks like:
<context:annotation-config />
<context:component-scan base-package="org.*" />
<bean id="conf...
Still can't find your answer? Check out these amazing Java communities for help...
Java Reddit Community | Java Help Reddit Community | Dev.to Java Community | Java Discord | Java Programmers (Facebook) | Java developers (Facebook)