I have a dilemma and I'm not sure about the best way to start solving it.
I'm working with an old code base at work. Some of the domain objects (and db tables behind them) don't make a lot of sense. eg, deleted is stored as a long, age is stored as a String, etc. Which I've been able to work with fine. In the view I can say if (deleted == 1).... But there are some specific business logic that is leading to a maintenance problem by having it in the view. Here's one example:
String title = null;
if (obj.getTitle != null) {
title = obj.getTitle();
} else {
title = obj.getName() + " - " + obj.getCategory();
}
I would really like to have a "view bean" where this business logic and legit oddities are ironed out and stored so that I can use it in multiple views but then change it in one place. If I had a Product POJO and then my ProductViewBean, as an example, I would do something like:
productViewBean.setDeleted( product.getDeleted() == 1 );
productViewBean.setTitle( product.getTitle() != null ? product.getTitle() : product.getName() + " - " + product.getCategory() );
My question is, where should I do this? Should I have a manager (with appropriate daos injected into it) that is injected into my controller and returns my "view bean"? Or am I going about this all wrong and could there be better approach?
Thanks in advance
(Note: I understand that the underlying structure is the real problem but it is beyond my jurisdiction to change at this point. Too many projects use these domain objects. And even if I did clean up the db/domain objects (so that deleted was a boolean etc) I'm still left with unavoidable business logic (if !title then 'build title from other components') that doesn't belong in the data layer and that I would like to encapsulate in one place so that neither the controller or view have to worry about it and it can be used across multiple controllers/views. I happen to be at a point where I can write something that is efficient and maintainable and could even create a good layer to ease cleanup of these domain objects in the future.)
I'll bet you can sort all that out in the Spring data binding and validation API.
I'd also say that you should have a service tier that's distinct from the web controller layer. Inject the services into the web tier and let them do all the work. They worry about units of work, transactions, and DAO objects.
I would try an Adapter delegating to the domain object like the following. The controller and view use this one. If the ProductViewBean is in the same package as the manager, the manager only can use the getDelegate() method to pass it to the dao.
public class ProductViewBean {
private final Product delegate;
public ProductViewBean(Product delegate) {
this.delegate = delegate;
}
Product getDelegate() {
return delegate;
}
public String getTitle() {
if (delegate.getTitle == null) {
return delegate.getName() + " - " + delegate.getCategory();
}
return delegate.getTitle();
}
public void setTitle(String title) {
delegate.setTitle(title);
}
public boolean isDeleted() {
return delegate.getDeleted() == 1L;
}
public void setDeleted(boolean deleted) {
delegate.setDeleted(deleted ? 1L : 0L);
}
...
}
So you can make the API you like.
Related
Our team are using Spring Boot 2 with sql2o as db library. In the paste in our services, for trivial methods, we simply call the repository and returns the model. For example, if I have a Supplier table, I had in the service
#Override
public List<Supplier> findAll() {
return supplierRepository.findAll();
}
Now, since in our controllers we need 99% in the cases other objects correlated to the model, I would create a composite class that holds the model and other models. For example:
#Override
public List<UnknownName> findAll() {
List<Supplier> suppliers = supplierRepository.findAll();
List<UnknownName> res = new ArrayList<>();
UnknownName unknownName;
LegalOffice legalOffice;
if (suppliers != null) {
for (Supplier supplier in suppliers) {
unknownName = new UnknownName();
unknownName.setSupplier(supplier);
legalOffice = legalOfficeService.findByIdlegaloffice(supplier.getLegalofficeid);
unknownName.setLegalOffice(legalOffice);
res.add(unknownName);
}
}
return res;
}
What should the name of class UnknownName?
PS: I simplified the code for better redability, but I use a generic enrich() function that I call for all the find methods, so I don't have to dupe the code.
I would recommend SupplierDto or SupplierLegalOfficeDto. DTO stands for Data Transfer Objects and it's commonly used for enriched models (more here).
Also you shouldn't check suppliers for null as repository always returns a non-null list.
In the end, I adopted the suffix Aggregator, following the Domain-driven design wording.
I need to check some data, whether or not to send a tracking info. This data is saved inside the Realm database. Here is the model:
public class RealmTrackedState extends RealmObject {
#PrimaryKey
private int id = 1;
private RealmList<RealmChat> realmChatsStarted;
private boolean isSupportChatOpened;
private boolean isSupportChatAnswered;
/* getters and setters */
}
The idea is - every chat that is not inside the realmChatsStarted should be tracked and then added to this list. Similar thing for isSupportChatOpened boolean - however because of the business logic this is a special case.
So - I've wrapped this inside one Realm object. And I've wrapped this into few shouldTrack() methods, like this:
#Override
public void insertOrUpdateAsync(#NonNull final RealmModel object, #Nullable OnInsertListener listener) {
Realm instance = getRealmInstance();
instance.executeTransactionAsync(realm -> realm.insertOrUpdate(object), () ->
notifyOnSuccessNclose(listener, instance),
error -> notifyOnErrorNclose(listener, error, instance));
}
#Override
public RealmTrackedState getRealmTrackedState() {
try (Realm instance = getRealmInstance()) {
RealmResults<RealmTrackedState> trackedStates = instance.where(RealmTrackedState.class).findAll();
if (!trackedStates.isEmpty()) {
return instance.copyFromRealm(trackedStates.first());
}
RealmTrackedState trackedState = new RealmTrackedState();
trackedState.setRealmChatsStarted(new RealmList<>());
insertOrUpdateAsync(trackedState, null);
return trackedState;
}
}
#Override
public boolean shouldTrackChatStarted(#NonNull RealmChat chat) {
if (getCurrentUser().isRecruiter()) {
return false;
}
RealmList<RealmChat> channels = getRealmTrackedState().getRealmChatsStarted();
for (RealmChat trackedChats : channels) {
if (trackedChats.getId() == chat.getId()) {
return false;
}
}
getRealmInstance().executeTransaction(realm -> {
RealmTrackedState realmTrackedState = getRealmTrackedState();
realmTrackedState.addChatStartedChat(chat);
realm.insertOrUpdate(realmTrackedState);
});
return true;
}
And for any other field inside RealmTrackedState model happens the same.
So, within the presenter class, where I'm firing a track I have this:
private void trackState(){
if(dataManager.shouldTrackChatStarted(chatCache)){
//track data
}
if(dataManager.shouldTrackSupportChatOpened(chatCache)){
//track data
}
if(dataManager.shouldTrackWhatever(chatCache)){
//track data
}
...
}
And I wonder:
a. How much of a performance impact this would have.
I'm new to Realm, but for me opening and closing a DB looks ... heavy.
I like in this implementation that each should(...) method is standalone. Even though I'm launching three of them in a row - in other cases I'd probably use only one.
However would it be wiser to get this main object once and then operate on it? Sounds like it.
b. I see that I can either operate on synchronous and asynchronous transactions. I'm afraid that stacking a series of synchronous transactions may clog the CPU, and using the series of asynchronous may cause unexpected behaviour.
c. #PrimaryKey - I used this because of the wild copy paste session. Assuming that this class should have only instance - is it a correct way to do this?
ad a.
Realm caches instances so opening and closing instances are not that expensive as it sounds. First time an app is opening a Realm file, a number of consistency checks are performed (primarily does model classes match classes on disk) but next time you open an instance, you don't do this check.
ad b.
If your transactions depend on each other, you might have to be careful. On the other hand, why have multiple transactions? An async transaction will notify you when it has completed which can help me to get the behaviour you except.
ad c.
Primary keys are useful when you update objects (using insertOrUpdate()) as the value is use to decide if you are creating/inserting or updating an object.
I am working on an application which has REST endpoints and for a Get-By-ID service, I am populating a resource (basically a POJO) by collecting data from the persistent store. Now, before sending the response back, I have to populate the HREF in the POJO resource. I want to do it in a generic way so that various other REST services (search etc.) can use it. I want to do this HREF population at a common place for reusability purpose. In a nutshell, my resource POJO can go through various massaging layers to have different state changed and finally sent back to the consumer.
Resource POJO --> Massager 1 --> Massager 2 --> Final Massaged POJO
Could someone help me to figure out a design pattern that can fit my problem.
I thought of Decorator pattern, but somehow it does not sail my ship.
~ NN
You could adapt Chain Of Responsability to your needs. Instead of having a series of processing objects which pass your POJO from one to another in case it cannot handle it, you could process your POJO and then pass it further.
abstract class Messager{
private Messager nextMessager;
void setNextMessager(Messager messager){
this.nextMessager = messager;
}
Messager getNextMessager(){
return this.nextMessager;
}
abstract void handle(Pojo pojo);
}
class FooMessager extends Messager{
void handle(Pojo pojo){
//operate on your pojo
if(pojo.getHref == null){
pojo.setHref("broken");
}
if(this.getNextMessager() != null){
this.getNextMessager().handle(pojo);
}
}
}
class BarMessager{
void handle(Pojo pojo){
//operate on your pojo
if(pojo.getHref().contains("broken")){
pojo.setHref(pojo.getHref().replace("broken","fixed"));
}
if(this.getNextMessager() != null){
this.getNextMessager().handle(pojo);
}
}
}
class Pojo{
private String href;
public Pojo() {
}
public String getHref() {
return href;
}
public void setHref(String href) {
this.href = href;
}
}
class Test{
public static void main(String[] args) {
Pojo pojo = new Pojo();
pojo.setHref(null);
Messager foo = new FooMessager();
Messager bar = new BarMessager();
foo.setNextMessager(bar);
foo.handle();
}
}
Even if the previous answers are good and does solve it, I want to propose you additional way if you want to go further. The communication between objects is very common, so a lot of concepts are out there and you can choose the one that fits best for your needs.
The Command pattern can help you with the encapsulation of a request as an object in
collecting data from the persistent store
It'll allow you to parameterize clients with queue or log requests.
The Mediator pattern can define your communication between the Massager 1 --> Massager 2 classes. By doing this it'll encapsulate your objects interaction. Also it promotes loose coupling by keeping objects from referring to each other explicitly, and it'll let you vary their interaction independently.
If you'll deal with how to notify change to Massager 1 --> Massager 2 classes
my resource POJO can go through various massaging layers to have different state changed
than the Observer pattern can define a dependency between your objects so that when one object changes state, all its dependents are notified and updated automatically.
I am new to Java and I'm trying to implement a basic database access layer.
I'm using Apache DBUtils to reduce JDBC boilerplate code and this is working really well.
The problem is that my implementation uses a separate class for CRUD for each table in my database and it feels wrong to be duplicating so much functionality.
Is this an acceptable design and if not what can I do to reduce code duplication?
Could I refactor my solution to use generics in some fashion?
I realize I could use an ORM (myBatis, Hibernate etc) as a solution but I would like to try to stick with DBUtils and plain JDBC if I can help it.
Just for clarification:
Lets say I have 2 tables...
---------------------
User | File
---------------------
userId | fileId
name | path
age | size
---------------------
In my current solution I would create 2 classes (UserStore, FileStore) and
each class would implement similar basic CRUD methods:
protected boolean Create(User newUser)
{
QueryRunner run = new QueryRunner(dataSource);
try
{
run.update("INSERT INTO User (name, age) " +
"VALUES (?, ?)", newUser.getName(), newUser.getAge());
}
catch (SQLException ex)
{
Log.logException(ex);
return false;
}
return true;
}
protected User Read(int userId)
{
try
{
User user = run.query("SELECT * FROM User WHERE userId = ? ", userId);
return user;
}
catch (SQLException ex)
{
Log.logException(ex);
return null;
}
}
protected update(User user)
{
... perform database query etc
}
protected delete(int userId)
{
... perform database query etc
}
You asked how i would do this with Template method. Here is an example how you could do it:
public class AbstractDAO<T> {
private String table;
private String id_field;
public AbstractDAO(String table, String id_field){
this.table = table;
...
}
public T read(int id){
try
{
T user = run.query("SELECT * FROM "+ table + " WHERE "+id_field +" = ? ", id);
return user;
}
catch (SQLException ex)
{
Log.logException(ex);
return null;
}
}
This one looks easy, how about Create?
public boolean Create(T user){
QueryRunner run = new QueryRunner(dataSource);
try
{
run.update("INSERT INTO "+table+ getFields() +
"VALUES " + getParameters(user));
}
catch (SQLException ex)
{
Log.logException(ex);
return false;
}
return true;
}
protected abstract String getFields();
protected abstract String getParameters(T user);
Ugly, and insecure, but okay for transmitting the idea.
It looks like I can give you few simple suggestions for your question.
1)
Instead of managing queries inside DAOs like what you are doing, make a factory class that has list of queries for your needs.
like
class QueryFactory {
static String INSERT_BOOK = "BLAH";
static String DELETE_BOOK = "BLAH";
}
This will separate queries from DAO code and make it easier to manage.
2)
Implement a generic DAO
http://www.codeproject.com/Articles/251166/The-Generic-DAO-pattern-in-Java-with-Spring-3-and
3) As you have mentioned above, use ORM to help yourself binding beans to Database and many more features.
Using DBUtils you have already abstracted away a lot of boilerplate code. What remains is mostly the work that differs between entities : The right sql statement, transformation of entity objects into UPDATE parameters and vice versa with SELECTs, exception handling.
Unfortunately it is not easy to create a general abstraction that is flexible enough for these remaining tasks. That's what ORM mappers are all about. I would still suggest to look into one of these. If you stick to the JPA API, you are still in standards land and able to switch the ORM provider more easily (although there is always some coupling).
I was impressed by SpringData's Repository abstraction. In simple use cases they give you zero code DAO's. If you are already using Spring and just want to persist your object model you should definitely look into it.
Alternatively I made some good experiences with jooq. It can also create DTO's and corresponding DAO's based on the tables in your schema. In contrast to ORM mappers it is closer to the relational schema, which may be an advantage or a disadvantage.
mybatis allows you to return a resulttype as hashmap:
<select id="mCount" resultType="hashmap">
select managerName, count(reportees) AS count
from mgr_employee
group by managerName;
</select>
So you can effectively write out in a workflow like this:
1) Develop an interface
2a) Use mybatis annotation to define the query required OR
2b) Link the interface to a xml and write the query
Take note that this will not be involving any DAO and other boilerplates involve as above
I am not really sure where my problem lies, as I am experimenting in two areas that I don't have much experience with: JPA and Futures (using Play! Framework's Jobs and Promises).
I have the following bit of code, which I want to return a Meeting object, when one of the fields of this object has been given a value, by another thread from another HTTP request. Here is what I have:
Promise<Meeting> meetingPromise = new Job<Meeting> () {
#Override
public Meeting doJobWithResult() throws Exception {
Meeting meeting = Meeting.findById(id);
while (meeting.bbbMeetingId == null) {
Thread.sleep(1000);
meeting = meeting.refresh(); // I tried each of these
meeting = meeting.merge(); // lines but to no avail; I
meeting = Meeting.findById(id); // get the same result
}
return meeting;
}
}.now();
Meeting meeting = await(meetingPromise);
As I note in the comments, there are three lines in there, any one of which I think should allow me to refresh the contents of my object from the database. From the debugger, it seems that the many-to-one relationships are refreshed by these calls, but the single values are not.
My Meeting object extends Play! Framework's Model, and for convenience, here is the refresh method:
/**
* Refresh the entity state.
*/
public <T extends JPABase> T refresh() {
em().refresh(this);
return (T) this;
}
and the merge method:
/**
* Merge this object to obtain a managed entity (usefull when the object comes from the Cache).
*/
public <T extends JPABase> T merge() {
return (T) em().merge(this);
}
So, how can I refresh my model from the database?
So, I ended up cross-posting this question on the play-framework group, and I got an answer there. So, for the discussion, check out that thread.
In the interest of having the answer come up in a web search to anyone who has this problem in the future, here is what the code snippet that I pasted earlier looks like:
Promise<Meeting> meetingPromise = new Job<Meeting> () {
#Override
public Meeting doJobWithResult() throws Exception {
Meeting meeting = Meeting.findById(id);
while (meeting.bbbMeetingId == null) {
Thread.sleep(1000);
if (JPA.isInsideTransaction()) {
JPAPlugin.closeTx(false);
}
JPAPlugin.startTx(true);
meeting = Meeting.findById(id);
JPAPlugin.closeTx(false);
}
return meeting;
}
}.now();
Meeting meeting = await(meetingPromise);
I am not using the #NoTransaction annotation, because that messes up some other code that checks if the request is coming from a valid user.
I'm not sure about it but JPA transactions are managed automatically by Play in the request/controller context (the JPAPlugin opens a transaction before invocation and closes it after invocation).
But I'm not sure at all what happens within jobs and I don't think transactions are auto-managed (or it's a feature I don't know). So, is your entity attached to an entitymanager or still transient? Is there a transaction somewhere? I don't really know but it may explain some weird behavior if not...