1+ package org .logende .converter .converters ;
2+
3+ import java .io .*;
4+ import java .nio .file .*;
5+ import java .util .*;
6+ import java .util .concurrent .TimeUnit ;
7+ import java .net .URISyntaxException ;
8+ import org .logende .converter .ConverterService ;
9+
10+ public class XsdToJsonSchemaConverter implements ConverterService .Converter {
11+
12+ private static final String JSONIX_JAR_NAME = "jsonix-schema-compiler-full-2.3.9.jar" ;
13+ private static final int TIMEOUT_SECONDS = 30 ;
14+
15+ @ Override
16+ public String getName () {
17+ return "Jsonix" ;
18+ }
19+
20+ @ Override
21+ public String getSourceFormat () {
22+ return "Xsd" ;
23+ }
24+
25+ @ Override
26+ public String getTargetFormat () {
27+ return "JsonSchema" ;
28+ }
29+
30+ @ Override
31+ public List <String > getSupportedFeatures () {
32+ return Collections .emptyList ();
33+ }
34+
35+ @ Override
36+ public String convert (String schema ) throws Exception {
37+ // Resolve Jsonix JAR path relative to this JAR’s directory
38+ String jarDir = getOwnJarDir ();
39+ String jsonixJar = Paths .get (jarDir , "lib" , JSONIX_JAR_NAME ).toString ();
40+
41+ // Validate JAR exists
42+ Path jarPath = Paths .get (jsonixJar );
43+ if (!Files .exists (jarPath )) {
44+ throw new RuntimeException ("Jsonix JAR not found at: " + jarPath .toAbsolutePath () +
45+ ". Please download and place it in the lib directory." );
46+ }
47+
48+ // Write input XSD to a temp file
49+ Path tempDir = Files .createTempDirectory ("xsd2jsonschema" );
50+ Path xsdFile = tempDir .resolve ("input.xsd" );
51+ Files .writeString (xsdFile , schema );
52+
53+ // Output directory for Jsonix
54+ Path outDir = tempDir .resolve ("out" );
55+ Files .createDirectories (outDir );
56+
57+ try {
58+ // Build command to execute Jsonix JAR
59+ List <String > command = Arrays .asList (
60+ "java" ,
61+ "-jar" , jarPath .toAbsolutePath ().toString (),
62+ "-generateJsonSchema" ,
63+ "-d" , outDir .toString (),
64+ xsdFile .toString ()
65+ );
66+
67+ // Execute the command
68+ ProcessBuilder pb = new ProcessBuilder (command );
69+ pb .directory (tempDir .toFile ());
70+ pb .redirectErrorStream (true );
71+
72+ Process process = pb .start ();
73+
74+ // Capture output for debugging
75+ StringBuilder output = new StringBuilder ();
76+ try (BufferedReader reader = new BufferedReader (
77+ new InputStreamReader (process .getInputStream ()))) {
78+ String line ;
79+ while ((line = reader .readLine ()) != null ) {
80+ output .append (line ).append ("\n " );
81+ }
82+ }
83+
84+ // Wait for process to complete with timeout
85+ boolean finished = process .waitFor (TIMEOUT_SECONDS , TimeUnit .SECONDS );
86+
87+ if (!finished ) {
88+ process .destroyForcibly ();
89+ throw new RuntimeException ("Jsonix process timed out after " + TIMEOUT_SECONDS + " seconds" );
90+ }
91+
92+ int exitCode = process .exitValue ();
93+ if (exitCode != 0 ) {
94+ throw new RuntimeException ("Jsonix failed with exit code " + exitCode +
95+ ". Output:\n " + output .toString ());
96+ }
97+
98+ } catch (IOException | InterruptedException e ) {
99+ cleanupTempFiles (tempDir );
100+ throw new RuntimeException ("Failed to execute Jsonix: " + e .getMessage (), e );
101+ }
102+
103+ // Find first .json schema file produced
104+ String result = findJsonSchemaFile (outDir );
105+
106+ // Clean up temp files
107+ cleanupTempFiles (tempDir );
108+
109+ if (result != null ) {
110+ return result ;
111+ }
112+
113+ throw new RuntimeException ("No JSON Schema produced by Jsonix." );
114+ }
115+
116+ private String findJsonSchemaFile (Path outDir ) throws IOException {
117+ // Look for .json files in the output directory
118+ try (DirectoryStream <Path > stream = Files .newDirectoryStream (outDir , "*.json" )) {
119+ for (Path file : stream ) {
120+ return Files .readString (file );
121+ }
122+ }
123+
124+ // Also check subdirectories (Jsonix sometimes creates nested structure)
125+ try (DirectoryStream <Path > dirStream = Files .newDirectoryStream (outDir ,
126+ path -> Files .isDirectory (path ))) {
127+ for (Path subDir : dirStream ) {
128+ try (DirectoryStream <Path > jsonStream = Files .newDirectoryStream (subDir , "*.json" )) {
129+ for (Path file : jsonStream ) {
130+ return Files .readString (file );
131+ }
132+ }
133+ }
134+ }
135+
136+ return null ;
137+ }
138+
139+ private void cleanupTempFiles (Path tempDir ) {
140+ try {
141+ Files .walk (tempDir )
142+ .sorted (Comparator .reverseOrder ())
143+ .map (Path ::toFile )
144+ .forEach (File ::delete );
145+ } catch (IOException e ) {
146+ System .err .println ("Warning: Failed to clean up temporary files in " +
147+ tempDir + ": " + e .getMessage ());
148+ }
149+ }
150+
151+
152+ private String getOwnJarDir () throws URISyntaxException {
153+ // Get path of the running JAR
154+ File jarFile = new File (
155+ ConverterService .class .getProtectionDomain ()
156+ .getCodeSource ()
157+ .getLocation ()
158+ .toURI ()
159+ );
160+ // Return the parent directory
161+ return jarFile .getParentFile ().getAbsolutePath ();
162+ }
163+
164+
165+ }
0 commit comments