8
8
#include < java_bytecode/java_bytecode_parser.h>
9
9
10
10
#include < boost/filesystem.hpp>
11
+ #include < java_bytecode/java_types.h>
12
+ #include < utility>
11
13
12
14
class cmdline_optionst final :
13
15
public parse_options_baset
@@ -22,9 +24,12 @@ class cmdline_optionst final:
22
24
ui_message_handlert ui_message_handler;
23
25
};
24
26
25
- cmdline_optionst::cmdline_optionst (int argc, const char **argv):
26
- parse_options_baset(" (version)(in-json):(out-json):" , argc, argv),
27
- ui_message_handler(cmdline, " java-class-info " JAVA_CLASS_INFO_VERSION)
27
+ cmdline_optionst::cmdline_optionst (int argc, const char **argv)
28
+ : parse_options_baset(
29
+ " (version)(in-json):(out-json):(out-di-json):" ,
30
+ argc,
31
+ argv),
32
+ ui_message_handler(cmdline, " java-class-info " JAVA_CLASS_INFO_VERSION)
28
33
{}
29
34
30
35
void cmdline_optionst::help ()
@@ -48,6 +53,41 @@ void cmdline_optionst::help()
48
53
" will be written.\n " ;
49
54
}
50
55
56
+ bool has_annotation_in_list (
57
+ const std::vector<java_bytecode_parse_treet::annotationt> &annotations,
58
+ const std::set<irep_idt> &names_to_match)
59
+ {
60
+ if (annotations.empty ())
61
+ {
62
+ return false ;
63
+ }
64
+
65
+ std::vector<irep_idt> annotation_names;
66
+ std::transform (
67
+ annotations.begin (),
68
+ annotations.end (),
69
+ std::inserter (annotation_names, annotation_names.end ()),
70
+ [](const java_bytecode_parse_treet::annotationt &annotation) {
71
+ INVARIANT (
72
+ annotation.type .id () == ID_pointer,
73
+ " Annotation type should be pointer." );
74
+ return annotation.type .subtype ().get (ID_C_base_name);
75
+ });
76
+
77
+ // Set_intersection requires a sort to have been done.
78
+ std::sort (annotation_names.begin (), annotation_names.end ());
79
+
80
+ std::set<irep_idt> matching_annotation_names;
81
+ std::set_intersection (
82
+ annotation_names.begin (),
83
+ annotation_names.end (),
84
+ names_to_match.begin (),
85
+ names_to_match.end (),
86
+ std::inserter (matching_annotation_names, matching_annotation_names.end ()));
87
+
88
+ return !matching_annotation_names.empty ();
89
+ }
90
+
51
91
int cmdline_optionst::doit ()
52
92
{
53
93
messaget msg (ui_message_handler);
@@ -104,9 +144,32 @@ int cmdline_optionst::doit()
104
144
return -6 ;
105
145
}
106
146
147
+ struct annotated_fieldt
148
+ {
149
+ annotated_fieldt (irep_idt name, std::string type)
150
+ : name(name), type(std::move(type))
151
+ {
152
+ }
153
+
154
+ irep_idt name;
155
+ std::string type;
156
+ };
157
+
158
+ struct beant
159
+ {
160
+ explicit beant (irep_idt name) : name(name)
161
+ {
162
+ }
163
+
164
+ irep_idt name;
165
+ std::vector<annotated_fieldt> fields;
166
+ };
167
+
168
+ const std::string di_out_path = cmdline.get_value (" out-di-json" );
169
+ bool enable_di_scan = !di_out_path.empty ();
107
170
json_objectt results;
108
171
json_arrayt errors;
109
-
172
+ std::vector<beant> beans;
110
173
int ret_code=0 ;
111
174
for (auto const &json_array_element : cfg.array )
112
175
{
@@ -198,6 +261,35 @@ int cmdline_optionst::doit()
198
261
}
199
262
class_json=class_props;
200
263
}
264
+
265
+ if (enable_di_scan)
266
+ {
267
+ static std::set<irep_idt> bean_annotations = {
268
+ " org.springframework.stereotype.Component"
269
+ };
270
+
271
+ static std::set<irep_idt> autowire_annotation = {
272
+ " org.springframework.beans.factory.annotation.Autowired"
273
+ };
274
+
275
+ const java_bytecode_parse_treet::classt &parsed_class =
276
+ parse_tree->parsed_class ;
277
+ if (has_annotation_in_list (parsed_class.annotations , bean_annotations))
278
+ {
279
+ beant bean (parsed_class.name );
280
+ for (const java_bytecode_parse_treet::fieldt &field :
281
+ parsed_class.fields )
282
+ {
283
+ if (has_annotation_in_list (field.annotations , autowire_annotation))
284
+ bean.fields .emplace_back (
285
+ field.name ,
286
+ field.signature .has_value () ? field.signature .value ()
287
+ : field.descriptor );
288
+ }
289
+
290
+ beans.push_back (std::move (bean));
291
+ }
292
+ }
201
293
}
202
294
catch (...)
203
295
{
@@ -238,6 +330,36 @@ int cmdline_optionst::doit()
238
330
result[" errors" ]=errors;
239
331
ofile << result;
240
332
333
+ if (enable_di_scan)
334
+ {
335
+ std::ofstream di_filename (di_out_path);
336
+ if (!di_filename)
337
+ {
338
+ msg.error ()
339
+ << " ERROR: Cannot open the output JSON file '"
340
+ << di_out_path
341
+ << " ' for writing."
342
+ << messaget::eom;
343
+ return -8 ;
344
+ }
345
+
346
+ json_objectt root;
347
+ json_objectt &json_beans = root[" beans" ].make_object ();
348
+ for (const beant &bean : beans)
349
+ {
350
+ json_objectt &json_bean = json_beans[id2string (bean.name )].make_object ();
351
+ json_objectt &json_fields = json_bean[" fields" ].make_object ();
352
+ for (const annotated_fieldt &field : bean.fields )
353
+ {
354
+ json_objectt &json_field =
355
+ json_fields[id2string (field.name )].make_object ();
356
+ json_field[" type" ] = json_stringt (field.type );
357
+ }
358
+ }
359
+
360
+ di_filename << root;
361
+ }
362
+
241
363
return ret_code;
242
364
}
243
365
0 commit comments