@@ -58,55 +58,118 @@ struct JavaToSwift: ParsableCommand {
5858 )
5959 var input : String
6060
61+ /// Describes what kind of generation action is being performed by
62+ /// Java2Swift.
63+ enum GenerationMode {
64+ /// Generate a configuration file given a Jar file.
65+ case configuration( jarFile: String )
66+
67+ /// Generate Swift wrappers for Java classes based on the given
68+ /// configuration.
69+ case classWrappers( Configuration )
70+ }
71+
6172 mutating func run( ) throws {
62- var vmOptions : [ String ] = [ ]
63- let classpath = classPathWithJarFile
64- if !classpath. isEmpty {
65- vmOptions. append ( " -cp " )
66- vmOptions. append ( contentsOf: classpath)
73+ // Determine the mode in which we'll execute.
74+ let generationMode : GenerationMode
75+ if jarFile {
76+ generationMode = . configuration( jarFile: input)
77+ } else {
78+ let config = try JavaTranslator . readConfiguration ( from: URL ( filePath: input) )
79+ generationMode = . classWrappers( config)
80+ }
81+
82+ // Load all of the dependent configurations and associate them with Swift
83+ // modules.
84+ let dependentConfigs = try dependsOn. map { dependentConfig in
85+ guard let equalLoc = dependentConfig. firstIndex ( of: " = " ) else {
86+ throw JavaToSwiftError . badConfigOption ( dependentConfig)
87+ }
88+
89+ let afterEqual = dependentConfig. index ( after: equalLoc)
90+ let swiftModuleName = String ( dependentConfig [ ..< equalLoc] )
91+ let configFileName = String ( dependentConfig [ afterEqual... ] )
92+
93+ let config = try JavaTranslator . readConfiguration ( from: URL ( filePath: configFileName) )
94+
95+ return ( swiftModuleName, config)
6796 }
6897
69- let jvm = try JavaVirtualMachine . shared ( vmOptions: vmOptions)
70- try run ( environment: jvm. environment ( ) )
98+ // Form a class path from all of our input sources:
99+ // * Command-line option --classpath
100+ var classPathPieces : [ String ] = classpath
101+ switch generationMode {
102+ case . configuration( jarFile: let jarFile) :
103+ // * Jar file (in `-jar-file` mode)
104+ classPathPieces. append ( jarFile)
105+ case . classWrappers( let config) :
106+ // * Class path specified in the configuration file (if any)
107+ config. classPath. map { classPathPieces. append ( $0) }
108+ }
109+
110+ // * Classes paths from all dependent configuration files
111+ for (_, config) in dependentConfigs {
112+ config. classPath. map { classPathPieces. append ( $0) }
113+ }
114+
115+ // Bring up the Java VM.
116+ let jvm = try JavaVirtualMachine . shared ( classPath: classPathPieces)
117+
118+ // Run the generation step.
119+ let classPath = classPathPieces. joined ( separator: " : " )
120+ switch generationMode {
121+ case . configuration( jarFile: let jarFile) :
122+ try emitConfiguration (
123+ forJarFile: jarFile,
124+ classPath: classPath,
125+ environment: jvm. environment ( )
126+ )
127+
128+ case . classWrappers( let config) :
129+ try generateWrappers (
130+ config: config,
131+ classPath: classPath,
132+ dependentConfigs: dependentConfigs,
133+ environment: jvm. environment ( )
134+ )
135+ }
71136 }
72137
73- mutating func run( environment: JNIEnvironment ) throws {
138+ /// Generate wrapper
139+ mutating func generateWrappers(
140+ config: Configuration ,
141+ classPath: String ,
142+ dependentConfigs: [ ( String , Configuration ) ] ,
143+ environment: JNIEnvironment
144+ ) throws {
74145 let translator = JavaTranslator (
75146 swiftModuleName: moduleName,
76147 environment: environment
77148 )
78149
79- // Load all of the configurations this depends on.
80- for config in dependsOn {
81- guard let equalLoc = config. firstIndex ( of: " = " ) else {
82- throw JavaToSwiftError . badConfigOption ( config)
83- }
84-
85- let afterEqual = config. index ( after: equalLoc)
86- let swiftModuleName = String ( config [ ..< equalLoc] )
87- let configFileName = String ( config [ afterEqual... ] )
88-
89- try translator. loadDependentConfiguration (
90- forSwiftModule: swiftModuleName,
91- from: URL ( filePath: configFileName)
150+ // Note all of the dependent configurations.
151+ for (swiftModuleName, dependentConfig) in dependentConfigs {
152+ translator. addConfiguration (
153+ dependentConfig,
154+ forSwiftModule: swiftModuleName
92155 )
93156 }
94157
95- // Jar file mode: read a Jar file and output a configuration.
96- if jarFile {
97- return try emitConfiguration ( forJarFile: input, environment: environment)
98- }
99-
100- // Load the configuration file.
101- let config = try translator. readConfiguration ( from: URL ( filePath: input) )
158+ // Add the configuration for this module.
159+ translator. addConfiguration ( config, forSwiftModule: moduleName)
102160
103161 // Load all of the requested classes.
162+ #if false
104163 let classLoader = URLClassLoader (
105- try classPathWithJarFile . map {
106- try URL ( " file:// \( $0 ) " , environment: environment)
107- } ,
164+ [
165+ try URL ( " file:// \( classPath ) " , environment: environment)
166+ ] ,
108167 environment: environment
109168 )
169+ #else
170+ let classLoader = try JavaClass < ClassLoader > ( in: environment)
171+ . getSystemClassLoader ( ) !
172+ #endif
110173 var javaClasses : [ JavaClass < JavaObject > ] = [ ]
111174 for (javaClassName, swiftName) in config. classes {
112175 guard let javaClass = try classLoader. loadClass ( javaClassName) else {
@@ -146,15 +209,6 @@ struct JavaToSwift: ParsableCommand {
146209 }
147210 }
148211
149- /// Return the class path augmented with the Jar file, if there is one.
150- var classPathWithJarFile : [ String ] {
151- if jarFile {
152- return [ input] + classpath
153- }
154-
155- return classpath
156- }
157-
158212 func writeContents( _ contents: String , to filename: String , description: String ) throws {
159213 if outputDirectory == " - " {
160214 print ( " // \( filename) - \( description) " )
@@ -171,10 +225,13 @@ struct JavaToSwift: ParsableCommand {
171225 print ( " done. " )
172226 }
173227
174- func emitConfiguration( forJarFile jarFileName: String , environment: JNIEnvironment ) throws {
175- var configuration = Configuration (
176- classPath: classPathWithJarFile. joined ( separator: " : " )
177- )
228+ func emitConfiguration(
229+ forJarFile jarFileName: String ,
230+ classPath: String ,
231+ environment: JNIEnvironment
232+ ) throws {
233+ var configuration = Configuration ( classPath: classPath)
234+
178235 let jarFile = try JarFile ( jarFileName, false , environment: environment)
179236 for entry in jarFile. entries ( ) ! {
180237 // We only look at class files in the Jar file.
@@ -190,6 +247,11 @@ struct JavaToSwift: ParsableCommand {
190247 }
191248 }
192249
250+ // TODO: For now, skip all nested classes.
251+ if entry. getName ( ) . contains ( " $ " ) {
252+ continue
253+ }
254+
193255 let javaCanonicalName = String ( entry. getName ( ) . replacing ( " / " , with: " . " )
194256 . dropLast ( " .class " . count) )
195257 configuration. classes [ javaCanonicalName] =
@@ -205,9 +267,7 @@ struct JavaToSwift: ParsableCommand {
205267 // Write the file.
206268 try writeContents (
207269 contents,
208- to: URL ( filePath: outputDirectory)
209- . appending ( path: " Java2Swift.config " )
210- . path ( percentEncoded: false ) ,
270+ to: " Java2Swift.config " ,
211271 description: " Java2Swift configuration file "
212272 )
213273 }
@@ -238,3 +298,14 @@ extension String {
238298 return self
239299 }
240300}
301+
302+ @JavaClass ( " java.lang.ClassLoader " )
303+ public struct ClassLoader {
304+ @JavaMethod
305+ public func loadClass( _ arg0: String ) throws -> JavaClass < JavaObject > ?
306+ }
307+
308+ extension JavaClass< ClassLoader> {
309+ @JavaStaticMethod
310+ public func getSystemClassLoader( ) -> ClassLoader ?
311+ }
0 commit comments