zerodds_dlrl_codegen/
java.rs1use alloc::format;
7use alloc::string::String;
8
9use crate::DlrlTypeInfo;
10
11#[allow(clippy::format_collect)]
14#[must_use]
15pub fn generate_java_object(info: &DlrlTypeInfo) -> String {
16 let cls = simple_name(&info.name);
17 let pkg = package(&info.name);
18 let key_lines: String = info
19 .keys
20 .iter()
21 .map(|k| format!(" @DlrlKey\n public long {k};\n"))
22 .collect();
23 let rel_lines: String = info
24 .relations
25 .iter()
26 .map(|(rel, target)| {
27 let t = simple_name(target);
28 format!(
29 " @DlrlRelation(target = {t}.class)\n public RefList<{t}> {rel} = new RefList<>();\n"
30 )
31 })
32 .collect();
33 let header = if pkg.is_empty() {
34 String::new()
35 } else {
36 format!("package {pkg};\n\n")
37 };
38 format!(
39 "{header}// Generated DLRL Object — Spec §B.6 Java-PSM\n\
40@DlrlObject\npublic class {cls} extends ObjectRoot {{\n{key_lines}{rel_lines}}}\n"
41 )
42}
43
44#[must_use]
46pub fn generate_java_object_listener(info: &DlrlTypeInfo) -> String {
47 let cls = simple_name(&info.name);
48 let pkg = package(&info.name);
49 let header = if pkg.is_empty() {
50 String::new()
51 } else {
52 format!("package {pkg};\n\n")
53 };
54 format!(
55 "{header}// Generated DLRL ObjectListener — Spec §B.6.7\n\
56public interface {cls}Listener extends ObjectListener<{cls}> {{\n\
57 void on{cls}Created({cls} obj);\n\
58 void on{cls}Modified({cls} obj);\n\
59 void on{cls}Deleted({cls} obj);\n\
60}}\n"
61 )
62}
63
64fn simple_name(scoped: &str) -> &str {
65 scoped.rsplit("::").next().unwrap_or(scoped)
66}
67
68fn package(scoped: &str) -> String {
69 let parts: alloc::vec::Vec<&str> = scoped.split("::").collect();
70 if parts.len() <= 1 {
71 return String::new();
72 }
73 parts[..parts.len() - 1].join(".")
74}
75
76#[cfg(test)]
77#[allow(clippy::expect_used, clippy::unwrap_used, clippy::panic)]
78mod tests {
79 use super::*;
80
81 fn trade_info() -> DlrlTypeInfo {
82 DlrlTypeInfo {
83 name: "demo::Trade".into(),
84 keys: alloc::vec!["symbol".into()],
85 relations: alloc::vec![("quotes".into(), "demo::Quote".into())],
86 }
87 }
88
89 #[test]
90 fn java_object_emits_package_and_annotations() {
91 let s = generate_java_object(&trade_info());
92 assert!(s.contains("package demo;"));
93 assert!(s.contains("@DlrlObject"));
94 assert!(s.contains("class Trade extends ObjectRoot"));
95 assert!(s.contains("@DlrlKey"));
96 assert!(s.contains("public long symbol;"));
97 assert!(s.contains("@DlrlRelation(target = Quote.class)"));
98 assert!(s.contains("RefList<Quote> quotes"));
99 }
100
101 #[test]
102 fn java_object_no_package_for_unscoped() {
103 let info = DlrlTypeInfo {
104 name: "Foo".into(),
105 ..DlrlTypeInfo::default()
106 };
107 let s = generate_java_object(&info);
108 assert!(!s.contains("package "));
109 assert!(s.contains("class Foo extends ObjectRoot"));
110 }
111
112 #[test]
113 fn listener_interface_emits_three_callbacks() {
114 let s = generate_java_object_listener(&trade_info());
115 assert!(s.contains("interface TradeListener extends ObjectListener<Trade>"));
116 assert!(s.contains("void onTradeCreated(Trade obj);"));
117 assert!(s.contains("void onTradeModified(Trade obj);"));
118 assert!(s.contains("void onTradeDeleted(Trade obj);"));
119 }
120}