6

The task I had to make has already been delivered, yet a certain question hangs around in my mind.

I defined the following interface:

package dao;

import java.sql.SQLException;

/**
 * Get / save / delete a single instance from the db in RESTful fashion on the object
 * @author kimg
 *
 * @param <T>
 */
public interface IDao<T> {

    public void fetch(int id); 
    public void save() throws SQLException; 
    public void delete() throws SQLException; 

} 

Purpose is to have all pojo's that are represented as database table entities implement these methods, so the user of the pojo's knows how to handle instances according to a pattern. I've taken this approach from Backbone (Javascript).

However, there are other methods that I liked to impose as class methods (static) on the Pojo class itself. The most obvious methods are things like:

List<Person> list = Person.fetchAll(); 
List<Person> list = Person.fetchAll(offset, limit); 
int i = Person.countAll(); 
... 

I've found that having these methods defined by default offers great benefit, yet nothing forces a developer to implement them, as static methods can't be imposed by default. Also, users of the classes can't know for sure that they'll be able to use the static methods that they would otherwise expect by contract (in case of an interface); any typo in the method name, omitting any method can cause the smooth app workflow to break.

What would be the most elegant solution to catch this pitfall?

html_programmer
  • 14,612
  • 12
  • 59
  • 125
  • 1
    Don't use static methods and segregate your DAO from your POJOs. – plalx Feb 08 '16 at 18:19
  • @plalx Could you elaborate a bit more on your thoughts? I see a few options there. – html_programmer Feb 08 '16 at 18:51
  • Lookup the repository pattern, it's a much better approach than ActiveRecord IMO. – plalx Feb 08 '16 at 19:11
  • @KimGysen, plalx is recommending that you create a separation between DAO and DTO (data transfer object). The interface you present suggests that you instead have fused DAO/DTO classes. DAOs are responsible for access logic -- data storage, retrieval, and modification -- whereas DTOs are strictly data containers, usually with no methods other than getters and setters. If you created such a separation then your `fetchAll()` etc. methods would be sensible as instance methods defined by your DAO interface. – John Bollinger Feb 08 '16 at 19:12
  • @JohnBollinger The important aspect is to hide the persistence details from the POJOs. I'm not prescribing any specific approach on how POJOs shall be implemented here. For instance, with a Transaction Script domain modeling approach then you may return simple DTOs or even query resultsets, but with a domain model you would return objects with behaviors. In that case I guess we could specifically refer to the Repository pattern. – plalx Feb 08 '16 at 19:19
  • @plaix Ok it's clear now the repository pattern. Just delegating these methods to a Dao instance and making the static methods instance, like you said. Pity to duplicate all the pojo's to repositories but I can live with it. Pity I didn't ask this earlier but that's ok. Thanks to both :-) – html_programmer Feb 08 '16 at 19:42

2 Answers2

3

I've found that having these methods defined by default offers great benefit, yet nothing forces a developer to implement them, as static methods can't be imposed by default.

If the methods are so beneficial then wouldn't developers want to implement them? At least if they were aware of the desired patterns and the usefulness of implementing them?

Also, users of the classes can't know for sure that they'll be able to use the static methods that they would otherwise expect by contract (in case of an interface)

That's irrelevant, because static methods are not virtual. Users do know for sure whether the type whose static method they would like to invoke in fact does have that method. If they forget then the compiler will gladly tell them.

any typo in the method name, omitting any method can cause the smooth app workflow to break.

I'm not sure I follow you. If you're talking about developers failing to implement these static methods or doing so wrongly, then that's what code review is for. You could also write automated tests that reflectively verify the methods' presence. I don't really see how this is a bigger issue than the methods being implemented with the desired signature but incorrect implementation.

Again, static methods are not virtual. The user of every static method call knows at compile time exactly which method is being called, and therefore whether such a method is available. If they want a particular method and do not have it then they have the alternatives of requesting that it be added, adding it themselves, or doing without.

What would be the most elegant solution to catch this pitfall?

Document any such expectations. Have project management enforce them (and if they refuse to do, then maybe it wasn't so important after all). Employ code reviews. Write automated tests, perhaps reflective ones.

John Bollinger
  • 121,924
  • 8
  • 64
  • 118
  • Yes I agree that you would want to implement them when working on the same app. I noticed that for Client, Product, Stock, etc, the same thing applied over and over, hence the urge to abstract common functionality. What I would like to achieve is while working on Controller classes, to be able to call the same static methods on every pojo class, assuming that they are there, the same way an interface provides this contract to an instance. As I follow your explanation, documentation seems the way to go although I remain a bit puzzled on the reason why such contract cannot exist on class... – html_programmer Feb 08 '16 at 18:39
  • @KimGysen, in principle, there is no reason why Java *could not* have a mechanism to enforce on classes a static contract such as you describe. But it *does not* have such a mechanism. I can only speculate on why it does not, but I'd be inclined to say that it is not a good fit with the Java language semantically, and the generality of use cases seems very much in question. Were I Oracle (or had I been Sun), I would not be inclined to design and implement an ill-fitting feature to serve a comparatively small number of special cases. – John Bollinger Feb 08 '16 at 19:04
  • I see. After browsing around such as here (C#): http://stackoverflow.com/questions/259026/why-doesnt-c-sharp-allow-static-methods-to-implement-an-interface it seems to be the reason. It is not a problem, there are plenty of ways to work my way around to see desired result; I was just wondering if there was a certain language-specific way to do it. But it's not blocking anyhow. Thanks and I accept! – html_programmer Feb 08 '16 at 19:09
  • @JohnBollinger The reason for not supporting static method contracts is simple. The beauty of programming against interfaces is that the client code only cares about the contract, not the implementor or the implementation. To invoke a static method on a static class you have to refer to a specific class, therefore a specific implementation which makes the contract and the implementation indistinguishable. – plalx Feb 08 '16 at 19:27
-1

Instead of having these methods on the Entity, try placing them on a repo/Dao:

public interface IDao<T> {
    void fetch(int id); 
    void save() throws SQLException; 
    void delete() throws SQLException; 
    List<T> list();
    List<T> list(offset, limit); 
    int count();
} 
public class Person {
    //...getters/setters/fields...
}
public class PersonDao implements IDao<Person> {//todo make me a singleton
    //implement the interface here
}
Andreas
  • 4,410
  • 2
  • 19
  • 28
  • 2
    I don't see how this solves the problem regarding the methods that are class rather than instance related. I started off with this approach initially, but ultimately created an abstract Dao class that takes care of a classtype-independent implementation of these methods, from which the pojo's then inherit. I found this to be more abstract than copying a separate Dao class for each Pojo. – html_programmer Feb 08 '16 at 18:29