I am coding a ribbon/achievements system for a website and I have to write some logic for each ribbon in my system. For example, you could earn a ribbon if you're in the first 2,000 people registering to the website or after 1,000 post in the forum. The idea is very similar to stackoverflow's badges, really.
So, every ribbon is obviously in the database but they also need a bit of logic to determine when a user has earned the ribbon.
In the way I coded it, Ribbon
is a simple abstract class:
@Entity
@Table(name = "ribbon")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "ribbon_type")
public abstract class Ribbon
{
@Id
@Column(name = "id", nullable = false, length = 8)
private int id;
@Column(name = "title", nullable = false, length = 64)
private String title;
public Ribbon()
{
}
public abstract boolean isEarned(User user);
// ... getters/setters...
}
You can see I define the inheritance strategy as SINGLE_TABLE
(since I have to code like 50 ribbons and I don't need additional columns for any of them).
Now, a specific ribbon will be implemented like this, for example:
@Entity
public class First2000UsersRibbon extends Ribbon
{
@Autowired
@Transient
private UserHasRibbonDao userHasRibbonDao;
public First2000UsersRibbon()
{
super.setId(1);
super.setTitle("Between the first 2,000 users who registered to the website");
}
@Override
public boolean isEarned(User user)
{
if(!userHasRibbonDao.userHasRibbon(user, this))
{
// TODO
// All the logic to determine whether the user earned the ribbon
// i.e. check whether the user is between the first 2000 users who registered to the website
// Other autowired DAOs are needed
}
else
{
return true;
}
return false;
}
}
The problem is that userHasRibbonDao
is null inside the isEarned()
method, so a NullPointerException
is thrown.
I thought that having DAOs autowired into domain objects was wrong, but in this topic they told me that it's the correct approach (Domain-Driven Design).
I shared a non-working very simple example on GitHub: https://github.com/MintTwist/TestApp (remember to change the connection details in /WEB-INF/properties/jdbc.properties and to import the test_app.sql script)
Any help very appreciated.
Thank you!
Update - Reading the first answers, it seems like my approach is completely wrong. How would you ideally structure the code given that there may be 50-70 different ribbons? Thanks
I'm not saying that I agree with injecting DAOs into domain instances....but
You can wire your DAO into you domain object. But you'll have to declare your domain object in your spring application-context and obtain new instances from Spring NOT using new
. Make sure that you use the prototype scope! You don't want to be getting the same singleton instance everytime!
Really this logic that you want to implement belongs in a service which is injected with the DAOs that it requires.
Perhaps you could have a service like:
@Service
public class RibbonServiceImpl implements RibbonService
@Autowired
private RibbonDAO ribbonDAO;
public boolean isEarned(Ribbon ribbon, User user) {
if(!userHasRibbonDao.userHasRibbon(user, this))
{
// TODO
// All the logic to determine whether the user earned the ribbon
// i.e. check whether the user is between the first 2000 users who registered to the website
// Other autowired DAOs are needed
}
else
{
return true;
}
return false;
}
Mark it as @Configurable
- @Configurable annotion will ensure that even if the beans are created outside of Spring, the dependencies are injected
You also need to add <context:spring-configured/>
in your context.
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