Class subclass:#JavaClass
instanceVariableNames:'constantPool interfaces accessFlags classLoader fullName
sourceFile binaryFilePath fields initValues staticFields'
classVariableNames:'InitialValuePerType A_OBSOLETE A_INTERFACE A_PUBLIC A_FINAL
A_ABSTRACT A_INITIALIZED A_SMALLTALK A_ABSTRACT_OR_INTERFACE
ArgumentConversionErrorSignal OrderOfClassInits'
poolDictionaries:''
category:'Java-Classes'
!
!JavaClass class methodsFor:'documentation'!
documentation
"
fields upTo-and-including accessFlags are known & used by the VM
only add fields after those and keep their order intact.
"
!
examples
"
(Java at:'java.util.Stack') new inspect
(Java at:'java.util.Vector') new inspect
"
! !
!JavaClass class methodsFor:'initialization'!
initialize
"/ those are defined in Java and read from the classFile
A_PUBLIC := 16r000001.
"/ A_PRIVATE := 16r000002.
"/ A_PROTECTED := 16r000004.
A_STATIC := 16r000008.
A_FINAL := 16r000010.
"/ A_SUPER := 16r000020.
"/ A_SYNCHRONIZED := 16r000020.
"/ A_VOLATILE := 16r000040.
"/ A_TRANSIENT := 16r000080.
A_NATIVE := 16r000100.
A_INTERFACE := 16r000200.
A_ABSTRACT := 16r000400.
A_OBSOLETE := 16r008000.
"/ those are local to the ST/X implementation
A_INITIALIZED := 16r100000.
A_SMALLTALK := 16r200000.
A_ABSTRACT_OR_INTERFACE := A_ABSTRACT bitOr:A_INTERFACE.
InitialValuePerType := IdentityDictionary new.
InitialValuePerType at:$B put:0.
InitialValuePerType at:$C put:0.
InitialValuePerType at:$D put:0.0.
InitialValuePerType at:$F put:(0.0 asShortFloat).
InitialValuePerType at:$I put:0.
InitialValuePerType at:$J put:0.
InitialValuePerType at:$S put:0.
InitialValuePerType at:$Z put:0.
InitialValuePerType at:$L put:nil.
InitialValuePerType at:$[ put:nil.
ArgumentConversionErrorSignal := ErrorSignal newSignal mayProceed:true.
"
JavaClass initialize
"
"Modified: / 13.11.1998 / 14:09:52 / cg"
! !
!JavaClass class methodsFor:'instance creation'!
fullName:aString
self shouldNotImplement.
^ self new flags:0; setFullName:aString
!
fullName:aString numStatic:nStatic
|meta cls fullName parts s ns|
"/ check for a JAVA nameSpace to exist
JAVA isNil ifTrue:[
Namespace name:'JAVA'
].
"create the metaclass first"
meta := Metaclass new.
meta setSuperclass:(self).
meta instSize:(JavaClass instSize + nStatic).
"/ meta setName:(aString , 'class') asSymbol.
"/ meta setClassVariableString:''.
meta flags:(meta flags bitOr:Behavior flagJavaClass).
"/ meta setSuperclass:JavaObject class.
"then let the new meta create the class"
cls := meta new.
cls setSuperclass:JavaObject.
cls instSize:0.
cls setName:('JAVA::' , aString).
cls flags:0.
"/ cls setClassVariableString:''.
cls setInstanceVariableString:''.
cls category:#java.
cls setFullName:aString.
"/ break up the package and create nameSpaces
"/ for each package component.
"/ This allows java.foo.bar to be visible in ST/X
"/ under the name JAVA::java::foo::bar
ns := JAVA.
parts := aString asCollectionOfSubstringsSeparatedBy:$/.
parts size > 1 ifTrue:[
s := '' writeStream.
s nextPutAll:'JAVA'.
parts from:1 to:(parts size - 1) do:[:aPart |
s nextPutAll:'::'.
s nextPutAll:aPart
].
Metaclass confirmationQuerySignal answer:false do:[
Class updateChangeFileQuerySignal answer:false do:[
ns := Namespace fullName:(s contents).
]
]
].
ns isNamespace ifTrue:[
ns at:parts last asSymbol put:cls.
].
"/ for ST/X browsing
Smalltalk at:('JAVA::' , aString) asSymbol put:cls.
^ cls
"Created: / 15.4.1996 / 15:52:55 / cg"
"Modified: / 3.1.1998 / 22:32:25 / cg"
!
name:aString
self shouldNotImplement
"Created: 15.4.1996 / 15:52:55 / cg"
! !
!JavaClass class methodsFor:'constants'!
A_NATIVE
^ A_NATIVE
"Created: / 16.5.1998 / 01:18:43 / cg"
!
A_PUBLIC
^ A_PUBLIC
"Created: / 13.5.1998 / 13:03:18 / cg"
!
A_STATIC
^ A_STATIC
"Created: / 16.5.1998 / 00:02:07 / cg"
! !
!JavaClass class methodsFor:'method lookup'!
canConvertArgsToJava:argArray asSpecifiedIn:argSigSpecArray
"given a smalltalk argument array, return true, if these can be converted to java objects as appropriate."
argArray
with:argSigSpecArray
do:[:arg :type |
self
convertToJava:arg
type:type
ifFail:[:msg :default| ^ false]].
^ true
"Created: / 5.11.1998 / 18:25:05 / cg"
"Modified: / 6.11.1998 / 00:45:58 / cg"
!
convertArgsToJava:argArray asSpecifiedIn:argSigSpecArray numArgs:na
"given a smalltalk argument array, convert to java objects as appropriate.
Currently, only Strings and booleans are converted."
|sigIndex newArgIndex newArgArray|
sigIndex := newArgIndex := 1.
newArgArray := Array new:na.
argArray do:[:arg |
|type newArg|
type := argSigSpecArray at:sigIndex.
sigIndex := sigIndex + 1.
newArg := self convertToJava:arg type:type.
newArgArray at:newArgIndex put:newArg.
newArgIndex := newArgIndex + 1.
(type == #long or:[type == #double]) ifTrue:[
newArgIndex > na ifTrue:[
self halt:'should not happen'
].
newArgArray at:newArgIndex put:nil.
newArgIndex := newArgIndex + 1.
]
].
^ newArgArray
"Created: / 5.11.1998 / 18:30:57 / cg"
"Modified: / 6.11.1998 / 00:45:00 / cg"
!
convertToJava:arg type:type
"given a smalltalk argument, convert to a java object as appropriate."
^ self
convertToJava:arg
type:type
ifFail:[:msg :default |
ArgumentConversionErrorSignal
raiseWith:arg
errorString:msg.
default
]
"Modified: / 5.11.1998 / 18:43:33 / cg"
"Created: / 6.11.1998 / 00:45:13 / cg"
!
convertToJava:arg type:type ifFail:failBlock
"given a smalltalk argument, convert to a java object as appropriate.
Currently, only a few types are converted."
|expectedCls f|
type == #boolean ifTrue:[
arg == true ifTrue:[
^ 1
].
arg == false ifTrue:[
^ 0
].
^ failBlock value:('cannot convert argument to ' , type) value:0
].
type == #int ifTrue:[
arg isInteger ifTrue:[
(arg between:-16r8000000 and:16r7FFFFFFF) ifTrue:[
^ arg
].
^ failBlock value:('integer range; cannot convert argument to ' , type) value:0.
].
^ failBlock value:('cannot convert argument to ' , type) value:0
].
type == #long ifTrue:[
arg isInteger ifTrue:[
(arg between:-16r800000000000000 and:16r7FFFFFFFFFFFFFFF) ifTrue:[
^ arg
].
^ failBlock value:('integer range; cannot convert argument to ' , type) value:0
].
^ failBlock value:('cannot convert argument to ' , type) value:0
].
(type == #float) ifTrue:[
arg isReal ifTrue:[
^ arg asShortFloat
].
^ failBlock value:('cannot convert argument to ' , type) value:0.0.
].
(type == 'java.lang.Float') ifTrue:[
arg isReal ifTrue:[
f := (Java at:'java.lang.Float') new.
f perform:#'<init>(F)V' with:(arg asShortFloat).
self halt.
^ f.
].
^ failBlock value:('cannot convert argument to ' , type) value:0.0.
].
(type == 'java.lang.Double') ifTrue:[
arg isReal ifTrue:[
f := (Java at:'java.lang.Double') new.
f perform:#'<init>(D)V' with:(arg asFloat).
self halt.
^ f.
].
^ failBlock value:('cannot convert argument to ' , type) value:0.0.
].
(type == #double) ifTrue:[
arg isReal ifTrue:[
^ arg asFloat
].
^ failBlock value:('cannot convert argument to ' , type) value:0.0.
].
(type == #char) ifTrue:[
arg isCharacter ifTrue:[
^ arg asciiValue
].
^ failBlock value:('cannot convert argument to ' , type) value:0
].
(type = 'char[]') ifTrue:[
arg isString ifTrue:[
^ arg
].
^ failBlock value:('cannot convert argument to ' , type) value:''
].
(type = 'int[]') ifTrue:[
(arg isArray or:[arg isMemberOf:SignedIntegerArray]) ifTrue:[
^ arg
].
^ failBlock value:('cannot convert argument to ' , type) value:''
].
(type = 'long[]') ifTrue:[
(arg isArray or:[arg isMemberOf:SignedIntegerArray]) ifTrue:[
^ arg
].
^ failBlock value:('cannot convert argument to ' , type) value:''
].
(type = 'float[]') ifTrue:[
(arg isArray or:[arg isMemberOf:FloatArray]) ifTrue:[
^ arg
].
^ failBlock value:('cannot convert argument to ' , type) value:''
].
(type = 'double[]') ifTrue:[
(arg isArray or:[arg isMemberOf:DoubleArray]) ifTrue:[
^ arg
].
^ failBlock value:('cannot convert argument to ' , type) value:''
].
(type endsWith:'[]') ifTrue:[
(arg isArray or:[arg isNil]) ifTrue:[
^ arg
].
^ failBlock value:('cannot convert argument to ' , type) value:''
].
(type = 'java.lang.Object') ifTrue:[
"/ matches any
^ arg
].
(type = 'java.lang.String') ifTrue:[
arg isString ifTrue:[
^ Java as_String:arg
].
^ failBlock value:('cannot convert argument to ' , type) value:''
].
expectedCls := Java classForName:type.
(arg isKindOf:expectedCls) ifTrue:[
"/ matches class and subclasses
^ arg
].
self halt.
^ failBlock value:('cannot convert argument to ' , type) value:nil
"Created: / 6.11.1998 / 00:46:19 / cg"
"Modified: / 11.11.1998 / 02:05:25 / cg"
!
convertToSmalltalk:jObj type:type
"given a java return value, convert to a smalltalk object as appropriate.
Currently, only a few types are converted."
type == #boolean ifTrue:[
jObj == 0 ifTrue:[
^ false
].
^ true
].
type == #void ifTrue:[
^ nil
].
(type = 'java.lang.String') ifTrue:[
^ Java as_ST_String:jObj
].
"/ (type = 'java.lang.Float') ifTrue:[
"/ ^ jObj instVarNamed:'value'
"/ ].
"/ (type = 'java.lang.Double') ifTrue:[
"/ ^ jObj instVarNamed:'value'
"/ ].
(type == #char) ifTrue:[
jObj isInteger ifTrue:[
^ Character value:jObj
].
].
^ jObj
"Created: / 6.11.1998 / 00:49:53 / cg"
"Modified: / 11.11.1998 / 02:08:11 / cg"
!
lookupMethod:selector numArgs:nargs in:aClass static:staticMethod
"lookup a method"
|method cls sel|
sel := selector.
(sel includes:$:) ifTrue:[
sel := sel copyTo:(sel indexOf:$:)-1
].
sel := sel asSymbolIfInterned.
sel notNil ifTrue:[
cls := aClass.
[cls notNil
and:[cls ~~ JavaObject
and:[cls ~~ JavaClass]]] whileTrue:[
cls methodDictionary keysAndValuesDo:[:jSel :aMethod |
((jSel == sel)
or:[aMethod name = sel
or:[aMethod signatureNameWithoutReturnType = sel]])
ifTrue:[
aMethod numArgs == nargs ifTrue:[
staticMethod == (aMethod isStatic) ifTrue:[
^ aMethod
]
]
]
].
cls := cls superclass.
].
].
"/ self halt.
^ nil
"Created: / 17.8.1997 / 18:25:47 / cg"
"Modified: / 4.11.1998 / 17:13:08 / cg"
!
lookupMethods:selector numArgs:nargs in:aClass static:staticMethod
"lookup methods matching a selector.
This is a special entry for doesNotUnderstand redirection
(the caller must select the one method which fits the argument(s) best."
|methods cls sel|
sel := selector.
(sel includes:$:) ifTrue:[
sel := sel copyTo:(sel indexOf:$:)-1
].
sel := sel asSymbolIfInterned.
sel notNil ifTrue:[
cls := aClass.
[cls notNil
and:[cls ~~ JavaObject
and:[cls ~~ JavaClass]]] whileTrue:[
cls methodDictionary keysAndValuesDo:[:jSel :aMethod |
((jSel == sel)
or:[aMethod name = sel
or:[aMethod signatureNameWithoutReturnType = sel]])
ifTrue:[
(nargs isNil
or:[aMethod numArgs == nargs]) ifTrue:[
staticMethod == (aMethod isStatic) ifTrue:[
methods isNil ifTrue:[
methods := OrderedCollection new
].
methods add:aMethod
]
]
]
].
cls := cls superclass.
].
].
^ methods ? #()
"Created: / 4.11.1998 / 19:04:51 / cg"
"Modified: / 4.11.1998 / 19:31:33 / cg"
! !
!JavaClass class methodsFor:'signature parsing'!
initialValueFromSignature:aSignature
"given a signature, return an initializer value"
|s|
s := aSignature readStream.
^ self initialValueFromStream:s.
"
JavaClass initialValueFromSignature:'LObject;'
JavaClass initialValueFromSignature:'B'
JavaClass initialValueFromSignature:'I'
"
!
initialValueFromStream:s
"parse a fieldTypeSpec - see java doc"
|typeChar|
typeChar := s next.
^ InitialValuePerType at:typeChar ifAbsent:nil.
! !
!JavaClass class methodsFor:'special'!
orderOfClassInits
^ OrderOfClassInits
"Created: / 12.11.1998 / 15:35:57 / cg"
!
setInstanceVariableStringFromFields:f in:aClass
|varNames|
varNames := ''.
f do:[:aField |
varNames := varNames , aField name , ' '
].
aClass setInstanceVariableString:varNames.
"Created: 15.4.1996 / 16:42:52 / cg"
!
startRememberingOrderOfClassInits
OrderOfClassInits := OrderedCollection new.
"Created: / 12.11.1998 / 15:26:32 / cg"
"Modified: / 12.11.1998 / 15:29:10 / cg"
! !
!JavaClass methodsFor:'accessing'!
binaryFile
^ binaryFilePath
!
category
"java classes do not really hav a category;
simulate one by separating its name into individual components,
prepending 'java'"
|nameComponents|
nameComponents := fullName asCollectionOfSubstringsSeparatedBy:$/.
nameComponents size <= 1 ifTrue:[
^ 'java' "/ fullName
].
^ ((nameComponents asStringWith:$/ from:1 to:(nameComponents size - 1)))
replaceAll:$/ with:$.
"Modified: 30.7.1997 / 15:35:22 / cg"
!
classLoader
^ classLoader
!
classLoader:aJavaClassLoaderOrNil
classLoader := aJavaClassLoaderOrNil
!
compiledMethodAt:name signature:sig
"lookup the classes methodDictionary"
methodDictionary keysAndValuesDo:[:mFullSelector :aMethod |
aMethod name == name ifTrue:[
aMethod signature == sig ifTrue:[
^ aMethod
]
]
].
^ nil
"Created: 1.8.1997 / 00:01:58 / cg"
!
constantPool
^ constantPool
!
fields
^ fields
!
fullName
^ fullName
!
interfaces
interfaces notNil ifTrue:[
interfaces := interfaces collect:[:clsRef |
clsRef isUnresolved ifTrue:[
clsRef preResolve
] ifFalse:[
clsRef
]
].
].
^ interfaces
!
javaClass
^ self
!
lastName
^ fullName copyFrom:(fullName lastIndexOf:$/)+1
"Created: / 5.11.1998 / 19:16:00 / cg"
!
name
^ name "/ fullName
!
nameSpace
^ JAVA
"Created: 20.1.1997 / 13:04:30 / cg"
!
nameWithoutNameSpacePrefix
^ fullName
"Created: 20.1.1997 / 13:05:30 / cg"
!
nameWithoutPrefix
^ fullName
"Created: 20.1.1997 / 13:06:06 / cg"
!
package
"extract from the fullName"
|components|
components := fullName asCollectionOfSubstringsSeparatedBy:$/.
components size > 1 ifTrue:[
^ (components copyWithoutLast:1) asStringWith:$/
].
^ fullName
"
Java allClasses first fullName
Java allClasses first package
"
!
source
^ Java classSourceOf:self
"
(Java at:'java.awt.Frame') source
(Java at:'ArcTest') source
(Java at:'ArcCanvas') source
"
"Modified: 30.7.1997 / 14:31:01 / cg"
!
sourceFile
^ sourceFile
!
staticFields
^ staticFields
!
typeOfField:aFieldName
fields do:[:aField |
aField name = aFieldName ifTrue:[
^ aField type
]
].
self error:'no such field'
"
(JAVA at:#'java/awt/image/ColorModel') typeOfField:'pixel_bits'
"
"Modified: 21.1.1997 / 22:48:28 / cg"
! !
!JavaClass methodsFor:'adding / removing'!
removeFromSystem
Java removeClass:self
"Created: 12.8.1997 / 02:46:51 / cg"
! !
!JavaClass methodsFor:'browser interface'!
isVisualStartable
"return true, if this is an application class,
which can be started via #open"
"/ if I have a main() method, I am
(self compiledMethodAt:#'main([Ljava/lang/String;)V') notNil ifTrue:[
^ true
].
"/ NEEDS startApplet to work ...
"/ "/ if I inherit from Applet, I am
"/
"/ (self isSubclassOf:(Java at:'java.applet.Applet')) ifTrue:[
"/ ^ true.
"/ ].
^ false
"Modified: / 3.11.1998 / 23:04:59 / cg"
!
open
"start a thread for my main method"
"/ if I have a main, call it ...
(self compiledMethodAt:#'main([Ljava/lang/String;)V') notNil ifTrue:[
^ self startMain
].
"/ otherwise, create a frame and wrap me;
"/ as in:
"/ public static void main(String args[]) {
"/ Frame f = new Frame("myName");
"/ mySelf me = new mySelf();
"/
"/ me.init();
"/ me.start();
"/
"/ f.add("Center", me);
"/ f.setSize(300, 300);
"/ f.show();
"/ }
^ self startApplet
"Created: / 15.1.1998 / 17:18:30 / cg"
"Modified: / 3.11.1998 / 22:51:47 / cg"
!
syntaxHighlighterClass
"return the parser to use for farmatting (prettyPrinting) this class -
this can be redefined in special classes, to get classes with
Lisp, Prolog, ASN1, Basic :-) or whatever syntax."
self == JavaClass ifFalse:[
^ nil
].
^ super syntaxHighlighterClass
"Created: / 22.10.1998 / 00:26:13 / cg"
"Modified: / 22.10.1998 / 00:27:02 / cg"
! !
!JavaClass methodsFor:'compiler interface'!
compilerClass
"return the compiler to use for this class -
this can be redefined in special classes, to get classes with
Lisp, Prolog, ASN1, Basic :-) or whatever syntax."
^ Compiler.
^ JavaCompiler
"Created: 31.7.1997 / 23:03:37 / cg"
"Modified: 4.8.1997 / 16:50:08 / cg"
!
evaluatorClass
"return the compiler to use for expression evaluation for this class -
this can be redefined in special classes, to get classes with
Lisp, Prolog, ASN1, Basic :-) or whatever syntax."
^ Compiler.
^ JavaCompiler
"Created: 31.7.1997 / 23:03:56 / cg"
"Modified: 4.8.1997 / 16:49:14 / cg"
!
parserClass
"return the parser to use for parsing this class -
this can be redefined in special classes, to get classes with
Lisp, Prolog, ASN1, Basic :-) or whatever syntax."
^ Compiler.
^ JavaCompiler
"Created: 31.7.1997 / 23:04:11 / cg"
"Modified: 4.8.1997 / 16:50:18 / cg"
! !
!JavaClass methodsFor:'documentation support'!
htmlDocumentation
^ nil "/ replace by access to javadoc-generated documentation later
"Modified: 22.3.1997 / 14:18:50 / cg"
! !
!JavaClass methodsFor:'executing programs'!
startApplet
|f me stub|
"/ TODO: setup embeddedAppletFrame correctly
"/ (for getParameter to work ...)
"/ create a frame and wrap me;
"/ as in:
"/ public static void main(String args[]) {
"/ Frame f = new Frame("myName");
"/ mySelf me = new mySelf();
"/
"/ me.init();
"/ me.start();
"/
"/ f.add("Center", me);
"/ f.setSize(300, 300);
"/ f.show();
"/ }
f := (Java at:'java.awt.Frame') basicNew.
f perform:#'<init>(Ljava/lang/String;)V' with:(Java as_String:self name).
self halt.
me := self basicNew.
me perform:#'<init>()V'.
self halt.
stub := (Java at:'netscape.applet.EmbeddedAppletFrame') new.
me instVarNamed:'stub' put:stub.
self halt.
me perform:#'init()V'.
me perform:#'start()V'.
self halt.
f perform:#'add(Ljava/lang/String;Ljava/awt/Component;)Ljava/awt/Component;'
with:(Java as_String:'Center')
with:me.
self halt.
f perform:#'setSize(II)V' with:300 with:300.
self halt.
f perform:#'show()V'.
self halt.
"Modified: / 3.11.1998 / 23:04:41 / cg"
!
startMain
"start a thread for my main() method"
Java executeMainOf:self
"Created: / 5.2.1998 / 00:36:06 / cg"
"Modified: / 5.2.1998 / 00:37:15 / cg"
!
startMainWithArgumentString:aCommandLineString
"start a thread for my main() method, passing a string with arguments"
Java executeMainOf:self withArgumentString:aCommandLineString
"Modified: / 5.2.1998 / 00:37:25 / cg"
"Created: / 5.2.1998 / 00:41:15 / cg"
! !
!JavaClass methodsFor:'fileOut'!
basicFileOutDefinitionOn:aStream withNameSpace:nameSpaceBoolean
JavaDecompiler definitionOf:self on:aStream
"Modified: 22.3.1997 / 14:30:28 / cg"
!
fileOut
self warn:'fileOut not yet supported'
"Modified: 22.3.1997 / 14:30:28 / cg"
"Created: 22.3.1997 / 14:35:43 / cg"
! !
!JavaClass methodsFor:'java initialization'!
classInit
"call the classes JAVA clinit function"
|m|
(accessFlags bitAnd:A_INITIALIZED) ~~ 0 ifTrue:[^ self].
accessFlags := accessFlags bitOr:A_INITIALIZED.
superclass ~~ JavaObject ifTrue:[
superclass classInit
].
"/ "/ also, all referenced classes must be ...
"/ constantPool classReferencesDo:[:aClass |
"/ aClass classInit
"/ ].
m := self compiledMethodAt:#'<clinit>()V'.
m notNil ifTrue:[
"/ 'calling clinit() of ' print. self fullName printNL.
[
OrderOfClassInits notNil ifTrue:[
OrderOfClassInits add:self.
].
m
valueWithReceiver:self
arguments:#()
selector:#'<clinit>()V'
search:self class
sender:nil
] valueOnUnwindDo:[
accessFlags := accessFlags bitXor:A_INITIALIZED.
]
] ifFalse:[
"/ self fullName print. ' has no clinit()' printNL.
].
"
JavaVM instructionTrace:true.
JavaVM callTrace:true.
(Java classNamed:'java.lang.String') classInit
(Java classNamed:'java.lang.System') classInit
(Java classNamed:'java/io/FileDescriptor') classInit
(Java classNamed:'java.util.Properties') classInit
"
"Modified: / 12.11.1998 / 15:41:11 / cg"
!
initializeStaticFields
staticFields isNil ifTrue:[^ self].
staticFields do:[:f |
|val type|
(val := f constantValue) isNil ifTrue:[
"/ careful: int/long etc. constants must be initialized
"/ with correct type.
type := f type.
type == #long ifTrue:[
val := 0.
] ifFalse:[type == #int ifTrue:[
val := 0.
] ifFalse:[type == #float ifTrue:[
val := 0.0 asShortFloat
] ifFalse:[type == #double ifTrue:[
val := 0.0
] ifFalse:[type == #byte ifTrue:[
val := 0.
] ifFalse:[type == #char ifTrue:[
val := 0.
] ifFalse:[type == #'unsigned short' ifTrue:[
val := 0.
] ifFalse:[type == #boolean ifTrue:[
val := 0.
]]]]]]]].
].
self instVarNamed:(f name) put:val.
].
! !
!JavaClass methodsFor:'java instance creation'!
initValueFor:instVarName
|idx field|
idx := fields findFirst:[:field | field name = instVarName].
idx == 0 ifTrue:[
superclass ~~ JavaObject ifTrue:[
^ superclass initValueFor:instVarName
].
self halt
] ifFalse:[
field := fields at:idx.
^ field initialValue
].
!
new
"create a new instance, preset its fields,
and call its JAVA init function"
|newJavaObject|
newJavaObject := self newCleared.
newJavaObject perform:#'<init>()V'.
^ newJavaObject
"
(Java classNamed:'java.lang.String') basicNew inspect
(Java classNamed:'java.lang.String') newCleared inspect
(Java classNamed:'java.lang.String') new inspect
"
"Modified: / 4.11.1998 / 18:04:34 / cg"
!
newCleared
"create a new cleared JAVA instance.
Its instVars are cleared to the corresponding typed values;
however, <init> is not invoked for it."
|newJavaObject sz "{ Class: SmallInteger }" |
(accessFlags bitAnd:A_ABSTRACT_OR_INTERFACE) ~~ 0 ifTrue:[
JavaVM throwInstantiationExceptionFor:self.
^ nil
].
newJavaObject := super basicNew.
initValues notNil ifTrue:[
sz := self instSize.
1 to:sz do:[:i |
newJavaObject instVarAt:i put:(initValues at:i)
].
].
^ newJavaObject
"
(Java classNamed:'java.lang.String') basicNew inspect
(Java classNamed:'java.lang.String') newCleared inspect
(Java classNamed:'java.lang.String') new inspect
"
"Modified: / 13.11.1998 / 14:10:45 / cg"
!
newWith_int:arg
"create a new instance, preset its fields,
and call its JAVA init function passing an int arg"
|newJavaObject|
newJavaObject := self newCleared.
newJavaObject perform:#'<init>(I)V' with:arg.
^ newJavaObject
"
((Java classNamed:'java.lang.Integer') newWith_int:123) inspect
"
"Modified: / 4.11.1998 / 18:04:34 / cg"
"Created: / 13.11.1998 / 14:17:01 / cg"
! !
!JavaClass methodsFor:'message sending'!
doesNotUnderstand:aMessage
"as a courtesy to the smalltalker, try to map static methods as
Smalltalk-class methods"
|r args numArgs methods javaMethod sel anyMethodsFound argType
argSignature newArgs oArgIdx nArgIdx canConvert
retVal|
args := aMessage arguments.
numArgs := args size.
sel := aMessage selector.
methods := JavaClass lookupMethods:sel numArgs:numArgs in:self static:true.
methods size == 1 ifTrue:[
javaMethod := methods first.
"/ there is only one - try that one.
] ifFalse:[
methods size > 1 ifTrue:[
"/ more than one - select the ones that could be used.
methods := methods select:[:aMethod |
|argSignature|
argSignature := aMethod argSignature.
(JavaClass canConvertArgsToJava:args asSpecifiedIn:argSignature)
].
methods size == 1 ifTrue:[
javaMethod := methods first.
]
]
].
javaMethod notNil ifTrue:[
(ArgumentConversionErrorSignal catch:[
args notNil ifTrue:[
args := JavaClass
convertArgsToJava:args
asSpecifiedIn:(javaMethod argSignature)
numArgs:numArgs.
].
]) ifFalse:[
retVal := javaMethod
valueWithReceiver:self "/ (javaMethod javaClass)
arguments:args
selector:(javaMethod selector)
search:self "/ (javaMethod javaClass class)
sender:nil.
^ JavaClass convertToSmalltalk:retVal type:(javaMethod returnType).
].
^ MessageNotUnderstoodSignal
raiseRequestWith:aMessage
errorString:'no method for given argument(s)'
in:thisContext "sender"
].
anyMethodsFound := false.
"/ try all with that name (the number of args could be different ...
methods := JavaClass lookupMethods:sel numArgs:nil in:self static:true.
methods size > 0 ifTrue:[
anyMethodsFound := true.
numArgs > 0 ifTrue:[
methods do:[:methodToTry |
(ArgumentConversionErrorSignal catch:[
newArgs := JavaClass
convertArgsToJava:args
asSpecifiedIn:(methodToTry argSignature)
numArgs:methodToTry numArgs.
]) ifFalse:[
retVal := methodToTry
valueWithReceiver:self "/ (methodToTry javaClass)
arguments:newArgs
selector:(methodToTry selector)
search:self "/ (methodToTry javaClass class)
sender:nil.
^ JavaClass convertToSmalltalk:retVal type:(methodToTry returnType).
].
].
]
].
anyMethodsFound ifTrue:[
methods size == 1 ifTrue:[
javaMethod := methods first.
^ MessageNotUnderstoodSignal
raiseRequestWith:aMessage
errorString:(sel , ' expects ' , javaMethod argSignature size printString , ' argument(s)')
in:thisContext "sender"
].
^ MessageNotUnderstoodSignal
raiseRequestWith:aMessage
errorString:'no method for given argument count or type'
in:thisContext "sender"
].
^ super doesNotUnderstand:aMessage
"Modified: / 6.11.1998 / 00:57:22 / cg"
!
lookupMethodFor:selector
|method cls sel|
sel := selector asSymbolIfInterned.
sel notNil ifTrue:[
cls := self.
[cls notNil] whileTrue:[
method := cls compiledMethodAt:sel.
method notNil ifTrue:[ ^ method ].
cls := cls superclass.
].
].
^ nil
!
performStatic:selector
"send a static message, without args."
|javaMethod sel|
sel := selector asSymbolIfInterned.
sel notNil ifTrue:[
javaMethod := methodDictionary at:sel.
javaMethod notNil ifTrue:[
javaMethod isStatic ifTrue:[
^ javaMethod
valueWithReceiver:self
arguments:#()
]
].
].
^ self doesNotUnderstand:(Message selector:selector)
"Modified: / 15.1.1998 / 00:31:27 / cg"
"Created: / 12.11.1998 / 16:29:20 / cg"
! !
!JavaClass methodsFor:'printOut'!
printNameInHierarchy
"return my name as printed in the hierarchy"
^ self displayString
"Modified: 22.3.1997 / 14:16:55 / cg"
!
printOutOn:aStream
self warn:'printOut not yet supported'
"Created: 22.3.1997 / 14:36:12 / cg"
!
printOutProtocolOn:aStream
self warn:'printOut not yet supported'
"Created: 22.3.1997 / 14:36:28 / cg"
! !
!JavaClass methodsFor:'printing & storing'!
displayString
^ fullName copyReplaceAll:$/ with:$.
"/ ^ 'JAVA-' , name .
"/ ^ name , '(Java)' "/ 'JavaClass(' , name , ')'
"Created: / 15.4.1996 / 16:02:48 / cg"
"Modified: / 18.7.1998 / 22:56:30 / cg"
! !
!JavaClass methodsFor:'private accessing'!
addMethod:m name:name signature:signature
|sel|
sel := (name , signature) asSymbol.
self addSelector:sel withMethod:m.
^ self.
"/ selectorArray isNil ifTrue:[
"/ selectorArray := #().
"/ methodArray := #()
"/ ].
"/ selectorArray := selectorArray copyWith:(name , signature) asSymbol. "/ name.
"/"/ selectorArray := selectorArray copyWith:name asSymbol. "/ name.
"/ methodArray := methodArray copyWith:m
"Created: 15.4.1996 / 16:42:52 / cg"
!
addSelector:newSelector withMethod:newMethod
"redefined to not flush smalltalk caches and send NO smalltalk-class
change notification. Will eventually flush Java caches."
|nargs oldMethod|
oldMethod := self compiledMethodAt:newSelector.
(self primAddSelector:newSelector withMethod:newMethod) ifFalse:[^ false].
^ true
"Created: 20.1.1997 / 13:00:48 / cg"
!
makeObsolete
accessFlags := accessFlags bitOr:A_OBSOLETE
"Created: 7.8.1997 / 19:04:48 / cg"
!
markUninitialized
(accessFlags bitAnd:A_INITIALIZED) ~~ 0 ifTrue:[
accessFlags := accessFlags bitXor:A_INITIALIZED
].
!
setAccessFlags:flags
accessFlags := flags.
"Created: 15.4.1996 / 16:42:52 / cg"
!
setBinaryFilePath:aPathName
binaryFilePath := aPathName
!
setConstantPool:anArray
constantPool := anArray.
"Created: 15.4.1996 / 16:42:52 / cg"
!
setFields:f
|vals|
JavaClass setInstanceVariableStringFromFields:f in:self.
instSize := superclass instSize + f size.
fields := f.
vals := self allInstVarNames
collect:[:nm |
self initValueFor:nm
].
vals isEmpty ifTrue:[
initValues := nil
] ifFalse:[
(vals detect:[:el | el notNil] ifNone:nil) isNil ifTrue:[
initValues := nil
] ifFalse:[
initValues := vals asArray
]
]
"Created: / 15.4.1996 / 16:42:52 / cg"
"Modified: / 6.11.1998 / 01:53:01 / cg"
!
setFullName:aString
|nameComponents|
fullName := aString asSymbol.
nameComponents := aString asCollectionOfSubstringsSeparatedBy:$/.
name := nameComponents last asSymbol.
name := fullName.
"Created: / 15.4.1996 / 16:42:52 / cg"
"Modified: / 5.11.1998 / 19:14:39 / cg"
!
setInterfaces:i
i size > 0 ifTrue:[
interfaces := i
] ifFalse:[
interfaces := nil
]
"Modified: 7.4.1997 / 15:44:53 / cg"
!
setSourceFile:aFilename
sourceFile := aFilename.
"Created: 15.4.1996 / 16:42:52 / cg"
!
setStaticFields:f
JavaClass setInstanceVariableStringFromFields:f in:self class.
staticFields := f.
!
setSuperclass:aClass
|iVars numIvars|
aClass isNil ifTrue:[
super setSuperclass:JavaObject
] ifFalse:[
(aClass isMemberOf:JavaUnresolvedClassConstant) ifTrue:[
self halt.
].
super setSuperclass:aClass.
].
iVars := self instVarNames.
((numIvars := iVars size) > 0) ifTrue:[
(superclass notNil and:[(superclass isMemberOf:JavaUnresolvedClassConstant) not]) ifTrue:[
instSize := superclass instSize + numIvars
] ifFalse:[
instSize := numIvars
]
].
"Created: 15.4.1996 / 16:42:52 / cg"
"Modified: 22.8.1997 / 15:06:45 / cg"
! !
!JavaClass methodsFor:'queries'!
browserClass
"return the browser to use for this class -
this can be redefined in special classes, to get different browsers"
^ SystemBrowser "/ JavaBrowser
"Modified: / 14.10.1998 / 15:28:38 / cg"
!
canBeSubclassed
"return true, if its allowed to create subclasses of the receiver."
self isFinal ifTrue:[^ false].
self isInterface ifTrue:[^ false].
^ true
"Created: / 5.11.1998 / 23:04:50 / cg"
!
hasInterface:aJavaInterface
"return true, if I respond to all methods as
required by the argument, an aJavaInterface"
interfaces size > 0 ifTrue:[
self interfaces do:[:if |
aJavaInterface == if ifTrue:[
^ true
].
]
].
"/ ^ false.
aJavaInterface methodDictionary keysAndValuesDo:[:sel :mthd |
(self canUnderstand:sel) ifFalse:[
^ false.
]
].
^ true
"Modified: / 28.1.1998 / 01:46:16 / cg"
!
isAbstract
"return true, if the receiver is abstract
(i.e. may not have instances)"
^ (accessFlags bitAnd:A_ABSTRACT) ~~ 0
"Modified: / 7.5.1998 / 12:24:42 / cg"
!
isFinal
"return true, if the receiver is final
(i.e. may not be subclassed)"
^ (accessFlags bitAnd:A_FINAL) ~~ 0
"Modified: / 7.5.1998 / 12:24:21 / cg"
!
isInitialized
"return true, if the receiver is initialized"
^ (accessFlags bitAnd:A_INITIALIZED) ~~ 0
"Modified: / 7.5.1998 / 12:23:54 / cg"
!
isInterface
"return true, if the receiver is an interface"
^ (accessFlags bitAnd:A_INTERFACE) ~~ 0
"Modified: / 7.5.1998 / 12:23:39 / cg"
!
isJavaClass
^ self ~~ JavaClass
"Created: 18.3.1997 / 17:48:01 / cg"
!
isObsolete
"return true, if the receiver is obsolete
Java classes are never."
^ (accessFlags bitAnd:A_OBSOLETE) ~~ 0.
"Modified: 7.8.1997 / 19:04:28 / cg"
!
isPublic
"return true, if the receiver is public"
^ (accessFlags bitAnd:A_PUBLIC) ~~ 0
"Modified: / 7.5.1998 / 12:22:44 / cg"
!
isUnresolved
"return true, if the receiver is unresolved;
javaClasses are never; JavaUnresolvedClasses are always"
^ false
"Modified: / 7.5.1998 / 12:23:14 / cg"
!
nameSpacePath
|parts s|
parts := self fullName asCollectionOfSubstringsSeparatedBy:$/.
s := '' writeStream.
s nextPutAll:'JAVA'.
parts from:1 to:(parts size - 1) do:[:aPart |
s nextPutAll:'::'.
s nextPutAll:aPart
].
^ s contents
"
JAVA::java::lang::Object fullName
JAVA::java::lang::Object nameSpacePath
JAVA::java::lang::Object name
"
"Modified: / 19.10.1998 / 20:07:24 / cg"
!
supportsMethodCategories
^ self isJavaClass not
"Created: / 30.7.1997 / 14:58:58 / cg"
"Modified: / 7.5.1998 / 12:25:54 / cg"
!
typeName
^ 'L' , self fullName
"
(Java at:'java.util.Stack') typeName
"
"Modified: / 10.2.1998 / 17:13:26 / cg"
! !
!JavaClass methodsFor:'special'!
arrayClass
self halt.
^ Array
"Created: / 10.11.1998 / 02:07:32 / cg"
"Modified: / 10.11.1998 / 02:10:26 / cg"
!
asClassPointerRef
self halt.
^ self
"Created: / 10.11.1998 / 02:07:01 / cg"
"Modified: / 10.11.1998 / 02:10:30 / cg"
!
deref
^ self
"Created: / 10.11.1998 / 02:08:06 / cg"
!
updateClassRefsFrom:oldClass to:newClass
self == oldClass ifTrue:[
self makeObsolete.
^ self
].
constantPool updateClassRefsFrom:oldClass to:newClass.
interfaces notNil ifTrue:[
interfaces := interfaces collect:[:anInterface |
anInterface == oldClass ifTrue:[
newClass isNil ifTrue:[
nil "/ replace by an unresolvedInterface
] ifFalse:[
newClass
]
] ifFalse:[
anInterface
]
]
]
"Modified: / 4.2.1998 / 22:08:19 / cg"
! !
!JavaClass class methodsFor:'documentation'!
version
^ '$Header: /home/jv/Projects/SmalltalkX/repositories/cvs/stx/libjava/JavaClass.st,v 1.92 1998/11/14 19:51:35 cg Exp $'
! !
JavaClass initialize!