@@ -26,6 +26,11 @@ struct JavaClassTranslator {
2626 /// The Java class (or interface) being translated.
2727 let javaClass : JavaClass < JavaObject >
2828
29+ /// Whether to translate this Java class into a Swift class.
30+ ///
31+ /// This will be false for Java interfaces.
32+ let translateAsClass : Bool
33+
2934 /// The type parameters to the Java class or interface.
3035 let javaTypeParameters : [ TypeVariable < JavaClass < JavaObject > > ]
3136
@@ -37,6 +42,10 @@ struct JavaClassTranslator {
3742 /// class.
3843 let swiftTypeName : String
3944
45+ /// The effective Java superclass object, which is the nearest
46+ /// superclass that has been mapped into Swift.
47+ let effectiveJavaSuperclass : JavaClass < JavaObject > ?
48+
4049 /// The Swift name of the superclass.
4150 let swiftSuperclass : String ?
4251
@@ -103,6 +112,7 @@ struct JavaClassTranslator {
103112 let fullName = javaClass. getName ( )
104113 self . javaClass = javaClass
105114 self . translator = translator
115+ self . translateAsClass = translator. translateAsClass && !javaClass. isInterface ( )
106116 self . swiftTypeName = try translator. getSwiftTypeNameFromJavaClassName (
107117 fullName,
108118 preferValueTypes: false ,
@@ -114,14 +124,24 @@ struct JavaClassTranslator {
114124 self . nestedClasses = translator. nestedClasses [ fullName] ?? [ ]
115125
116126 // Superclass.
117- if !javaClass. isInterface ( ) , let javaSuperclass = javaClass. getSuperclass ( ) {
118- do {
119- self . swiftSuperclass = try translator. getSwiftTypeName ( javaSuperclass, preferValueTypes: false ) . swiftName
120- } catch {
121- translator. logUntranslated ( " Unable to translate ' \( fullName) ' superclass: \( error) " )
122- self . swiftSuperclass = nil
127+ if !javaClass. isInterface ( ) {
128+ var javaSuperclass = javaClass. getSuperclass ( )
129+ var swiftSuperclass : String ? = nil
130+ while let javaSuperclassNonOpt = javaSuperclass {
131+ do {
132+ swiftSuperclass = try translator. getSwiftTypeName ( javaSuperclassNonOpt, preferValueTypes: false ) . swiftName
133+ break
134+ } catch {
135+ translator. logUntranslated ( " Unable to translate ' \( fullName) ' superclass: \( error) " )
136+ }
137+
138+ javaSuperclass = javaSuperclassNonOpt. getSuperclass ( )
123139 }
140+
141+ self . effectiveJavaSuperclass = javaSuperclass
142+ self . swiftSuperclass = swiftSuperclass
124143 } else {
144+ self . effectiveJavaSuperclass = nil
125145 self . swiftSuperclass = nil
126146 }
127147
@@ -161,9 +181,15 @@ struct JavaClassTranslator {
161181 }
162182
163183 // Gather methods.
164- for method in javaClass. getMethods ( ) {
184+ let methods = translateAsClass
185+ ? javaClass. getDeclaredMethods ( )
186+ : javaClass. getMethods ( )
187+ for method in methods {
165188 guard let method else { continue }
166189
190+ // Only look at public and protected methods here.
191+ guard method. isPublic || method. isProtected else { continue }
192+
167193 // Skip any methods that are expected to be implemented in Swift. We will
168194 // visit them in the second pass, over the *declared* methods, because
169195 // we want to see non-public methods as well.
@@ -178,6 +204,7 @@ struct JavaClassTranslator {
178204 }
179205
180206 if translator. swiftNativeImplementations. contains ( javaClass. getName ( ) ) {
207+ // Gather the native methods we're going to implement.
181208 for method in javaClass. getDeclaredMethods ( ) {
182209 guard let method else { continue }
183210
@@ -209,6 +236,12 @@ extension JavaClassTranslator {
209236 return
210237 }
211238
239+ // Don't include inherited fields when translating to a class.
240+ if translateAsClass &&
241+ !field. getDeclaringClass ( ) !. equals ( javaClass. as ( JavaObject . self) !) {
242+ return
243+ }
244+
212245 fields. append ( field)
213246 }
214247
@@ -283,8 +316,18 @@ extension JavaClassTranslator {
283316 // Collect all of the members of this type.
284317 let members = properties + enumDecls + initializers + instanceMethods
285318
286- // Compute the "extends" clause for the superclass.
287- let extends = swiftSuperclass. map { " , extends: \( $0) .self " } ?? " "
319+ // Compute the "extends" clause for the superclass (of the struct
320+ // formulation) or the inheritance clause (for the class
321+ // formulation).
322+ let extends : String
323+ let inheritanceClause : String
324+ if translateAsClass {
325+ extends = " "
326+ inheritanceClause = swiftSuperclass. map { " : \( $0) " } ?? " "
327+ } else {
328+ extends = swiftSuperclass. map { " , extends: \( $0) .self " } ?? " "
329+ inheritanceClause = " "
330+ }
288331
289332 // Compute the string to capture all of the interfaces.
290333 let interfacesStr : String
@@ -297,10 +340,11 @@ extension JavaClassTranslator {
297340
298341 // Emit the struct declaration describing the java class.
299342 let classOrInterface : String = isInterface ? " JavaInterface " : " JavaClass " ;
343+ let introducer = translateAsClass ? " open class " : " public struct "
300344 var classDecl : DeclSyntax =
301345 """
302346 @ \( raw: classOrInterface) ( \( literal: javaClass. getName ( ) ) \( raw: extends) \( raw: interfacesStr) )
303- public struct \( raw: swiftInnermostTypeName) \( raw: genericParameterClause) {
347+ \( raw : introducer ) \( raw: swiftInnermostTypeName) \( raw: genericParameterClause) \( raw : inheritanceClause ) {
304348 \( raw: members. map { $0. description } . joined ( separator: " \n \n " ) )
305349 }
306350 """
@@ -447,9 +491,11 @@ extension JavaClassTranslator {
447491 let parametersStr = parameters. map { $0. description } . joined ( separator: " , " )
448492 let throwsStr = javaConstructor. throwsCheckedException ? " throws " : " "
449493 let accessModifier = javaConstructor. isPublic ? " public " : " "
494+ let convenienceModifier = translateAsClass ? " convenience " : " "
495+ let nonoverrideAttribute = translateAsClass ? " @_nonoverride " : " "
450496 return """
451497 @JavaMethod
452- \( raw: accessModifier) init( \( raw: parametersStr) ) \( raw: throwsStr)
498+ \( raw: nonoverrideAttribute ) \( raw : accessModifier) \( raw : convenienceModifier ) init( \( raw: parametersStr) ) \( raw: throwsStr)
453499 """
454500 }
455501
@@ -483,9 +529,14 @@ extension JavaClassTranslator {
483529 let methodAttribute : AttributeSyntax = implementedInSwift
484530 ? " "
485531 : javaMethod. isStatic ? " @JavaStaticMethod \n " : " @JavaMethod \n " ;
486- let accessModifier = implementedInSwift ? " " : " public "
532+ let accessModifier = implementedInSwift ? " "
533+ : ( javaMethod. isStatic || !translateAsClass) ? " public "
534+ : " open "
535+ let overrideOpt = ( translateAsClass && !javaMethod. isStatic && isOverride ( javaMethod) )
536+ ? " override "
537+ : " "
487538 return """
488- \( methodAttribute) \( raw: accessModifier) func \( raw: swiftMethodName) \( raw: genericParameterClause) ( \( raw: parametersStr) ) \( raw: throwsStr) \( raw: resultTypeStr) \( raw: whereClause)
539+ \( methodAttribute) \( raw: accessModifier) \( raw : overrideOpt ) func \( raw: swiftMethodName) \( raw: genericParameterClause) ( \( raw: parametersStr) ) \( raw: throwsStr) \( raw: resultTypeStr) \( raw: whereClause)
489540 """
490541 }
491542
@@ -532,20 +583,23 @@ extension JavaClassTranslator {
532583 }
533584 """
534585
586+ let convenienceModifier = translateAsClass ? " convenience " : " "
535587 let initSyntax : DeclSyntax = """
536- public init(_ enumValue: \( raw: name) , environment: JNIEnvironment? = nil) {
588+ public \( raw : convenienceModifier ) init(_ enumValue: \( raw: name) , environment: JNIEnvironment? = nil) {
537589 let _environment = if let environment {
538590 environment
539591 } else {
540592 try! JavaVirtualMachine.shared().environment()
541593 }
542- let classObj = try! JavaClass<Self >(environment: _environment)
594+ let classObj = try! JavaClass< \( raw : swiftInnermostTypeName ) >(environment: _environment)
543595 switch enumValue {
544596 \( raw: enumConstants. map {
545597 return """
546598 case . \( $0. getName ( ) ) :
547599 if let \( $0. getName ( ) ) = classObj. \( $0. getName ( ) ) {
548- self = \( $0. getName ( ) )
600+ \( translateAsClass
601+ ? " self.init(javaHolder: \( $0. getName ( ) ) .javaHolder) "
602+ : " self = \( $0. getName ( ) ) " )
549603 } else {
550604 fatalError( " Enum value \( $0. getName ( ) ) was unexpectedly nil, please re-run Java2Swift on the most updated Java class " )
551605 }
@@ -611,3 +665,171 @@ struct MethodCollector {
611665 methods. append ( method)
612666 }
613667}
668+
669+ // MARK: Utility functions
670+ extension JavaClassTranslator {
671+ /// Determine whether this method is an override of another Java
672+ /// method.
673+ func isOverride( _ method: Method ) -> Bool {
674+ var currentSuperclass = effectiveJavaSuperclass
675+ while let currentSuperclassNonOpt = currentSuperclass {
676+ // Set the loop up for the next run.
677+ defer {
678+ currentSuperclass = currentSuperclassNonOpt. getSuperclass ( )
679+ }
680+
681+ do {
682+ // If this class didn't get translated into Swift, skip it.
683+ if translator. translatedClasses [ currentSuperclassNonOpt. getName ( ) ] == nil {
684+ continue
685+ }
686+
687+ // If this superclass declares a method with the same parameter types,
688+ // we have an override.
689+ guard let overriddenMethod = try currentSuperclassNonOpt
690+ . getDeclaredMethod ( method. getName ( ) , method. getParameterTypes ( ) ) else {
691+ continue
692+ }
693+
694+ // Ignore non-public, non-protected methods because they would not
695+ // have been render into the Swift superclass.
696+ if !overriddenMethod. isPublic && !overriddenMethod. isProtected {
697+ continue
698+ }
699+
700+ // We know that Java considers this method an override. However, it is
701+ // possible that Swift will not consider it an override, because Java
702+ // has subtyping relations that Swift does not.
703+ if method. getGenericReturnType ( ) . isEqualToOrSubtypeOf ( overriddenMethod. getGenericReturnType ( ) ) {
704+ return true
705+ }
706+ } catch {
707+ }
708+ }
709+
710+ return false
711+ }
712+ }
713+
714+ extension [ Type ? ] {
715+ /// Determine whether the types in the array match the other array.
716+ func allTypesEqual( _ other: [ Type ? ] ) -> Bool {
717+ if self . count != other. count {
718+ return false
719+ }
720+
721+ for (selfType, otherType) in zip ( self , other) {
722+ if !selfType!. isEqualTo ( otherType!) {
723+ return false
724+ }
725+ }
726+
727+ return true
728+ }
729+ }
730+
731+ extension Type {
732+ /// Adjust the given type to use its bounds, mirroring what we do in
733+ /// mapping Java types into Swift.
734+ func adjustToJavaBounds( adjusted: inout Bool ) -> Type {
735+ if let typeVariable = self . as ( TypeVariable< GenericDeclaration> . self ) ,
736+ typeVariable. getBounds ( ) . count == 1 ,
737+ let bound = typeVariable. getBounds ( ) [ 0 ] {
738+ adjusted = true
739+ return bound
740+ }
741+
742+ if let wildcardType = self . as ( WildcardType . self) ,
743+ wildcardType. getUpperBounds ( ) . count == 1 ,
744+ let bound = wildcardType. getUpperBounds ( ) [ 0 ] {
745+ adjusted = true
746+ return bound
747+ }
748+
749+ return self
750+ }
751+
752+ /// Determine whether this type is equivalent to or a subtype of the other
753+ /// type.
754+ func isEqualTo( _ other: Type ) -> Bool {
755+ // First, adjust types to their bounds, if we need to.
756+ var anyAdjusted : Bool = false
757+ let adjustedSelf = self . adjustToJavaBounds ( adjusted: & anyAdjusted)
758+ let adjustedOther = other. adjustToJavaBounds ( adjusted: & anyAdjusted)
759+ if anyAdjusted {
760+ return adjustedSelf. isEqualTo ( adjustedOther)
761+ }
762+
763+ // If both are classes, check for equivalence.
764+ if let selfClass = self . as ( JavaClass< JavaObject> . self ) ,
765+ let otherClass = other. as ( JavaClass< JavaObject> . self ) {
766+ return selfClass. equals ( otherClass. as ( JavaObject . self) )
767+ }
768+
769+ // If both are arrays, check that their component types are equivalent.
770+ if let selfArray = self . as ( GenericArrayType . self) ,
771+ let otherArray = other. as ( GenericArrayType . self) {
772+ return selfArray. getGenericComponentType ( ) . isEqualTo ( otherArray. getGenericComponentType ( ) )
773+ }
774+
775+ // If both are parameterized types, check their raw type and type
776+ // arguments for equivalence.
777+ if let selfParameterizedType = self . as ( ParameterizedType . self) ,
778+ let otherParameterizedType = other. as ( ParameterizedType . self) {
779+ if !selfParameterizedType. getRawType ( ) . isEqualTo ( otherParameterizedType. getRawType ( ) ) {
780+ return false
781+ }
782+
783+ return selfParameterizedType. getActualTypeArguments ( )
784+ . allTypesEqual ( otherParameterizedType. getActualTypeArguments ( ) )
785+ }
786+
787+ // If both are type variables, compare their bounds.
788+ // FIXME: This is a hack.
789+ if let selfTypeVariable = self . as ( TypeVariable< GenericDeclaration> . self ) ,
790+ let otherTypeVariable = other. as ( TypeVariable< GenericDeclaration> . self ) {
791+ return selfTypeVariable. getBounds ( ) . allTypesEqual ( otherTypeVariable. getBounds ( ) )
792+ }
793+
794+ // If both are wildcards, compare their upper and lower bounds.
795+ if let selfWildcard = self . as ( WildcardType . self) ,
796+ let otherWildcard = other. as ( WildcardType . self) {
797+ return selfWildcard. getUpperBounds ( ) . allTypesEqual ( otherWildcard. getUpperBounds ( ) )
798+ && selfWildcard. getLowerBounds ( ) . allTypesEqual ( otherWildcard. getLowerBounds ( ) )
799+ }
800+
801+ return false
802+ }
803+
804+ /// Determine whether this type is equivalent to or a subtype of the
805+ /// other type.
806+ func isEqualToOrSubtypeOf( _ other: Type ) -> Bool {
807+ // First, adjust types to their bounds, if we need to.
808+ var anyAdjusted : Bool = false
809+ let adjustedSelf = self . adjustToJavaBounds ( adjusted: & anyAdjusted)
810+ let adjustedOther = other. adjustToJavaBounds ( adjusted: & anyAdjusted)
811+ if anyAdjusted {
812+ return adjustedSelf. isEqualToOrSubtypeOf ( adjustedOther)
813+ }
814+
815+ if isEqualTo ( other) {
816+ return true
817+ }
818+
819+ // If both are classes, check for subclassing.
820+ if let selfClass = self . as ( JavaClass< JavaObject> . self ) ,
821+ let otherClass = other. as ( JavaClass< JavaObject> . self ) {
822+ return selfClass. isSubclass ( of: otherClass)
823+ }
824+
825+ // Anything object-like is a subclass of java.lang.Object
826+ if let otherClass = other. as ( JavaClass< JavaObject> . self ) ,
827+ otherClass. getName ( ) == " java.lang.Object " {
828+ if self . is ( GenericArrayType . self) || self . is ( ParameterizedType . self) ||
829+ self . is ( WildcardType . self) || self . is ( TypeVariable< GenericDeclaration> . self ) {
830+ return true
831+ }
832+ }
833+ return false
834+ }
835+ }
0 commit comments