@@ -26,6 +26,11 @@ struct JavaClassTranslator {
26
26
/// The Java class (or interface) being translated.
27
27
let javaClass : JavaClass < JavaObject >
28
28
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
+
29
34
/// The type parameters to the Java class or interface.
30
35
let javaTypeParameters : [ TypeVariable < JavaClass < JavaObject > > ]
31
36
@@ -37,6 +42,10 @@ struct JavaClassTranslator {
37
42
/// class.
38
43
let swiftTypeName : String
39
44
45
+ /// The effective Java superclass object, which is the nearest
46
+ /// superclass that has been mapped into Swift.
47
+ let effectiveJavaSuperclass : JavaClass < JavaObject > ?
48
+
40
49
/// The Swift name of the superclass.
41
50
let swiftSuperclass : String ?
42
51
@@ -103,6 +112,7 @@ struct JavaClassTranslator {
103
112
let fullName = javaClass. getName ( )
104
113
self . javaClass = javaClass
105
114
self . translator = translator
115
+ self . translateAsClass = translator. translateAsClass && !javaClass. isInterface ( )
106
116
self . swiftTypeName = try translator. getSwiftTypeNameFromJavaClassName (
107
117
fullName,
108
118
preferValueTypes: false ,
@@ -114,14 +124,24 @@ struct JavaClassTranslator {
114
124
self . nestedClasses = translator. nestedClasses [ fullName] ?? [ ]
115
125
116
126
// 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 ( )
123
139
}
140
+
141
+ self . effectiveJavaSuperclass = javaSuperclass
142
+ self . swiftSuperclass = swiftSuperclass
124
143
} else {
144
+ self . effectiveJavaSuperclass = nil
125
145
self . swiftSuperclass = nil
126
146
}
127
147
@@ -161,9 +181,15 @@ struct JavaClassTranslator {
161
181
}
162
182
163
183
// Gather methods.
164
- for method in javaClass. getMethods ( ) {
184
+ let methods = translateAsClass
185
+ ? javaClass. getDeclaredMethods ( )
186
+ : javaClass. getMethods ( )
187
+ for method in methods {
165
188
guard let method else { continue }
166
189
190
+ // Only look at public and protected methods here.
191
+ guard method. isPublic || method. isProtected else { continue }
192
+
167
193
// Skip any methods that are expected to be implemented in Swift. We will
168
194
// visit them in the second pass, over the *declared* methods, because
169
195
// we want to see non-public methods as well.
@@ -178,6 +204,7 @@ struct JavaClassTranslator {
178
204
}
179
205
180
206
if translator. swiftNativeImplementations. contains ( javaClass. getName ( ) ) {
207
+ // Gather the native methods we're going to implement.
181
208
for method in javaClass. getDeclaredMethods ( ) {
182
209
guard let method else { continue }
183
210
@@ -209,6 +236,12 @@ extension JavaClassTranslator {
209
236
return
210
237
}
211
238
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
+
212
245
fields. append ( field)
213
246
}
214
247
@@ -283,8 +316,18 @@ extension JavaClassTranslator {
283
316
// Collect all of the members of this type.
284
317
let members = properties + enumDecls + initializers + instanceMethods
285
318
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
+ }
288
331
289
332
// Compute the string to capture all of the interfaces.
290
333
let interfacesStr : String
@@ -297,10 +340,11 @@ extension JavaClassTranslator {
297
340
298
341
// Emit the struct declaration describing the java class.
299
342
let classOrInterface : String = isInterface ? " JavaInterface " : " JavaClass " ;
343
+ let introducer = translateAsClass ? " open class " : " public struct "
300
344
var classDecl : DeclSyntax =
301
345
"""
302
346
@ \( 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 ) {
304
348
\( raw: members. map { $0. description } . joined ( separator: " \n \n " ) )
305
349
}
306
350
"""
@@ -447,9 +491,11 @@ extension JavaClassTranslator {
447
491
let parametersStr = parameters. map { $0. description } . joined ( separator: " , " )
448
492
let throwsStr = javaConstructor. throwsCheckedException ? " throws " : " "
449
493
let accessModifier = javaConstructor. isPublic ? " public " : " "
494
+ let convenienceModifier = translateAsClass ? " convenience " : " "
495
+ let nonoverrideAttribute = translateAsClass ? " @_nonoverride " : " "
450
496
return """
451
497
@JavaMethod
452
- \( raw: accessModifier) init( \( raw: parametersStr) ) \( raw: throwsStr)
498
+ \( raw: nonoverrideAttribute ) \( raw : accessModifier) \( raw : convenienceModifier ) init( \( raw: parametersStr) ) \( raw: throwsStr)
453
499
"""
454
500
}
455
501
@@ -483,9 +529,14 @@ extension JavaClassTranslator {
483
529
let methodAttribute : AttributeSyntax = implementedInSwift
484
530
? " "
485
531
: 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
+ : " "
487
538
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)
489
540
"""
490
541
}
491
542
@@ -532,20 +583,23 @@ extension JavaClassTranslator {
532
583
}
533
584
"""
534
585
586
+ let convenienceModifier = translateAsClass ? " convenience " : " "
535
587
let initSyntax : DeclSyntax = """
536
- public init(_ enumValue: \( raw: name) , environment: JNIEnvironment? = nil) {
588
+ public \( raw : convenienceModifier ) init(_ enumValue: \( raw: name) , environment: JNIEnvironment? = nil) {
537
589
let _environment = if let environment {
538
590
environment
539
591
} else {
540
592
try! JavaVirtualMachine.shared().environment()
541
593
}
542
- let classObj = try! JavaClass<Self >(environment: _environment)
594
+ let classObj = try! JavaClass< \( raw : swiftInnermostTypeName ) >(environment: _environment)
543
595
switch enumValue {
544
596
\( raw: enumConstants. map {
545
597
return """
546
598
case . \( $0. getName ( ) ) :
547
599
if let \( $0. getName ( ) ) = classObj. \( $0. getName ( ) ) {
548
- self = \( $0. getName ( ) )
600
+ \( translateAsClass
601
+ ? " self.init(javaHolder: \( $0. getName ( ) ) .javaHolder) "
602
+ : " self = \( $0. getName ( ) ) " )
549
603
} else {
550
604
fatalError( " Enum value \( $0. getName ( ) ) was unexpectedly nil, please re-run Java2Swift on the most updated Java class " )
551
605
}
@@ -611,3 +665,171 @@ struct MethodCollector {
611
665
methods. append ( method)
612
666
}
613
667
}
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