I am working on a Spring 3.1 MVC application and for one of my scenarios, I had to write two implementations of a DAO. I would like to know how to autowire this in a service layer based on another object's attribute.
For example,
class Vehicle {
private name;
private type;
..
..
..
}
@Service
class VehicleServiceImpl implements VehicleService {
// There are two implementations to this DAO
// if Vehicle.type == "CAR", inject CarDAO
// if Vehicle.type == "TRAIN", inject TrainDAO
@Autowired
private VehicleDAO vehicleDAO ;
}
@Repository
class CarDAO implements VehicleDAO {
}
@Repository
class TrainDAO implements VehicleDAO {
}
If my Vehicle is a Car, I need to autowire CarDAO and if it's a train, I need to autowire TrainDAO
What is the best way to implement this in spring 3.1.
I was hoping to use either context property place holders or @Qualifier annotation but both these are kind of restricted to lookup based on some property. I am not sure how to do this at runtime based on the property of another object.
2) byType autowiring mode It internally uses setter injection. In this case, it works fine because you have created an instance of B type. It doesn't matter that you have different bean name than reference name. But, if you have multiple bean of one type, it will not work and throw exception.
The @Autowired annotation in spring automatically injects the dependent beans into the associated references of a POJO class. This annotation will inject the dependent beans by matching the data-type (i.e. Works internally as Autowiring byType).
3. Autowiring using property type. Allows a property to be autowired if exactly one bean of property type exists in the container. If more than one exists, it's a fatal exception is thrown, which indicates that you may not used byType autowiring for that bean.
My solution would be as follows:
a method isResponsibleFor in the VehicleDao interface:
interface VehicleDao {
public boolean isResponsibleFor(Vehicle vehicle);
}
example implementation:
@Repository
class CarDAO implements VehicleDAO {
public boolean isResponsibleFor(Vehicle vehicle) {
return "CAR".equals(vehicle.getType());
}
}
then autowire a list of all VehicleDao-implementations in the VehicleService:
public class VehicleServiceImpl implements VehicleService {
@Autowired
private List<VehicleDao> vehicleDaos;
private VehicleDao daoForVehicle(Vehicle vehicle) {
foreach(VehicleDao vehicleDao : vehicleDaos) {
if(vehicleDao.isResponsibleFor(vehicle) {
return vehicleDao;
}
}
throw new UnsupportedOperationException("unsupported vehicleType");
}
@Transactional
public void save(Vehicle vehicle) {
daoForVehicle(vehicle).save(vehicle);
}
}
This has the advantage that you don't need to modify the service when you are adding a new vehicleType at a later time - you just need to add a new VehicleDao-implementation.
There is an cleaner option to accomplish this strategy. We know Spring is smart enough to inject where it sees a bean that it has control over, so when it sees your VehicleDAO
with an @Autowire
or @Resource
annotation, it will correctly inject that concrete implementation.
Keeping that in mind, this will work anywhere you ask Spring to perform dependency injection, using a Map<>
or a List<>
for instance.
// Injects the map will all VehicleDAO implementations where key = the
// concrete implementation (The default name is the class name, otherwise you
// can specify the name explicitly).
@Autowired
private Map<String, VehicleDAO> vehicleDAO;
// When you want to use a specific implementaion of VehicleDAO, just call the
// 'get()' method on the map as in:
...
vehicleDAO.get("carDAO").yourMethod();
...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With