1

I'm coding a SQL generator based on java reflection (it's intended to be used with generics in the future). I receive an object as a parameter to generate the table name, fields and field values (for insert and update operations), but in my DAO classes I'm instantiating a new empty object, that won't be used anywhere else in the code, just obtain these information. Is there a way to cast some sort of "ghost" object, which won't occupy memory space, to serve this purpose?

This is the class responsible for generating the SQL:

public abstract class DynamicSQL
{
    public static final boolean NO_ID = false;
    public static final boolean WITH_ID = true;

    private Vector<Field> get_class_fields(Object obj, id_wanted)
    {
        Class<?> cls = obj.getClass();
        Vector<Field> fields = new Vector<>();

        while(cls != Object.class)
        {
            Field[] cls_flds = cls.getDeclaredFields();
            fields.addAll(Arrays.asList(cls_flds));

            cls = cls.getSuperclass();
        }
        // If the id is not wanted, it is removed here
        if(!id_wanted)
        {
            for(int i = 0; i < fields.size(); i += 1)
            {
                Field f = fields.get(i);
                if(f.getName().equals("id")) 
                                fields.remove(f);
            }
        }
        return fields;
    }

    private Vector<String> get_fields_names(Object obj, boolean id)
    {
        Vector<Field> fields = get_class_fields(obj, id);
        Vector<String> field_names = new Vector<>();

        for(Field f : fields)
        {
            field_names.add(f.getName());
        }
        return field_names;
    }

    private String get_table_name(Object obj) 
    {
        String[] class_name = obj.getClass().getName().toLowerCase().split("\\.");
        String table_name = class_name[class_name.length - 1];

        return table_name;
    }

    protected String select_sql(Object obj)
    {
        String table_name = get_table_name(obj);
        Vector<String> fields = get_fields_names(obj, WITH_ID);

        String sql = "SELECT ";
        for(int i = 0; i < fields.size(); i += 1)
        {
            sql += fields.get(i);
            if(i < fields.size()-1) sql += ", ";
        }
        sql += " FROM " + table_name;
        return sql;
    }

        //work in progress...
}

This is my DAO class:

public class CustomerDAO extends DynamicSQL implements IDAO<Customer>
{
    @Override
    public Vector<Customer> list_all() 
    {
        Vector<Customer> customers = new Vector<>();

        //Here I instantiate the object I'm willing to get rid of
        String sql = select_sql(new Customer.Builder().build(), DynamicSQL.WITH_ID);
        try
        {
            ResultSet rs = ConnectionFactory.get_instance().execute_query(sql);

            while(rs.next())
            {
                customers.add(new Cliente.Builder().
                        id(rs.getLong("id")).
                        nome(rs.getString("nome")).
                        endereco(rs.getString("endereco")).
                        telefone(rs.getString("telefone")).
                        build()
                        );
            }
        }
        catch(SQLException e)
        {
            e.printStackTrace();
        }
        return customers;
    }

    //other method overrides and implementation...
}

Everything runs fine, but I'm annoyed with that unnecessary object instantiation. Is there another way to do it, or do I need to instantiate that object anyway?

sandmann
  • 363
  • 2
  • 13
  • 2
    You shouldn't. Nobody is smarter than any of jvm and it's garbage collectors, even than the earliest ones. Keep code readable and maintainable, jvm will do the rest. Optmize only it you have a proven bottleneck here. – lotor Oct 09 '19 at 13:12
  • To make it (also semantically) clear that it's just a constant dummy value, I’d put the dummy into a `private static final CUSTOMER_DUMMY = …` constant. But on the other hand (at least from looking in above's code): Why don't you pass a `Class` object instead of the instance (ie. go for `Customer.class` instead)? – qqilihq Oct 09 '19 at 13:15
  • Instead of the parameter `Object obj`, pass a `Class> type`. There are other similar mature solutions, like JPA (eclpiseLink). – Joop Eggen Oct 09 '19 at 13:20

1 Answers1

3

In Java, you can never directly access objects. What you have is object references (like pointers in C or C++) that can refer to an object. Therefore different classes and methods can share objects by using different object references that refer to (point to) the same object. If several classes (or methods) share objects, rather than each creating a new object for their sole use, no additional space is used for the second and subsequent uses. So although you can not create a ghost object, you can do something equivalent by sharing objects. This works best if the objects are immutable.

If a method uses an equivalent immutable object every time (which seems to be the case for your method), you can save the cost of object creation by changing the object to be a static object, so the object is created when the class is loaded and shared for all subsequent method executions.

This is what the Collections.emptyList() method does:

Implementations of this method need not create a separate List object for each call.

Raedwald
  • 46,613
  • 43
  • 151
  • 237