Question: Can a Java object with nested Java objects be stored in a table?
Yes, it can. Figure 1 shows the HelloWorld class from
Tip 81 - Getting Started, with some simplifications,
and Figure 2 shows another class NestedWorld
that contains an object of type HelloWorld.
Figure 1: Simplified HelloWorld.java From Tip 81
public class HelloWorld {
public String hello ;
public String world ;
public java.lang.Integer counter ;
HelloWorld () { // Constructor 1
hello = "Hello";
world = "World";
counter = new java.lang.Integer ( 1 );
}
HelloWorld ( String inHello, // Constructor 2
String inWorld,
int inCounter
) {
hello = inHello;
world = inWorld;
counter = new java.lang.Integer ( inCounter );
}
public String toString() {
return hello + " " + world + ": " + counter.toString();
}
public int compareTo( HelloWorld anotherHelloWorld ) {
// Compare first on the basis of counter
// and then on the basis of toString()
java.lang.Integer lVal = counter;
java.lang.Integer rVal = anotherHelloWorld.counter;
if ( lVal.intValue() > rVal.intValue() ) {
return 1;
}
else if (lVal.intValue() < rVal.intValue() ) {
return -1;
}
else {
return toString().compareTo( anotherHelloWorld.toString() );
}
}
}
|
Figure 2: NestedWorld.java Contains Object of Type HelloWorld
public class NestedWorld {
public HelloWorld nestedHelloWorld ;
public java.lang.Integer outerCounter ;
NestedWorld () { // Constructor 1
nestedHelloWorld = new HelloWorld();
outerCounter = new java.lang.Integer ( 999 );
}
NestedWorld ( String inHello, // Constructor 2
String inWorld,
int inCounter,
int inOuterCounter
) {
nestedHelloWorld = new HelloWorld ( inHello, inWorld, inCounter );
outerCounter = new java.lang.Integer ( inOuterCounter );
}
NestedWorld ( HelloWorld inHelloWorld, // Constructor 3
int inOuterCounter
) {
nestedHelloWorld = inHelloWorld;
outerCounter = new java.lang.Integer ( inOuterCounter );
}
public String toString() {
return nestedHelloWorld.toString()
+ ": " + outerCounter.toString();
}
public int compareTo( NestedWorld anotherNestedWorld ) {
// Compare first on the basis of counter
// and then on the basis of toString()
java.lang.Integer lVal = outerCounter;
java.lang.Integer rVal = anotherNestedWorld.outerCounter;
if ( lVal.intValue() > rVal.intValue() ) {
return 1;
}
else if (lVal.intValue() < rVal.intValue() ) {
return -1;
}
else {
return toString().compareTo( anotherNestedWorld.toString() );
}
}
}
|
Of particular interest in Figure 2 are the three constructors for NestedWorld.
The first one simply calls the default constructor for HelloWorld to initialize
nestedHelloWorld, and then fills in outerCounter with a default value.
The second constructor for NestedWorld expects values for all 4 base fields.
It passes the first 3 parameters on to the second constructor for HelloWorld,
and uses the 4th parameter to fill in outerCounter.
The third constructor for NestedWorld expects only 2 parameters but the first
one is of type HelloWorld. The caller is responsible for creating an object
of type HelloWorld and passing it to this constructor which then uses it to
initialize nestedHelloWorld. The other parameter is used to fill in outerCounter.
Figure 3 shows how the two classes are loaded into the database and used
to create a table called java_nested_world.
(Note: Simplified batch files for compiling classes and launching DBSRV6 and
DBISQL are shown in the Appendix.)
Figure 3: Install and Use NestedWorld.class
INSTALL JAVA NEW FROM FILE
'c:\\amisc\\ASAJava\\HelloWorld.class';
INSTALL JAVA NEW FROM FILE
'c:\\amisc\\ASAJava\\NestedWorld.class';
CREATE TABLE java_nested_world
( pkey INTEGER NOT NULL,
JNestedWorld NestedWorld NOT NULL,
PRIMARY KEY ( pkey ) );
/* Reverse-order removal:
DROP TABLE java_nested_world;
REMOVE JAVA CLASS NestedWorld;
REMOVE JAVA CLASS HelloWorld;
*/
|
Figure 4 shows how the three different constructors are invoked. The first INSERT
uses the first constructor to fill in the defaults, and the second INSERT uses
the constructor that expects all 4 base fields to be passed to it.
The other INSERTs use the third constructor for NestedWorld, with a nested
call to the second constructor for HelloWorld as the first argument. Support for
nested objects is provided all the way up to the SQL level, proving once
again that the folks at Watcom have their act together.
Figure 4: Insert and Select java_nested_world
INSERT INTO java_nested_world ( pkey, JNestedWorld )
VALUES ( 1, NEW NestedWorld() );
INSERT INTO java_nested_world ( pkey, JNestedWorld )
VALUES ( 2, NEW NestedWorld ( 'Hello', 'World', 0, 55 ) );
INSERT INTO java_nested_world ( pkey, JNestedWorld )
VALUES ( 3,
NEW NestedWorld
( NEW HelloWorld ( 'Hello', 'World', 2 ),
66 ) );
INSERT INTO java_nested_world ( pkey, JNestedWorld )
VALUES ( 4,
NEW NestedWorld
( NEW HelloWorld ( 'Good', 'Bye', 0 ),
77 ) );
INSERT INTO java_nested_world ( pkey, JNestedWorld )
VALUES ( 5,
NEW NestedWorld
( NEW HelloWorld ( 'Good', 'Bye', 2 ),
88 ) );
SELECT *
FROM java_nested_world
ORDER BY pkey;
|
Figure 5 shows what a simple SELECT * looks like when the classes implement
nested toString methods. Again, this works the way you would expect it to.
Figure 5: Insert and Select via DBISQL
Appendix: Handy Batch Files
Three handy batch files were set up to launch the Java compiler, ASA server and
DBISQL without worrying about directories, paths, etc. Here's how they are run
via Windows 95 Start - Run:
c:\amisc\ASAJava\run_javac NestedWorld
c:\amisc\ASAJava\run_dbsrv6 ASAJava
c:\amisc\ASAJava\run_dbisql
Figures 6, 7 and 8 show the contents of the batch files.
Figure 6: run_javac.bat
rem Start - Run Format: c:\amisc\ASAJava\run_javac [ClassName]
rem Define shortcuts for long paths:
SET ASA=E:\Program Files\Sybase\Adaptive Server Anywhere 6.0\java
SET JDK=e:\jdk1.1.6\bin
SET DEV=c:\amisc\ASAJava
rem Move to the development directory:
c:
cd "%DEV%"
rem Set the CLASSPATH for the compiler to use:
SET CLASSPATH=.;%ASA%;%ASA%\jdbcdrv.zip;%ASA%\asajdbc.zip
rem Compile %1.java into %1.class:
%JDK%\javac.exe -d %DEV% %1.java
|
Figure 7: run_dbsrv6.bat
rem Start - Run Format: c:\amisc\ASAJava\run_dbsrv6 [DBFileName]
rem Define shortcuts for long paths:
SET ASA=E:\Program Files\Sybase\Adaptive Server Anywhere 6.0\win32
SET DEV=c:\amisc\ASAJava
rem Move to the development directory:
c:
cd "%DEV%"
rem Start %1.db via DBSRV6:
"%ASA%\dbsrv6.exe" -x NONE -c 12m -gp 4096 %DEV%\%1.db
|
Figure 8: run_dbisql.bat
rem Start - Run Format: c:\amisc\ASAJava\run_dbisql
rem Define shortcuts for long paths:
SET ASA=E:\Program Files\Sybase\Adaptive Server Anywhere 6.0\win32
SET DEV=c:\amisc\ASAJava
rem Move to the development directory:
c:
cd "%DEV%"
rem Launch DBISQL:
"%ASA%\dbisql.exe" -c "UID=dba;PWD=sql"
|
|