My Java Assignment 2
Specification.html
This assignment ties together assignment #1 and #2. Assignment #1 had you read the first part of the class file, up until the start of the constant pool. Assignment #2 had you read each type of constant pool entry. Assignment 3 has you read the whole constant pool + the access flags, this class, super class, and the interfaces. Again, look here for the structure: https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-4.html#jvms-4.1
I inadvertently forgot the ConstantPoolModule tests in assignment #2, so that is added in #3.
You will need to update the ClassFile to read more parts of the file, but I would do that after writing the rest of the classes. I suggest you try to pass the tests in this order:
1) ConstantPoolModuleTests
2) DefaultConstantPoolFactoryTests
3) ConstantPoolTests
4) InterfacePoolTests
5) MissingConstantPoolCountTests
6) ShortConstantPoolCountTests
7) ClassFileTest
8) All of the tests in the "classes" tests directory.
The files in the "classes" test directory were created from the source files in the "classes.zip" file. What I did was compile the classes and then generate code to get the bytes and then generate the test files. That means that the data we are using came directly from the compiler. Dod you really think i made all of these tests by hand? :-) You can use programs to automate everything. YOU DO NOT NEED TO COMPILE OR EVEN LOOK AT THE FILES (it is a good idea to look at them).
As you go through the tests you will be able to start to see how a .java file is converted to a .class file, which is the other part of this set of assignments. You actually lear a lot about Java when you understand how the class file fits together.
Also, two things about the constant pool:
- the 0 index is always null
- for long and double they take up 2 slots, that means that the entry after them is null.
Assignment 3.zip
Assignment 3/.DS_Store
__MACOSX/Assignment 3/._.DS_Store
Assignment 3/Assignment 3.iml
Assignment 3/.idea/uiDesigner.xml
Assignment 3/.idea/.gitignore
# Default ignored files /shelf/ /workspace.xml
Assignment 3/.idea/workspace.xml
1592102201333 1592102201333
Assignment 3/.idea/modules.xml
Assignment 3/.idea/misc.xml
Assignment 3/src/.DS_Store
__MACOSX/Assignment 3/src/._.DS_Store
Assignment 3/.idea/codeStyles/codeStyleConfig.xml
Assignment 3/.idea/libraries/org_hamcrest_hamcrest_2_2.xml
Assignment 3/src/test/.DS_Store
__MACOSX/Assignment 3/src/test/._.DS_Store
Assignment 3/src/main/.DS_Store
__MACOSX/Assignment 3/src/main/._.DS_Store
Assignment 3/src/test/ca/.DS_Store
__MACOSX/Assignment 3/src/test/ca/._.DS_Store
Assignment 3/src/main/ca/.DS_Store
__MACOSX/Assignment 3/src/main/ca/._.DS_Store
Assignment 3/src/test/ca/bcit/.DS_Store
__MACOSX/Assignment 3/src/test/ca/bcit/._.DS_Store
Assignment 3/src/main/ca/bcit/.DS_Store
__MACOSX/Assignment 3/src/main/ca/bcit/._.DS_Store
Assignment 3/src/test/ca/bcit/comp2526/ShortMagic1Tests.java
Assignment 3/src/test/ca/bcit/comp2526/ShortMagic1Tests.java
package
ca
.
bcit
.
comp2526
;
import
org
.
junit
.
jupiter
.
api
.
Test
;
import
static
org
.
hamcrest
.
CoreMatchers
.
equalTo
;
import
static
org
.
hamcrest
.
MatcherAssert
.
assertThat
;
import
static
org
.
junit
.
jupiter
.
api
.
Assertions
.
assertThrows
;
public
class
ShortMagic1Tests
extends
ClassFileTest
{
@
Test
public
void
createClassFile
()
{
final
NotEnoughDataException
ex
;
ex
=
assertThrows
(
NotEnoughDataException
.
class
,
()
->
createClassFile
(
new
byte
[]
{
(
byte
)
0xCA
}));
assertThat
(
ex
.
getMessage
(),
equalTo
(
"Require 4 bytes to be available, have: 1"
));
}
}
Assignment 3/src/test/ca/bcit/comp2526/ByteUtils.java
Assignment 3/src/test/ca/bcit/comp2526/ByteUtils.java
package
ca
.
bcit
.
comp2526
;
import
java
.
io
.
*
;
public
final
class
ByteUtils
{
private
ByteUtils
()
{
throw
new
IllegalStateException
(
"Do not create instances"
);
}
public
static
DataInputStream
createStream
(
final
byte
[]
...
bytes
)
throws
IOException
{
try
(
final
ByteArrayOutputStream
byteStream
=
new
ByteArrayOutputStream
())
{
final
byte
[]
allBytes
;
for
(
final
byte
[]
array
:
bytes
)
{
byteStream
.
writeBytes
(
array
);
}
allBytes
=
byteStream
.
toByteArray
();
return
new
DataInputStream
(
new
ByteArrayInputStream
(
allBytes
));
}
}
public
static
byte
[]
byteToBytes
(
final
byte
value
)
throws
IOException
{
final
ByteArrayOutputStream
byteStream
;
byteStream
=
new
ByteArrayOutputStream
();
try
(
final
var stream
=
new
DataOutputStream
(
byteStream
))
{
final
byte
[]
bytes
;
stream
.
writeByte
(
value
);
bytes
=
byteStream
.
toByteArray
();
return
bytes
;
}
}
public
static
byte
[]
unsignedByteToBytes
(
final
int
value
)
throws
IOException
{
final
byte
[]
bytes
;
bytes
=
byteToBytes
((
byte
)
value
);
return
bytes
;
}
public
static
byte
[]
shortToBytes
(
final
short
value
)
throws
IOException
{
final
ByteArrayOutputStream
byteStream
;
byteStream
=
new
ByteArrayOutputStream
();
try
(
final
var stream
=
new
DataOutputStream
(
byteStream
))
{
final
byte
[]
bytes
;
stream
.
writeShort
(
value
);
bytes
=
byteStream
.
toByteArray
();
return
bytes
;
}
}
public
static
byte
[]
unsignedShortToBytes
(
final
int
value
)
throws
IOException
{
final
byte
[]
bytes
;
bytes
=
shortToBytes
((
short
)
value
);
return
bytes
;
}
public
static
byte
[]
intToBytes
(
final
int
value
)
throws
IOException
{
final
ByteArrayOutputStream
byteStream
;
byteStream
=
new
ByteArrayOutputStream
();
try
(
final
var stream
=
new
DataOutputStream
(
byteStream
))
{
final
byte
[]
bytes
;
stream
.
writeInt
(
value
);
bytes
=
byteStream
.
toByteArray
();
return
bytes
;
}
}
public
static
byte
[]
unsignedIntToBytes
(
final
long
value
)
throws
IOException
{
final
byte
[]
bytes
;
bytes
=
intToBytes
((
int
)
value
);
return
bytes
;
}
public
static
byte
[]
longToBytes
(
final
long
value
)
throws
IOException
{
final
ByteArrayOutputStream
byteStream
;
byteStream
=
new
ByteArrayOutputStream
();
try
(
final
var stream
=
new
DataOutputStream
(
byteStream
))
{
final
byte
[]
bytes
;
stream
.
writeLong
(
value
);
bytes
=
byteStream
.
toByteArray
();
return
bytes
;
}
}
public
static
byte
[]
floatToBytes
(
final
float
value
)
throws
IOException
{
final
ByteArrayOutputStream
byteStream
;
byteStream
=
new
ByteArrayOutputStream
();
try
(
final
var stream
=
new
DataOutputStream
(
byteStream
))
{
final
byte
[]
bytes
;
stream
.
writeFloat
(
value
);
bytes
=
byteStream
.
toByteArray
();
return
bytes
;
}
}
public
static
byte
[]
doubleToBytes
(
final
double
value
)
throws
IOException
{
final
ByteArrayOutputStream
byteStream
;
byteStream
=
new
ByteArrayOutputStream
();
try
(
final
var stream
=
new
DataOutputStream
(
byteStream
))
{
final
byte
[]
bytes
;
stream
.
writeDouble
(
value
);
bytes
=
byteStream
.
toByteArray
();
return
bytes
;
}
}
public
static
byte
[]
stringToBytes
(
final
String
value
)
throws
IOException
{
final
ByteArrayOutputStream
byteStream
;
byteStream
=
new
ByteArrayOutputStream
();
try
(
final
var stream
=
new
DataOutputStream
(
byteStream
))
{
final
byte
[]
bytes
;
stream
.
writeBytes
(
value
);
bytes
=
byteStream
.
toByteArray
();
return
bytes
;
}
}
}
Assignment 3/src/test/ca/bcit/comp2526/ShortMinorTests.java
Assignment 3/src/test/ca/bcit/comp2526/ShortMinorTests.java
package
ca
.
bcit
.
comp2526
;
import
org
.
junit
.
jupiter
.
api
.
Test
;
import
static
org
.
hamcrest
.
CoreMatchers
.
equalTo
;
import
static
org
.
hamcrest
.
MatcherAssert
.
assertThat
;
import
static
org
.
junit
.
jupiter
.
api
.
Assertions
.
assertThrows
;
public
class
ShortMinorTests
extends
ClassFileTest
{
@
Test
public
void
createClassFile
()
{
final
NotEnoughDataException
ex
;
ex
=
assertThrows
(
NotEnoughDataException
.
class
,
()
->
createClassFile
(
new
byte
[]
{
(
byte
)
0xCA
,
(
byte
)
0xFE
,
(
byte
)
0xBA
,
(
byte
)
0xBE
,
(
byte
)
0x00
}));
assertThat
(
ex
.
getMessage
(),
equalTo
(
"Require 2 bytes to be available, have: 1"
));
}
}
Assignment 3/src/test/ca/bcit/comp2526/.DS_Store
__MACOSX/Assignment 3/src/test/ca/bcit/comp2526/._.DS_Store
Assignment 3/src/test/ca/bcit/comp2526/MissingConstantPoolCountTests.java
Assignment 3/src/test/ca/bcit/comp2526/MissingConstantPoolCountTests.java
package
ca
.
bcit
.
comp2526
;
import
org
.
junit
.
jupiter
.
api
.
Test
;
import
static
org
.
hamcrest
.
CoreMatchers
.
equalTo
;
import
static
org
.
hamcrest
.
MatcherAssert
.
assertThat
;
import
static
org
.
junit
.
jupiter
.
api
.
Assertions
.
assertThrows
;
public
class
MissingConstantPoolCountTests
extends
ClassFileTest
{
@
Test
public
void
createClassFile
()
{
final
NotEnoughDataException
ex
;
ex
=
assertThrows
(
NotEnoughDataException
.
class
,
()
->
createClassFile
(
new
byte
[]
{
(
byte
)
0xCA
,
(
byte
)
0xFE
,
(
byte
)
0xBA
,
(
byte
)
0xBE
,
(
byte
)
0x00
,
(
byte
)
0x00
,
(
byte
)
0x00
,
(
byte
)
0x37
}));
assertThat
(
ex
.
getMessage
(),
equalTo
(
"Require 2 bytes to be available, have: 0"
));
}
}
Assignment 3/src/test/ca/bcit/comp2526/ShortMajorTests.java
Assignment 3/src/test/ca/bcit/comp2526/ShortMajorTests.java
package
ca
.
bcit
.
comp2526
;
import
org
.
junit
.
jupiter
.
api
.
Test
;
import
static
org
.
hamcrest
.
CoreMatchers
.
equalTo
;
import
static
org
.
hamcrest
.
MatcherAssert
.
assertThat
;
import
static
org
.
junit
.
jupiter
.
api
.
Assertions
.
assertThrows
;
public
class
ShortMajorTests
extends
ClassFileTest
{
@
Test
public
void
createClassFile
()
{
final
NotEnoughDataException
ex
;
ex
=
assertThrows
(
NotEnoughDataException
.
class
,
()
->
createClassFile
(
new
byte
[]
{
(
byte
)
0xCA
,
(
byte
)
0xFE
,
(
byte
)
0xBA
,
(
byte
)
0xBE
,
(
byte
)
0x00
,
(
byte
)
0x00
,
(
byte
)
0x00
}));
assertThat
(
ex
.
getMessage
(),
equalTo
(
"Require 2 bytes to be available, have: 1"
));
}
}
Assignment 3/src/test/ca/bcit/comp2526/DefaultConstantPoolEntryFactoryTest.java
Assignment 3/src/test/ca/bcit/comp2526/DefaultConstantPoolEntryFactoryTest.java
package
ca
.
bcit
.
comp2526
;
import
ca
.
bcit
.
comp2526
.
constantpool
.
*
;
import
org
.
junit
.
jupiter
.
api
.
BeforeAll
;
import
org
.
junit
.
jupiter
.
api
.
Test
;
import
org
.
junit
.
jupiter
.
api
.
TestInstance
;
import
java
.
io
.
IOException
;
import
static
org
.
hamcrest
.
MatcherAssert
.
assertThat
;
import
static
org
.
hamcrest
.
Matchers
.
equalTo
;
import
static
org
.
hamcrest
.
Matchers
.
instanceOf
;
@
TestInstance
(
TestInstance
.
Lifecycle
.
PER_CLASS
)
public
class
DefaultConstantPoolEntryFactoryTest
{
private
DefaultConstantPoolEntryFactory
factory
;
@
BeforeAll
public
void
setup
()
{
factory
=
new
DefaultConstantPoolEntryFactory
();
}
@
Test
public
void
testCreateConstantPoolEntryClass
()
throws
InvalidReferenceKindException
,
InvalidConstantPoolIndexException
,
NotEnoughDataException
,
InvalidConstantPoolTagException
,
IOException
{
final
ConstantPoolEntry
entry
;
final
ConstantPoolEntryClass
specificEntry
;
entry
=
factory
.
createConstantPoolEntry
(
ConstantPoolType
.
CLASS
,
ByteUtils
.
createStream
(
ByteUtils
.
unsignedShortToBytes
(
3
)));
assertThat
(
entry
.
getType
(),
equalTo
((
ConstantPoolType
.
CLASS
)));
assertThat
(
entry
,
instanceOf
(
ConstantPoolEntryClass
.
class
));
specificEntry
=
(
ConstantPoolEntryClass
)
entry
;
assertThat
(
specificEntry
.
getNameIndex
(),
equalTo
(
3
));
}
@
Test
public
void
testCreateConstantPoolEntryDouble
()
throws
InvalidReferenceKindException
,
InvalidConstantPoolIndexException
,
NotEnoughDataException
,
InvalidConstantPoolTagException
,
IOException
{
final
ConstantPoolEntry
entry
;
final
ConstantPoolEntryDouble
specificEntry
;
entry
=
factory
.
createConstantPoolEntry
(
ConstantPoolType
.
DOUBLE
,
ByteUtils
.
createStream
(
ByteUtils
.
doubleToBytes
(
123.456
)));
assertThat
(
entry
.
getType
(),
equalTo
((
ConstantPoolType
.
DOUBLE
)));
assertThat
(
entry
,
instanceOf
(
ConstantPoolEntryDouble
.
class
));
specificEntry
=
(
ConstantPoolEntryDouble
)
entry
;
assertThat
(
specificEntry
.
getValue
(),
equalTo
(
123.456
));
}
@
Test
public
void
testCreateConstantPoolEntryDynamic
()
throws
InvalidReferenceKindException
,
InvalidConstantPoolIndexException
,
NotEnoughDataException
,
InvalidConstantPoolTagException
,
IOException
{
final
ConstantPoolEntry
entry
;
final
ConstantPoolEntryDynamic
specificEntry
;
entry
=
factory
.
createConstantPoolEntry
(
ConstantPoolType
.
DYNAMIC
,
ByteUtils
.
createStream
(
ByteUtils
.
unsignedShortToBytes
(
1
),
ByteUtils
.
unsignedShortToBytes
(
2
)));
assertThat
(
entry
.
getType
(),
equalTo
((
ConstantPoolType
.
DYNAMIC
)));
assertThat
(
entry
,
instanceOf
(
ConstantPoolEntryDynamic
.
class
));
specificEntry
=
(
ConstantPoolEntryDynamic
)
entry
;
assertThat
(
specificEntry
.
getBootstrapMethodAttrIndex
(),
equalTo
(
1
));
assertThat
(
specificEntry
.
getNameAndTypeIndex
(),
equalTo
(
2
));
}
@
Test
public
void
testCreateConstantPoolEntryField
()
throws
InvalidReferenceKindException
,
InvalidConstantPoolIndexException
,
NotEnoughDataException
,
InvalidConstantPoolTagException
,
IOException
{
final
ConstantPoolEntry
entry
;
final
ConstantPoolEntryField
specificEntry
;
entry
=
factory
.
createConstantPoolEntry
(
ConstantPoolType
.
FIELD
,
ByteUtils
.
createStream
(
ByteUtils
.
unsignedShortToBytes
(
2
),
ByteUtils
.
unsignedShortToBytes
(
3
)));
assertThat
(
entry
.
getType
(),
equalTo
((
ConstantPoolType
.
FIELD
)));
assertThat
(
entry
,
instanceOf
(
ConstantPoolEntryField
.
class
));
specificEntry
=
(
ConstantPoolEntryField
)
entry
;
assertThat
(
specificEntry
.
getClassIndex
(),
equalTo
(
2
));
assertThat
(
specificEntry
.
getNameAndTypeIndex
(),
equalTo
(
3
));
}
@
Test
public
void
testCreateConstantPoolEntryFloat
()
throws
InvalidReferenceKindException
,
InvalidConstantPoolIndexException
,
NotEnoughDataException
,
InvalidConstantPoolTagException
,
IOException
{
final
ConstantPoolEntry
entry
;
final
ConstantPoolEntryFloat
specificEntry
;
entry
=
factory
.
createConstantPoolEntry
(
ConstantPoolType
.
FLOAT
,
ByteUtils
.
createStream
(
ByteUtils
.
floatToBytes
(
234.567f
)));
assertThat
(
entry
.
getType
(),
equalTo
((
ConstantPoolType
.
FLOAT
)));
assertThat
(
entry
,
instanceOf
(
ConstantPoolEntryFloat
.
class
));
specificEntry
=
(
ConstantPoolEntryFloat
)
entry
;
assertThat
(
specificEntry
.
getValue
(),
equalTo
(
234.567f
));
}
@
Test
public
void
testCreateConstantPoolEntryInteger
()
throws
InvalidReferenceKindException
,
InvalidConstantPoolIndexException
,
NotEnoughDataException
,
InvalidConstantPoolTagException
,
IOException
{
final
ConstantPoolEntry
entry
;
final
ConstantPoolEntryInteger
specificEntry
;
entry
=
factory
.
createConstantPoolEntry
(
ConstantPoolType
.
INTEGER
,
ByteUtils
.
createStream
(
ByteUtils
.
intToBytes
(
12
)));
assertThat
(
entry
.
getType
(),
equalTo
((
ConstantPoolType
.
INTEGER
)));
assertThat
(
entry
,
instanceOf
(
ConstantPoolEntryInteger
.
class
));
specificEntry
=
(
ConstantPoolEntryInteger
)
entry
;
assertThat
(
specificEntry
.
getValue
(),
equalTo
(
12
));
}
@
Test
public
void
testCreateConstantPoolEntryInterfaceMethod
()
throws
InvalidReferenceKindException
,
InvalidConstantPoolIndexException
,
NotEnoughDataException
,
InvalidConstantPoolTagException
,
IOException
{
final
ConstantPoolEntry
entry
;
final
ConstantPoolEntryInterfaceMethod
specificEntry
;
entry
=
factory
.
createConstantPoolEntry
(
ConstantPoolType
.
INTERFACE_METHOD
,
ByteUtils
.
createStream
(
ByteUtils
.
unsignedShortToBytes
(
1
),
ByteUtils
.
unsignedShortToBytes
(
4
)));
assertThat
(
entry
.
getType
(),
equalTo
((
ConstantPoolType
.
INTERFACE_METHOD
)));
assertThat
(
entry
,
instanceOf
(
ConstantPoolEntryInterfaceMethod
.
class
));
specificEntry
=
(
ConstantPoolEntryInterfaceMethod
)
entry
;
assertThat
(
specificEntry
.
getClassIndex
(),
equalTo
(
1
));
assertThat
(
specificEntry
.
getNameAndTypeIndex
(),
equalTo
(
4
));
}
@
Test
public
void
testCreateConstantPoolEntryInvokeDynamic
()
throws
InvalidReferenceKindException
,
InvalidConstantPoolIndexException
,
NotEnoughDataException
,
InvalidConstantPoolTagException
,
IOException
{
final
ConstantPoolEntry
entry
;
final
ConstantPoolEntryInvokeDynamic
specificEntry
;
entry
=
factory
.
createConstantPoolEntry
(
ConstantPoolType
.
INVOKE_DYNAMIC
,
ByteUtils
.
createStream
(
ByteUtils
.
unsignedShortToBytes
(
2
),
ByteUtils
.
unsignedShortToBytes
(
3
)));
assertThat
(
entry
.
getType
(),
equalTo
((
ConstantPoolType
.
INVOKE_DYNAMIC
)));
assertThat
(
entry
,
instanceOf
(
ConstantPoolEntryInvokeDynamic
.
class
));
specificEntry
=
(
ConstantPoolEntryInvokeDynamic
)
entry
;
assertThat
(
specificEntry
.
getBootstrapMethodAttrIndex
(),
equalTo
(
2
));
assertThat
(
specificEntry
.
getNameAndTypeIndex
(),
equalTo
(
3
));
}
@
Test
public
void
testCreateConstantPoolEntryLong
()
throws
InvalidReferenceKindException
,
InvalidConstantPoolIndexException
,
NotEnoughDataException
,
InvalidConstantPoolTagException
,
IOException
{
final
ConstantPoolEntry
entry
;
final
ConstantPoolEntryLong
specificEntry
;
entry
=
factory
.
createConstantPoolEntry
(
ConstantPoolType
.
LONG
,
ByteUtils
.
createStream
(
ByteUtils
.
longToBytes
(
9998L
)));
assertThat
(
entry
.
getType
(),
equalTo
((
ConstantPoolType
.
LONG
)));
assertThat
(
entry
,
instanceOf
(
ConstantPoolEntryLong
.
class
));
specificEntry
=
(
ConstantPoolEntryLong
)
entry
;
assertThat
(
specificEntry
.
getValue
(),
equalTo
(
9998L
));
}
@
Test
public
void
testCreateConstantPoolEntryMethodHandle
()
throws
InvalidReferenceKindException
,
InvalidConstantPoolIndexException
,
NotEnoughDataException
,
InvalidConstantPoolTagException
,
IOException
{
final
ConstantPoolEntry
entry
;
final
ConstantPoolEntryMethodHandle
specificEntry
;
entry
=
factory
.
createConstantPoolEntry
(
ConstantPoolType
.
METHOD_HANDLE
,
ByteUtils
.
createStream
(
ByteUtils
.
unsignedByteToBytes
(
MethodHandleKind
.
INVOKE_INTERFACE
.
getType
()),
ByteUtils
.
unsignedShortToBytes
(
1
)));