1

I think this explains my question well enough:

public class Model {
    public static Model [] findAllBySQL(String SQL){
        //this is simplified.  It should really query the DB and then fill model(s) with the DB values, and return the model(s).  sql query can return more than one row
        return new this(); //sytax error here
    }
}


public class UserModel extends Model {

}


UserModel.findAllBySQL("firstname=john") //How do I design the above so this returns a UserModel object?

I'm relatively new to Java. My background is mostly PHP. I am trying to create a simple home-made active record system.. I know this is recreating the wheel, but that's how I learn :)

EDIT: Most of you guys misunderstood me. I know how to simple to new UserModel(). I changed the code to make it more clear.

Jonah
  • 2,040
  • 7
  • 29
  • 32
  • @Jonah - see edited answer, is that what you meant? – MByD Apr 10 '11 at 05:41
  • Are you expecting this to query an SQL database and return an object filled in with values from that database? If so look into a library called "Hibernate". Java does not have any SQL integration built-in. – Bill K Apr 10 '11 at 06:04
  • @Bill I heard about Hibernate but I would rather create my own library, in order to learn Java better and since I need something ultra simple right now. Also, I am using java.sql – Jonah Apr 10 '11 at 06:09
  • In that case you need to use an SQL class library (like http://download.oracle.com/javase/1.4.2/docs/api/java/sql/package-summary.html) to execute a query, then create a class with exactly the same attributes (variables) as you have in the table. You then copy over each variable by hand from the query into the class. This is exactly why they created hibernate, it's what hibernate does. – Bill K Apr 10 '11 at 06:19
  • I was thinking of storing the results of the query into a HashMap in the model. Then there would be a getAttribute(String attribute) method in the Model class, which returns the attribute. I can't argue that this is a better approach than Hibernate's.. but it doesn't require you to list all the table attributes as class attributes – Jonah Apr 10 '11 at 06:39
  • Actually that's a good solution @Jonha. I've done this--the trick is to wrap the HashMap in a class that can do stuff like validation (if you change an attribute and want it written back, ensure the type is correct), etc. You also want to ensure that a caller doesn't accidentally add an attribute by doing a set() with a misspelled name. Even if you just use it for getting then you'll still find the wrapper class very useful. I had a huge xml metadata structure defining the values in this meta-class but you may be able to get the meta out of the DB. – Bill K Apr 13 '11 at 20:27
  • Yes, I was planning on getting the meta data of the tables straight from the DB. I know this is possible because it is what the Yii Framework does in PHP. This way, my class should know the types of all the columns – Jonah Apr 17 '11 at 06:10

6 Answers6

2

Why not simply use new operator as

UserModel userModel = new UserModel();

To know different ways to create an object in java see this thread: what-are-all-the-different-ways-to-create-an-object-in-java


Edit

Based on your edit what you can do is?

public static Model findBySQL(String SQL){
        Model model = new Model();
        // Now query in db to get data. then use setter methods of Model to set data in object
        // i.e. model.setXXX(XXX);
        // and finally return that model object.
        return model;
    }

Edit 2

UserModel could have getFullName() which concatenates the first name with the last name from the db. I would need to be able to access this method straight away on the object returned from findBySQL

You can try like this: in UserModel,

public String getFullName(){
    Model model = findBySql("str='str'");
    return model.getFirstName()+"  "+model.getLastName();
}
Community
  • 1
  • 1
Harry Joy
  • 58,650
  • 30
  • 162
  • 207
  • I don't think so.. this will return a Model object.. but I need an object of the type of the caller.. – Jonah Apr 10 '11 at 05:51
  • @Jonah: Because `UserModel` extends `Model` you can easily parse it to caller. Or You can change the return type to caller. – Harry Joy Apr 10 '11 at 05:52
  • Not sure what you mean (I am new to Java, remember). I would need to be able to call methods from the sub-class. Eg UserModel could have getFullName() which concatenates the first name with the last name from the db. I would need to be able to access this method straight away on the object returned from findBySQL – Jonah Apr 10 '11 at 05:56
  • No.. I need it to be more flexible. For instance I want usage like this: UserModel u = UserModel.findBySQL(...); print(u.getFullName()); print(u.getOtherDynamicField()); – Jonah Apr 10 '11 at 06:12
  • @Jonah: then you should try using [generic types](http://download.oracle.com/javase/tutorial/java/generics/gentypes.html). – Harry Joy Apr 10 '11 at 06:15
2

You should use a constructor:

public class Model {
    //Constructor
    public Model()
    {
    // Do initialization stuff here
    }
}


public class UserModel extends Model {
    //Constructor
    public UserModel()
    {
    // Do initialization stuff here
    }
}

To create new object, you call it like that:

UserModel myUserModel;    // Declare new object reference
myUserModel = new UserModel();   // create new object of this class

Edit:

If you declare the method as a method returning array of Models, you can't return a single model, you may return a Model array with one Model, but not a single object.

For example

public static Model [] findAllBySQL(String SQL){
    // find how many models do you have
    Model[] models = new Model[numberOfModels];
    for (Model model : models)
    {
         model = new Model();
         //do what you want with it...
    }
    return models; //sytax error here
}
MByD
  • 135,866
  • 28
  • 264
  • 277
1

Sounds like you need the Factory Method Pattern. If you have a Model super class and several types of Models then you can encapsulate the object creation in a ModelFactory class with a createModel() method that returns the appropriate type of Model based on the parameter to the method.

 class ModelFactory(){
       public Model createModel(String sql, String type){
            //execute SQL

            if(type.equals("user")){
                 UserModel model = new UserModel();
                 //set the attributes here
                 return model;
            }

            if(type.equals("other")){
                 OtherModel model = new OtherModel();
                 //set attributes here
                 return model;
            }

             //etc
       }
 }

To actually get a Model object you can now:

       ModelFactory factory = new ModelFactory();
       Model m = factory.createModel("select * from mytable", "user");
Vincent Ramdhanie
  • 102,349
  • 23
  • 137
  • 192
  • This is the best solution so far. The only thing I don't like: createModel() is not DRY. Any way to make it DRY? I do not want to have to add to createModel() every time I add a new model to my application :/ (Rant: This is why I do not like strong typing) – Jonah Apr 10 '11 at 06:17
  • The advantage of the Factory pattern is that the object creation logic is encapsulated in one place, unfortunately that place needs to be changed as your model changes. It may be possible to use reflection to avoid this. See http://download.oracle.com/javase/tutorial/reflect/member/ctorInstance.html for some details on instantiating objects by reflection. – Vincent Ramdhanie Apr 10 '11 at 11:43
0

This is how you use this

UserModel m = new UserModel();

UserModel m now has all functions/values from
UserModel + the functions/values from Model.

Example

public class Model {
    public Model()
    {
    // Do initialization stuff here
    }

    public getVal(){
        return 1+1;
    }
}


public class UserModel extends Model {
    public UserModel()
    {
    // Do initialization stuff here
    }

    public getValue2(){
        return 2+2;
    }
}


UserModel m = new UserModel();

m.getVal(); //Will return 2
m.getValue2(); // Will return 4
Mark Mooibroek
  • 7,636
  • 3
  • 32
  • 53
0

You can do it in this way :

import java.util.ArrayList;
import java.util.List;
import sun.reflect.generics.reflectiveObjects.NotImplementedException;

public class Generics<T> {

    //method that returns a generic list
    public List<T> findAllBySQL(String SQL) {
        throw new NotImplementedException();
    }

    public static void main(String[] args) {
        //base class that returns a list of childs
        Generics result = new ExtendedGenerics(null);
        List<ExtendedGenerics> genericArray = result.findAllBySQL(null);
        for (ExtendedGenerics item : genericArray) {
            System.out.println(item);
        }
    }
}

//extend base class and specify generic type
class ExtendedGenerics extends Generics<ExtendedGenerics> {

    private String myMessage;

    public ExtendedGenerics(String yourMessage) {
        myMessage = yourMessage;
    }

    @Override
    //overriding base method, so it return a instances list of this class 
    public List<ExtendedGenerics> findAllBySQL(String SQL) {
        ArrayList<ExtendedGenerics> result = new ArrayList<ExtendedGenerics>();
        result.add(new ExtendedGenerics("I am first"));
        result.add(new ExtendedGenerics("I am second"));
        result.add(new ExtendedGenerics("I am third"));
        return result;
    }

    @Override
    public String toString() {
        return "ExtendedGenerics{" + myMessage + '}';
    }
}

So in this way no casting in necessary. This is the output of the code :

ExtendedGenerics{I am first}
ExtendedGenerics{I am second}
ExtendedGenerics{I am third}
StKiller
  • 7,631
  • 10
  • 43
  • 56
0

You can use Factory Method plus Java Generics:

public class Model {
  public static <T> T[] findAllBySQL(String SQL, Class<T extends Model> type) {
    T[] result = new T[123];
    for (int i = 0; i < 123; i++) {
      result[i] = type.newInstance();
    }
    return result;
  }
}
public class UserModel extends Model {
}
Model[] rowset = UserModel.findAllBySQL("firstname=john", UserModel.class); 

I assume this is the alternative of a plain simple PHP construct:

new $type();
yegor256
  • 102,010
  • 123
  • 446
  • 597