简体   繁体   中英

java generic constructors

I currently have the following code that retrieves data from the database and then create a User . This code is used in many of my classe to create other objects such as News , Comments etc...

It uses apache commons dbutils.

final ResultSetHandler<User> handler = new ResultSetHandler<User>() {

            @Override
            public User handle(ResultSet rs) throws SQLException {

                User user = null;
                if (rs.next()) {
                    user = new User();
                    user.setId(rs.getInt("id"));
                    user.setUsername(rs.getString("username"));
                    user.setPassword(rs.getString("password"));
                }
                return user;
            }
        };

        final User user = run.query(
                "SELECT id, username, password FROM users WHERE username = ? AND active = 2 LIMIT 1;", handler,
                username);

Would it be possible to wrap the QueryRunner in a generic class and override the query method so the handler instanciate the generic T with the ResultSet. I would make sure any T type would ahve a constructor accepting a ResultSet .

Like so :

        public class QueryExecuter<T> extends QueryRunner {
    private ResultSetHandler<T> _handler;

    public QueryExecuter(){//The T type was for testing haha
        super();
        handler = new ResultSetHandler<T>() {

            @Override
            public T handle(ResultSet rs) throws SQLException {

                T object = null;
                if (rs.next()) {
                    object = new T(rs);
                }
                return object;
            }
        };
    }
}

I don't know if you'll understand, but I hope so, ask me if you want more details or a better explanation.

EDIT

I thought I could use a AbstractClass instead of the generic type that all of the differents objects would extends but it seems like I can't write an abstract constructor. Will I have to make a static method that return an instance of the object like:

public abstract class DatabaseEntity {
    public static abstract DatabaseEntity create(ResultSet rs);//even this doesn't work...
}

Possible, yes? But its a bad idea.

You could do:

class ResultSetHandler<T> {
  ResultSetHandler<T>(Class<T> clazz) {
    this.clazz = clazz;
  }

  public T handle(ResultSet rs) throws SQLException {
    T object = null;
    if (rs.next()) {
      object = clazz.getConstructor(ResultSet.class).newInstance(rs)
    }
    return object;
  }
}

Mixing domain and database is a bad idea, however. What would be better, however, would be to define an abtract method that creates the object based on the resultset:

abstract class ResultSetHandler<T> {

  protected abstract T create(ResultSet rs);

  public T handle(ResultSet rs) throws SQLException {
    T object = null;
    if (rs.next()) {
      object = create(rs);
    }
    return object;
  }
}

Then, in your implementing class, you only need to provide a create() method instead of handling the result set yourself, for example:

h = new ResultSetHandler<Person>() {
  protected Person create(ResultSet rs) {
    return new Person(rs.getString("name"));
  }
}

You could do something like that (by passing the class of the object to create, and use reflection to call its constructor), but I would find it bad design to have the POJO dependent on JDBC, and knowing not only how it's stored in database, but also which aliases have been used in the query used to load it.

In short, it's not the responsibility of the User POJO constructor to handle a result set of an external, unknown query.

You could design an AbstractSingleEntityHandler superclass which would just have the

if (rs.next()) {

block, and would delegate the actual entity creation to an abstract method, but you wouldn't gain much.

I do not think it is possible to do this in Java. You cannot create an instance of T in a generic. Generics in java are not really templates as in C++, they are only syntax sugar around an object which removes the casts and induces compile time warnings.

There is no way like in C# to constrain T so that it must have a constructor.

Your best bet if this is really neccessary is to resolve the appropriate class using reflection, but even then you will run into problem since you cannot know the runtime class of T as the method is being invoked - this information is stripped from the java bytecode. So you are left with passing the class to the method in order to use reflection on it. And I'm not too sure this is a good design idea anyway.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM