I am building a spring based application that handles server-side game management for a mobile game app. The stack is Spring/Hibernate/Jersey. I want the clients (mobile) to call a REST API to update/retrieve the game state.
I created a TournamentController class which responsability is to update the tournament state using some business logic. This class is designed to be instanciated every time an operation on a Tournament is required and then thrown away.
public class TournamentController {
@Autowired
private TournamentDAO tournamentDAO;
private final Tournament tournament;
public TournamentController( Tournament tournament ) {
this.tournament = tournament;
}
public void startTournament() {
if ( tournament.getState() != TournamentState.SETUP ) {
throw new TournamentAlreadyStartedException();
}
tournament.setState( TournamentState.IN_PROGRESS );
//... some other logic and calls to other DAOs
tournamentDAO.save( tournament );
}
}
I also created a TournamentResource class that is the REST front end for the tournament. It’s responsability is to do some basic validation (user security, …) and exception translation.
@Path( "/tournament" )
@Component
@Scope( "prototype" )
public class TournamentResource {
private static final Log log = LogFactory.getLog( TournamentResource.class );
@Autowired
private TournamentDAO tournamentDAO;
@GET
@Path( "{tournamentId}/start" )
@Produces( MediaType.APPLICATION_JSON )
@Transactional
public TournamentDTO startTournament( @PathParam( "tournamentId" ) long tournamentId ) {
Tournament tournament = tournamentDAO.getTournament( tournamentId, LockMode.PESSIMISTIC_WRITE );
if ( tournament == null ) {
throw new WebApplicationException( Status.NOT_FOUND );
}
try {
TournamentController controller = new TournamentController( tournament );
controller.startTournament();
} catch ( TournamentAlreadyStartedException e ) {
log.warn( "Could not start tournament " + tournamentId + " since it is already started." );
throw new RestException( Status.BAD_REQUEST, "Tournament already started" );
}
return DTOConverterUtil.getTournament( tournament );
}
}
I am using load time weaving with AspectJ. Here is my context:
<context:annotation-config />
<!-- Make spring aware ANY pojo with the @Configurable annotation -->
<context:spring-configured />
<!-- Scan all classes in com.mdarveau for annotations -->
<context:component-scan base-package="so.question" />
<!-- Load Time Weaver -->
<context:load-time-weaver weaver-class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver" aspectj-weaving="on" />
<!-- DB config -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
...
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="com.mdarveau.fnp.model" />
<property name="hibernateProperties">
<value>
hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
</value>
</property>
</bean>
<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<!-- enable @Transactional -->
<tx:annotation-driven transaction-manager="txManager" mode="aspectj" />
My TournamentResource class is a singleton by design and is working well.
My problem is that when it instanciate the TournamentController using new instead of spring, it’s @Autowired attributes does not seems to be wired correctly. I tried to add the @Component annotation on it without success.
Should I make TournamentResource ApplicationContextAware and create the TournamentController through spring?
This must be a fairly common problem. I see a lot of examples where the backend is a singleton but I would like to avoid passing the Tournament to every method call on TournamentController (all then to all private methods in TournamentController).
Since you already have load-time weaving and
<context:spring-configured />, you can declare yourTournamentControlleras@Configurable.It will enable autowiring for instances of
TournamentControllercreated withnew.