0

I'm re-engineering an app that I've been writing and in doing so I'm currently separating table definitions into different interfaces, one per table and then an overall interface for the whole database.

In doing so I have some common constants, in the overall interface, that are used in the table interfaces. The overall, interface also utilises constants from the table interfaces.

I've compiled and successfully run an app (basically the ubiquitous Hello World app with just two additional lines of code) using this and all appears to be fine. I'm actually quite surprised that this compiles.

Basically, am I taking a path doomed to cause problems.

Here's some example code:-

Interface DBAislesTableConstants Note! reduced to just 1 row

import static mjt.shopwise.DBConstants.DEFAULTORDER;
import static mjt.shopwise.DBConstants.IDTYPE;
import static mjt.shopwise.DBConstants.INT;
import static mjt.shopwise.DBConstants.PERIOD;
import static mjt.shopwise.DBConstants.STD_ID;
import static mjt.shopwise.DBConstants.TXT;

public interface DBAislesTableConstants {
    String AISLES_ID_COL = STD_ID;
    String AISLES_ID_COL_FULL = AISLES_TABLE +
            PERIOD +
            AISLES_ID_COL;
    String AISLES_ALTID_COL = AISLES_TABLE + STD_ID;
    String AISLES_ALTID_COL_FULL = AISLES_TABLE +
            PERIOD +
            AISLES_ALTID_COL;
    String AISLES_ID_TYPE = IDTYPE;
    Boolean AISLES_ID_PRIMARY_INDEX = true;
    DBColumn AISLESIDCOL = new DBColumn(AISLES_ID_COL,
            AISLES_ID_TYPE,
            AISLES_ID_PRIMARY_INDEX,
            ""
    );

    ArrayList<DBColumn> AISLESCOLS = new ArrayList<>(Arrays.asList(AISLESIDCOL));
    DBTable AISLESTABLE = new DBTable(AISLES_TABLE,AISLESCOLS);
}

DBColum and DBTable are defined classes with methods used to build what I'll can an internal schema used for creating and updating the actual database.

Interface DBConstants is :-

import java.util.ArrayList;
import java.util.Arrays;

import static mjt.shopwise.DBAislesTableConstants.AISLESTABLE;
import static mjt.shopwise.DBProductsTableConstants.PRODUCTSTABLE;
import static mjt.shopwise.DBShopsTableConstants.SHOPSTABLE;

interface DBConstants {

    String DATABASE_NAME = "ShopWise";
    String STD_ID = "_id";
    String PERIOD = ".";
    String INT = "INTEGER";
    String TXT = "TEXT";
    String IDTYPE = INT;
    String DEFAULTORDER = "1000";


    ArrayList<DBTable> SHOPWISETABLES = new ArrayList<>(Arrays.asList(
            AISLESTABLE));
    DBDatabase SHOPWISE = new DBDatabase(DATABASE_NAME,SHOPWISETABLES);

}

DBDatabase is a defined class for the whole database e.g. below I use the generateExportSchemaSQL method.

To test this I've used the following, which creates the SQL to create all the tables (ran this and dropped the SQL into SQLite Manager and it created the tables). stophere was just used for a breakpoint so I could inspect and copy the SQL.

String sql = DBConstants.SHOPWISE.generateExportSchemaSQL();
int stophere = 0;
Ekta Padaliya
  • 5,743
  • 3
  • 39
  • 51
MikeT
  • 51,415
  • 16
  • 49
  • 68
  • some questions: your interfaces define constant values only, is that right? and, what issues are you expecting? – nandsito Nov 16 '16 at 09:23
  • Yes only constants. My concern is that referencing each other may cause issues, although from a small test it appears to be ok to do that. e.g.DBAislesTableConstants uses values from DBConstants and vice-versa (there will be 7 DB???TablesConstants each getting values from DBConstants, works with 3 done to date). – MikeT Nov 16 '16 at 09:51

1 Answers1

1

Syntactically, cross-referencing classes (or interfaces, for that matter) is not a problem.

I made a test program. All classes are in the same package. Using IntelliJ IDEA 2016.2.5 and Oracle JDK 1.8.0_112, it compiles with no warnings and runs with no exceptions:

class ClassOne {
    static final String CONSTANT_ONE = ClassTwo.CONSTANT_TWO;
}
class ClassTwo {
    static final String CONSTANT_TWO = ClassOne.CONSTANT_ONE;
}
interface InterfaceOne {
    String VALUE_ONE = InterfaceTwo.VALUE_TWO;
}
interface InterfaceTwo {
    String VALUE_TWO = InterfaceOne.VALUE_ONE;
}
public class Main {
    public static void main(String[] args) {
        System.out.println(InterfaceOne.VALUE_ONE == null);
        System.out.println(InterfaceTwo.VALUE_TWO == null);
        System.out.println(ClassOne.CONSTANT_ONE == null);
        System.out.println(ClassTwo.CONSTANT_TWO == null);
    }
}

The output is:

true
true
true
true

Thus leading to a semantic issue. While Java allows cyclic reference of classes and even its fields, in runtime they will be null, which most probably is not the expected value the developer wanted to assign to the fields.

In sum, you should pay attention to cyclic references in fields.

By the way, you should define constants in classes instead of interfaces. See this question: What is the use of interface constants?

Community
  • 1
  • 1
nandsito
  • 3,782
  • 2
  • 19
  • 26
  • I'm playing with using classes instead of interfaces. One thing the advice is pretty even more cyclic than what I'm doing :). I used interfaces due to seeing Q & A's on here suggesting them in preference to classes. – MikeT Nov 16 '16 at 12:17
  • @MikeT yes, i intended to push the *cyclicness* to the limit, and see how Java responds to it – nandsito Nov 16 '16 at 12:27