Skip to content

Commit 5b82e9f

Browse files
Major update to tool
Add overlay annotations Handle factory beans Handle recursive bean definitions Handle forward references Handle aliases Handle beans with multiple names Handle Set and Map values Known limitation: May not declare all exception types in the presence of mutually recursive beans Ignores import paths on the Java classpath
1 parent 06315d5 commit 5b82e9f

File tree

5 files changed

+435
-141
lines changed

5 files changed

+435
-141
lines changed

env-model-generator/src/JavaCode.ts

+29-5
Original file line numberDiff line numberDiff line change
@@ -239,10 +239,7 @@ export class BlankLine extends CodeElement implements Statement, Member {
239239
}
240240
}
241241

242-
export class Braces extends CodeElement implements Statement, Member {
243-
public isStatement: true = true;
244-
public isMember: true = true;
245-
242+
class Braces extends CodeElement {
246243
private intro: string;
247244
private body: Statement[];
248245

@@ -261,20 +258,46 @@ export class Braces extends CodeElement implements Statement, Member {
261258
}
262259
}
263260

261+
export class Block extends Braces implements Statement {
262+
public isStatement: true = true;
263+
}
264+
265+
export class Method extends Braces implements Member {
266+
public isMember: true = true;
267+
268+
private annotations: string[];
269+
270+
public constructor(intro: string, body: Statement[], exceptions?: string[], annotations?: string[]) {
271+
super(intro + (exceptions === undefined || exceptions.length === 0 ? "" : ` throws ${exceptions.join(", ")}`), body);
272+
this.annotations = annotations === undefined ? [] : annotations;
273+
}
274+
275+
public flatten(): string[] {
276+
return [
277+
...this.annotations.map((annotation) => "@" + annotation),
278+
...super.flatten(),
279+
];
280+
}
281+
}
282+
264283
export class Class extends CodeElement {
265284
private modifiers: string;
266285
private name: string;
267286
private baseClass: string | undefined;
268287
private interfaces: string[];
269288
private members: Member[];
289+
private annotations: string[];
270290

271-
public constructor(modifiers: string, name: string, baseClass: string | undefined, interfaces: string[], members: Member[]) {
291+
public constructor(
292+
modifiers: string, name: string, baseClass: string | undefined, interfaces: string[], members: Member[], annotations?: string[])
293+
{
272294
super();
273295
this.modifiers = modifiers;
274296
this.name = name;
275297
this.baseClass = baseClass;
276298
this.interfaces = interfaces;
277299
this.members = members;
300+
this.annotations = annotations === undefined ? [] : annotations;
278301
}
279302

280303
public flatten(): string[] {
@@ -284,6 +307,7 @@ export class Class extends CodeElement {
284307
const baseClassString = this.baseClass === undefined ? "" : ` extends ${this.baseClass}`;
285308
const interfacesString = this.interfaces.length === 0 ? "" : ` implements ${this.interfaces.join(", ")}`;
286309
return [
310+
...this.annotations.map((annotation) => "@" + annotation),
287311
`${this.modifiers} class ${this.name}${baseClassString}${interfacesString} {`,
288312
..._.flatMap(members, (member) => member.flatten()).map((line) => indent + line),
289313
"}",

env-model-generator/src/env-model-generator.ts

+68-39
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import * as program from "commander";
66
import * as fs from "fs-extra";
77
import * as _ from "lodash";
88
import * as pathUtils from "path";
9-
import { BlankLine, Braces, Class, FnCall, Null, Return } from "./JavaCode";
9+
import { BlankLine, Block, Class, FnCall, Method, Null, Return, Statement } from "./JavaCode";
1010
import * as model from "./model";
1111
import parseSpringXmlConfigFile from "./parse-spring-xml";
1212
import { createPath } from "./utils";
@@ -32,6 +32,13 @@ if (program.args.length === 0) {
3232
program.help();
3333
}
3434

35+
enum ReturnValue {
36+
Success,
37+
ParseError,
38+
CreateJavaError,
39+
OutputFolderNotFound,
40+
OutputError,
41+
}
3542

3643
async function transformConfigFile(fileName: string, options: any) {
3744
let fileNames = [ fileName ];
@@ -41,51 +48,73 @@ async function transformConfigFile(fileName: string, options: any) {
4148
await parseSpringXmlConfigFile(fileNames);
4249
} catch (err) {
4350
console.error(`Error parsing config file: ${err.message}`);
44-
process.exit(2);
51+
process.exit(ReturnValue.ParseError);
4552
return;
4653
}
4754
const packageName = "org.springframework.context.support";
4855
let output = `package ${packageName};\n\n`;
49-
const applicationContext =
50-
new Class(
51-
"public", "ClassPathXmlApplicationContext", undefined, [ "org.springframework.context.ApplicationContext" ],
52-
[
53-
new Braces(
54-
"public ClassPathXmlApplicationContext(String[] args)",
55-
[]
56-
),
57-
new Braces(
58-
"public Object getBean(String name)",
59-
[
60-
new Braces(
61-
"try",
62-
model.Bean.getNamed().map((bean) =>
63-
new Braces(
64-
`if (name.equals("${bean.name}"))`,
65-
[
66-
new Return(new FnCall(bean.getter, [])),
67-
])),
68-
),
69-
new Braces(
70-
"catch(Exception ex)",
71-
[]),
72-
new Return(new Null()),
73-
]
74-
),
75-
new BlankLine(),
76-
new BlankLine(),
77-
..._.flatMap([...model.Bean.getAll()], (bean) => bean.toJava()[0]),
78-
new BlankLine(),
79-
...model.PropertiesValue.utilityMethods(),
80-
...model.BeanValue.utilityMethods(),
81-
]);
82-
output += applicationContext.toString() + "\n";
56+
try {
57+
const applicationContext =
58+
new Class(
59+
"public", "ClassPathXmlApplicationContext", undefined, [ "org.springframework.context.ApplicationContext" ],
60+
[
61+
new Method(
62+
"public ClassPathXmlApplicationContext(String[] args)",
63+
[]),
64+
new Method(
65+
"public Object getBean(String name)",
66+
[
67+
new Block(
68+
"try",
69+
(<Statement[]>[]).concat(
70+
model.Bean.getNamed().map((bean) =>
71+
new Block(
72+
`if (name.equals("${bean.name}"))`,
73+
[
74+
new Return(new FnCall(bean.getter, [])),
75+
])),
76+
[...model.Bean.getAliases()].map(
77+
function ([ alias, beanId ]) {
78+
const bean = model.Bean.tryGet(beanId);
79+
if (bean === undefined)
80+
throw new Error("Found alias to bean that doesn't exist");
81+
return new Block(
82+
`if (name.equals("${alias}"))`,
83+
[
84+
new Return(new FnCall(bean.getter, [])),
85+
]);
86+
}),
87+
),
88+
),
89+
new Block(
90+
"catch(Exception ex)",
91+
[]),
92+
new Return(new Null()),
93+
],
94+
[],
95+
[ "OverlayMethodImplementation" ]
96+
),
97+
new BlankLine(),
98+
new BlankLine(),
99+
..._.flatMap([...model.Bean.getAll()], (bean) => bean.javaMembers),
100+
new BlankLine(),
101+
...model.PropertiesValue.utilityMethods(),
102+
...model.MapValue.utilityMethods(),
103+
...model.BeanValue.utilityMethods(),
104+
],
105+
[ "OverlayClassImplementation" ]);
106+
output += applicationContext.toString() + "\n";
107+
} catch (err) {
108+
console.error(`Error converting to Java: ${err.message}`);
109+
process.exit(ReturnValue.CreateJavaError);
110+
return;
111+
}
83112
// Write out the generated Java
84113
let outputPath = options.outputPath;
85114
if (outputPath) {
86115
if (!fs.existsSync(outputPath)) {
87116
console.error(`Given output folder '${outputPath}' does not exist`);
88-
process.exit(5);
117+
process.exit(ReturnValue.OutputFolderNotFound);
89118
return;
90119
}
91120
// Create folder to store it in based on the package name
@@ -94,7 +123,7 @@ async function transformConfigFile(fileName: string, options: any) {
94123
outputPath = createPath(appContextFolder, outputPath);
95124
} catch (err) {
96125
console.error(`Can't create output folder '${appContextFolder}': ${err.message}`);
97-
process.exit(3);
126+
process.exit(ReturnValue.OutputError);
98127
return;
99128
}
100129
// Write file
@@ -104,7 +133,7 @@ async function transformConfigFile(fileName: string, options: any) {
104133
console.log("Output written to %s", outputFileName);
105134
} catch (err) {
106135
console.error(`Can't write output file '${outputFileName}': ${err.message}`);
107-
process.exit(4);
136+
process.exit(ReturnValue.OutputError);
108137
return;
109138
}
110139
} else

0 commit comments

Comments
 (0)