serde_generate/
java.rs

1// Copyright (c) Facebook, Inc. and its affiliates
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4use crate::{
5    common,
6    indent::{IndentConfig, IndentedWriter},
7    CodeGeneratorConfig, Encoding,
8};
9use heck::CamelCase;
10use include_dir::include_dir as include_directory;
11use serde_reflection::{ContainerFormat, Format, FormatHolder, Named, Registry, VariantFormat};
12use std::{
13    collections::{BTreeMap, HashMap},
14    io::{Result, Write},
15    path::PathBuf,
16};
17
18/// Main configuration object for code-generation in Java.
19pub struct CodeGenerator<'a> {
20    /// Language-independent configuration.
21    config: &'a CodeGeneratorConfig,
22    /// Mapping from external type names to fully-qualified class names (e.g. "MyClass" -> "com.my_org.my_package.MyClass").
23    /// Derived from `config.external_definitions`.
24    external_qualified_names: HashMap<String, String>,
25}
26
27/// Shared state for the code generation of a Java source file.
28struct JavaEmitter<'a, T> {
29    /// Writer.
30    out: IndentedWriter<T>,
31    /// Generator.
32    generator: &'a CodeGenerator<'a>,
33    /// Current namespace (e.g. vec!["com", "my_org", "my_package", "MyClass"])
34    current_namespace: Vec<String>,
35    /// Current (non-qualified) generated class names that could clash with names in the registry
36    /// (e.g. "Builder" or variant classes).
37    /// * We count multiplicities to allow inplace backtracking.
38    /// * Names in the registry are assumed to never clash.
39    current_reserved_names: HashMap<String, usize>,
40}
41
42impl<'a> CodeGenerator<'a> {
43    /// Create a Java code generator for the given config.
44    pub fn new(config: &'a CodeGeneratorConfig) -> Self {
45        if config.c_style_enums {
46            panic!("Java does not support generating c-style enums");
47        }
48        let mut external_qualified_names = HashMap::new();
49        for (namespace, names) in &config.external_definitions {
50            for name in names {
51                external_qualified_names
52                    .insert(name.to_string(), format!("{}.{}", namespace, name));
53            }
54        }
55        Self {
56            config,
57            external_qualified_names,
58        }
59    }
60
61    /// Output class definitions for ` registry` in separate source files.
62    /// Source files will be created in a subdirectory of `install_dir` corresponding to the given
63    /// package name (if any, otherwise `install_dir` it self).
64    pub fn write_source_files(
65        &self,
66        install_dir: std::path::PathBuf,
67        registry: &Registry,
68    ) -> Result<()> {
69        let current_namespace = self
70            .config
71            .module_name
72            .split('.')
73            .map(String::from)
74            .collect::<Vec<_>>();
75
76        let mut dir_path = install_dir;
77        for part in &current_namespace {
78            dir_path = dir_path.join(part);
79        }
80        std::fs::create_dir_all(&dir_path)?;
81
82        for (name, format) in registry {
83            self.write_container_class(&dir_path, current_namespace.clone(), name, format)?;
84        }
85        if self.config.serialization {
86            self.write_helper_class(&dir_path, current_namespace, registry)?;
87        }
88        Ok(())
89    }
90
91    fn write_container_class(
92        &self,
93        dir_path: &std::path::Path,
94        current_namespace: Vec<String>,
95        name: &str,
96        format: &ContainerFormat,
97    ) -> Result<()> {
98        let mut file = std::fs::File::create(dir_path.join(name.to_string() + ".java"))?;
99        let mut emitter = JavaEmitter {
100            out: IndentedWriter::new(&mut file, IndentConfig::Space(4)),
101            generator: self,
102            current_namespace,
103            current_reserved_names: HashMap::new(),
104        };
105
106        emitter.output_preamble()?;
107        emitter.output_container(name, format)
108    }
109
110    fn write_helper_class(
111        &self,
112        dir_path: &std::path::Path,
113        current_namespace: Vec<String>,
114        registry: &Registry,
115    ) -> Result<()> {
116        let mut file = std::fs::File::create(dir_path.join("TraitHelpers.java"))?;
117        let mut emitter = JavaEmitter {
118            out: IndentedWriter::new(&mut file, IndentConfig::Space(4)),
119            generator: self,
120            current_namespace,
121            current_reserved_names: HashMap::new(),
122        };
123
124        emitter.output_preamble()?;
125        emitter.output_trait_helpers(registry)
126    }
127}
128
129impl<'a, T> JavaEmitter<'a, T>
130where
131    T: Write,
132{
133    fn output_preamble(&mut self) -> Result<()> {
134        writeln!(self.out, "package {};\n", self.generator.config.module_name)?;
135        Ok(())
136    }
137
138    /// Compute a safe reference to the registry type `name` in the given context.
139    /// If `name` is not marked as "reserved" (e.g. "Builder"), we compare the global
140    /// name `self.qualified_names[name]` with the current namespace and try to use the
141    /// short string `name` if possible.
142    fn quote_qualified_name(&self, name: &str) -> String {
143        let qname = self
144            .generator
145            .external_qualified_names
146            .get(name)
147            .cloned()
148            .unwrap_or_else(|| format!("{}.{}", self.generator.config.module_name, name));
149        let mut path = qname.split('.').collect::<Vec<_>>();
150        if path.len() <= 1 {
151            return qname;
152        }
153        let name = path.pop().unwrap();
154        if self.current_reserved_names.contains_key(name) {
155            return qname;
156        }
157        for (index, element) in path.iter().enumerate() {
158            match self.current_namespace.get(index) {
159                Some(e) if e == element => (),
160                _ => {
161                    return qname;
162                }
163            }
164        }
165        name.to_string()
166    }
167
168    fn output_comment(&mut self, name: &str) -> std::io::Result<()> {
169        let mut path = self.current_namespace.clone();
170        path.push(name.to_string());
171        if let Some(doc) = self.generator.config.comments.get(&path) {
172            let text = textwrap::indent(doc, " * ").replace("\n\n", "\n *\n");
173            writeln!(self.out, "/**\n{} */", text)?;
174        }
175        Ok(())
176    }
177
178    fn output_custom_code(&mut self) -> std::io::Result<()> {
179        if let Some(code) = self
180            .generator
181            .config
182            .custom_code
183            .get(&self.current_namespace)
184        {
185            writeln!(self.out, "\n{}", code)?;
186        }
187        Ok(())
188    }
189
190    fn quote_type(&self, format: &Format) -> String {
191        use Format::*;
192        match format {
193            TypeName(x) => self.quote_qualified_name(x),
194            Unit => "com.novi.serde.Unit".into(),
195            Bool => "Boolean".into(),
196            I8 => "Byte".into(),
197            I16 => "Short".into(),
198            I32 => "Integer".into(),
199            I64 => "Long".into(),
200            I128 => "java.math.@com.novi.serde.Int128 BigInteger".into(),
201            U8 => "@com.novi.serde.Unsigned Byte".into(),
202            U16 => "@com.novi.serde.Unsigned Short".into(),
203            U32 => "@com.novi.serde.Unsigned Integer".into(),
204            U64 => "@com.novi.serde.Unsigned Long".into(),
205            U128 => "java.math.@com.novi.serde.Unsigned @com.novi.serde.Int128 BigInteger".into(),
206            F32 => "Float".into(),
207            F64 => "Double".into(),
208            Char => "Character".into(),
209            Str => "String".into(),
210            Bytes => "com.novi.serde.Bytes".into(),
211
212            Option(format) => format!("java.util.Optional<{}>", self.quote_type(format)),
213            Seq(format) => format!("java.util.List<{}>", self.quote_type(format)),
214            Map { key, value } => format!(
215                "java.util.Map<{}, {}>",
216                self.quote_type(key),
217                self.quote_type(value)
218            ),
219            Tuple(formats) => format!(
220                "com.novi.serde.Tuple{}<{}>",
221                formats.len(),
222                self.quote_types(formats)
223            ),
224            TupleArray { content, size } => format!(
225                "java.util.@com.novi.serde.ArrayLen(length={}) List<{}>",
226                size,
227                self.quote_type(content)
228            ),
229            Variable(_) => panic!("unexpected value"),
230        }
231    }
232
233    fn enter_class(&mut self, name: &str, reserved_subclass_names: &[&str]) {
234        self.out.indent();
235        self.current_namespace.push(name.to_string());
236        for name in reserved_subclass_names {
237            let entry = self
238                .current_reserved_names
239                .entry(name.to_string())
240                .or_insert(0);
241            *entry += 1;
242        }
243    }
244
245    fn leave_class(&mut self, reserved_subclass_names: &[&str]) {
246        self.out.unindent();
247        self.current_namespace.pop();
248        for name in reserved_subclass_names {
249            let entry = self.current_reserved_names.get_mut(*name).unwrap();
250            *entry -= 1;
251            if *entry == 0 {
252                self.current_reserved_names.remove(*name);
253            }
254        }
255    }
256
257    fn quote_types(&self, formats: &[Format]) -> String {
258        formats
259            .iter()
260            .map(|f| self.quote_type(f))
261            .collect::<Vec<_>>()
262            .join(", ")
263    }
264
265    fn output_trait_helpers(&mut self, registry: &Registry) -> Result<()> {
266        let mut subtypes = BTreeMap::new();
267        for format in registry.values() {
268            format
269                .visit(&mut |f| {
270                    if Self::needs_helper(f) {
271                        subtypes.insert(common::mangle_type(f), f.clone());
272                    }
273                    Ok(())
274                })
275                .unwrap();
276        }
277        writeln!(self.out, "final class TraitHelpers {{")?;
278        let reserved_names = &[];
279        self.enter_class("TraitHelpers", reserved_names);
280        for (mangled_name, subtype) in &subtypes {
281            self.output_serialization_helper(mangled_name, subtype)?;
282            self.output_deserialization_helper(mangled_name, subtype)?;
283        }
284        self.leave_class(reserved_names);
285        writeln!(self.out, "}}\n")
286    }
287
288    fn needs_helper(format: &Format) -> bool {
289        use Format::*;
290        matches!(
291            format,
292            Option(_) | Seq(_) | Map { .. } | Tuple(_) | TupleArray { .. }
293        )
294    }
295
296    fn quote_serialize_value(&self, value: &str, format: &Format) -> String {
297        use Format::*;
298        match format {
299            TypeName(_) => format!("{}.serialize(serializer);", value),
300            Unit => format!("serializer.serialize_unit({});", value),
301            Bool => format!("serializer.serialize_bool({});", value),
302            I8 => format!("serializer.serialize_i8({});", value),
303            I16 => format!("serializer.serialize_i16({});", value),
304            I32 => format!("serializer.serialize_i32({});", value),
305            I64 => format!("serializer.serialize_i64({});", value),
306            I128 => format!("serializer.serialize_i128({});", value),
307            U8 => format!("serializer.serialize_u8({});", value),
308            U16 => format!("serializer.serialize_u16({});", value),
309            U32 => format!("serializer.serialize_u32({});", value),
310            U64 => format!("serializer.serialize_u64({});", value),
311            U128 => format!("serializer.serialize_u128({});", value),
312            F32 => format!("serializer.serialize_f32({});", value),
313            F64 => format!("serializer.serialize_f64({});", value),
314            Char => format!("serializer.serialize_char({});", value),
315            Str => format!("serializer.serialize_str({});", value),
316            Bytes => format!("serializer.serialize_bytes({});", value),
317            _ => format!(
318                "{}.serialize_{}({}, serializer);",
319                self.quote_qualified_name("TraitHelpers"),
320                common::mangle_type(format),
321                value
322            ),
323        }
324    }
325
326    fn quote_deserialize(&self, format: &Format) -> String {
327        use Format::*;
328        match format {
329            TypeName(name) => format!(
330                "{}.deserialize(deserializer)",
331                self.quote_qualified_name(name)
332            ),
333            Unit => "deserializer.deserialize_unit()".to_string(),
334            Bool => "deserializer.deserialize_bool()".to_string(),
335            I8 => "deserializer.deserialize_i8()".to_string(),
336            I16 => "deserializer.deserialize_i16()".to_string(),
337            I32 => "deserializer.deserialize_i32()".to_string(),
338            I64 => "deserializer.deserialize_i64()".to_string(),
339            I128 => "deserializer.deserialize_i128()".to_string(),
340            U8 => "deserializer.deserialize_u8()".to_string(),
341            U16 => "deserializer.deserialize_u16()".to_string(),
342            U32 => "deserializer.deserialize_u32()".to_string(),
343            U64 => "deserializer.deserialize_u64()".to_string(),
344            U128 => "deserializer.deserialize_u128()".to_string(),
345            F32 => "deserializer.deserialize_f32()".to_string(),
346            F64 => "deserializer.deserialize_f64()".to_string(),
347            Char => "deserializer.deserialize_char()".to_string(),
348            Str => "deserializer.deserialize_str()".to_string(),
349            Bytes => "deserializer.deserialize_bytes()".to_string(),
350            _ => format!(
351                "{}.deserialize_{}(deserializer)",
352                self.quote_qualified_name("TraitHelpers"),
353                common::mangle_type(format),
354            ),
355        }
356    }
357
358    fn output_serialization_helper(&mut self, name: &str, format0: &Format) -> Result<()> {
359        use Format::*;
360
361        write!(
362            self.out,
363            "static void serialize_{}({} value, com.novi.serde.Serializer serializer) throws com.novi.serde.SerializationError {{",
364            name,
365            self.quote_type(format0)
366        )?;
367        self.out.indent();
368        match format0 {
369            Option(format) => {
370                write!(
371                    self.out,
372                    r#"
373if (value.isPresent()) {{
374    serializer.serialize_option_tag(true);
375    {}
376}} else {{
377    serializer.serialize_option_tag(false);
378}}
379"#,
380                    self.quote_serialize_value("value.get()", format)
381                )?;
382            }
383
384            Seq(format) => {
385                write!(
386                    self.out,
387                    r#"
388serializer.serialize_len(value.size());
389for ({} item : value) {{
390    {}
391}}
392"#,
393                    self.quote_type(format),
394                    self.quote_serialize_value("item", format)
395                )?;
396            }
397
398            Map { key, value } => {
399                write!(
400                    self.out,
401                    r#"
402serializer.serialize_len(value.size());
403int[] offsets = new int[value.size()];
404int count = 0;
405for (java.util.Map.Entry<{}, {}> entry : value.entrySet()) {{
406    offsets[count++] = serializer.get_buffer_offset();
407    {}
408    {}
409}}
410serializer.sort_map_entries(offsets);
411"#,
412                    self.quote_type(key),
413                    self.quote_type(value),
414                    self.quote_serialize_value("entry.getKey()", key),
415                    self.quote_serialize_value("entry.getValue()", value)
416                )?;
417            }
418
419            Tuple(formats) => {
420                writeln!(self.out)?;
421                for (index, format) in formats.iter().enumerate() {
422                    let expr = format!("value.field{}", index);
423                    writeln!(self.out, "{}", self.quote_serialize_value(&expr, format))?;
424                }
425            }
426
427            TupleArray { content, size } => {
428                write!(
429                    self.out,
430                    r#"
431if (value.size() != {0}) {{
432    throw new java.lang.IllegalArgumentException("Invalid length for fixed-size array: " + value.size() + " instead of "+ {0});
433}}
434for ({1} item : value) {{
435    {2}
436}}
437"#,
438                    size,
439                    self.quote_type(content),
440                    self.quote_serialize_value("item", content),
441                )?;
442            }
443
444            _ => panic!("unexpected case"),
445        }
446        self.out.unindent();
447        writeln!(self.out, "}}\n")
448    }
449
450    fn output_deserialization_helper(&mut self, name: &str, format0: &Format) -> Result<()> {
451        use Format::*;
452
453        write!(
454        self.out,
455        "static {} deserialize_{}(com.novi.serde.Deserializer deserializer) throws com.novi.serde.DeserializationError {{",
456        self.quote_type(format0),
457        name,
458    )?;
459        self.out.indent();
460        match format0 {
461            Option(format) => {
462                write!(
463                    self.out,
464                    r#"
465boolean tag = deserializer.deserialize_option_tag();
466if (!tag) {{
467    return java.util.Optional.empty();
468}} else {{
469    return java.util.Optional.of({});
470}}
471"#,
472                    self.quote_deserialize(format),
473                )?;
474            }
475
476            Seq(format) => {
477                write!(
478                    self.out,
479                    r#"
480long length = deserializer.deserialize_len();
481java.util.List<{0}> obj = new java.util.ArrayList<{0}>((int) length);
482for (long i = 0; i < length; i++) {{
483    obj.add({1});
484}}
485return obj;
486"#,
487                    self.quote_type(format),
488                    self.quote_deserialize(format)
489                )?;
490            }
491
492            Map { key, value } => {
493                write!(
494                    self.out,
495                    r#"
496long length = deserializer.deserialize_len();
497java.util.Map<{0}, {1}> obj = new java.util.HashMap<{0}, {1}>();
498int previous_key_start = 0;
499int previous_key_end = 0;
500for (long i = 0; i < length; i++) {{
501    int key_start = deserializer.get_buffer_offset();
502    {0} key = {2};
503    int key_end = deserializer.get_buffer_offset();
504    if (i > 0) {{
505        deserializer.check_that_key_slices_are_increasing(
506            new com.novi.serde.Slice(previous_key_start, previous_key_end),
507            new com.novi.serde.Slice(key_start, key_end));
508    }}
509    previous_key_start = key_start;
510    previous_key_end = key_end;
511    {1} value = {3};
512    obj.put(key, value);
513}}
514return obj;
515"#,
516                    self.quote_type(key),
517                    self.quote_type(value),
518                    self.quote_deserialize(key),
519                    self.quote_deserialize(value),
520                )?;
521            }
522
523            Tuple(formats) => {
524                write!(
525                    self.out,
526                    r#"
527return new {}({}
528);
529"#,
530                    self.quote_type(format0),
531                    formats
532                        .iter()
533                        .map(|f| format!("\n    {}", self.quote_deserialize(f)))
534                        .collect::<Vec<_>>()
535                        .join(",")
536                )?;
537            }
538
539            TupleArray { content, size } => {
540                write!(
541                    self.out,
542                    r#"
543java.util.List<{0}> obj = new java.util.ArrayList<{0}>({1});
544for (long i = 0; i < {1}; i++) {{
545    obj.add({2});
546}}
547return obj;
548"#,
549                    self.quote_type(content),
550                    size,
551                    self.quote_deserialize(content)
552                )?;
553            }
554
555            _ => panic!("unexpected case"),
556        }
557        self.out.unindent();
558        writeln!(self.out, "}}\n")
559    }
560
561    fn output_variant(
562        &mut self,
563        base: &str,
564        index: u32,
565        name: &str,
566        variant: &VariantFormat,
567    ) -> Result<()> {
568        use VariantFormat::*;
569        let fields = match variant {
570            Unit => Vec::new(),
571            NewType(format) => vec![Named {
572                name: "value".to_string(),
573                value: format.as_ref().clone(),
574            }],
575            Tuple(formats) => formats
576                .iter()
577                .enumerate()
578                .map(|(i, f)| Named {
579                    name: format!("field{}", i),
580                    value: f.clone(),
581                })
582                .collect(),
583            Struct(fields) => fields.clone(),
584            Variable(_) => panic!("incorrect value"),
585        };
586        self.output_struct_or_variant_container(Some(base), Some(index), name, &fields)
587    }
588
589    fn output_variants(
590        &mut self,
591        base: &str,
592        variants: &BTreeMap<u32, Named<VariantFormat>>,
593    ) -> Result<()> {
594        for (index, variant) in variants {
595            self.output_variant(base, *index, &variant.name, &variant.value)?;
596        }
597        Ok(())
598    }
599
600    fn output_struct_or_variant_container(
601        &mut self,
602        variant_base: Option<&str>,
603        variant_index: Option<u32>,
604        name: &str,
605        fields: &[Named<Format>],
606    ) -> Result<()> {
607        // Beginning of class
608        writeln!(self.out)?;
609        if let Some(base) = variant_base {
610            self.output_comment(name)?;
611            writeln!(
612                self.out,
613                "public static final class {} extends {} {{",
614                name, base
615            )?;
616        } else {
617            self.output_comment(name)?;
618            writeln!(self.out, "public final class {} {{", name)?;
619        }
620        let reserved_names = &["Builder"];
621        self.enter_class(name, reserved_names);
622        // Fields
623        for field in fields {
624            self.output_comment(&field.name)?;
625            writeln!(
626                self.out,
627                "public final {} {};",
628                self.quote_type(&field.value),
629                field.name
630            )?;
631        }
632        if !fields.is_empty() {
633            writeln!(self.out)?;
634        }
635        // Constructor.
636        writeln!(
637            self.out,
638            "public {}({}) {{",
639            name,
640            fields
641                .iter()
642                .map(|f| format!("{} {}", self.quote_type(&f.value), &f.name))
643                .collect::<Vec<_>>()
644                .join(", ")
645        )?;
646        self.out.indent();
647        for field in fields {
648            writeln!(
649                self.out,
650                "java.util.Objects.requireNonNull({0}, \"{0} must not be null\");",
651                &field.name
652            )?;
653        }
654        for field in fields {
655            writeln!(self.out, "this.{} = {};", &field.name, &field.name)?;
656        }
657        self.out.unindent();
658        writeln!(self.out, "}}")?;
659        // Serialize
660        if self.generator.config.serialization {
661            writeln!(
662                self.out,
663                "\npublic void serialize(com.novi.serde.Serializer serializer) throws com.novi.serde.SerializationError {{",
664            )?;
665            self.out.indent();
666            writeln!(self.out, "serializer.increase_container_depth();")?;
667            if let Some(index) = variant_index {
668                writeln!(self.out, "serializer.serialize_variant_index({});", index)?;
669            }
670            for field in fields {
671                writeln!(
672                    self.out,
673                    "{}",
674                    self.quote_serialize_value(&field.name, &field.value)
675                )?;
676            }
677            writeln!(self.out, "serializer.decrease_container_depth();")?;
678            self.out.unindent();
679            writeln!(self.out, "}}")?;
680
681            if variant_index.is_none() {
682                for encoding in &self.generator.config.encodings {
683                    self.output_class_serialize_for_encoding(*encoding)?;
684                }
685            }
686        }
687        // Deserialize (struct) or Load (variant)
688        if self.generator.config.serialization {
689            if variant_index.is_none() {
690                writeln!(
691                    self.out,
692                    "\npublic static {} deserialize(com.novi.serde.Deserializer deserializer) throws com.novi.serde.DeserializationError {{",
693                    name,
694                )?;
695            } else {
696                writeln!(
697                    self.out,
698                    "\nstatic {} load(com.novi.serde.Deserializer deserializer) throws com.novi.serde.DeserializationError {{",
699                    name,
700                )?;
701            }
702            self.out.indent();
703            writeln!(self.out, "deserializer.increase_container_depth();")?;
704            writeln!(self.out, "Builder builder = new Builder();")?;
705            for field in fields {
706                writeln!(
707                    self.out,
708                    "builder.{} = {};",
709                    field.name,
710                    self.quote_deserialize(&field.value)
711                )?;
712            }
713            writeln!(self.out, "deserializer.decrease_container_depth();")?;
714            writeln!(self.out, "return builder.build();")?;
715            self.out.unindent();
716            writeln!(self.out, "}}")?;
717
718            if variant_index.is_none() {
719                for encoding in &self.generator.config.encodings {
720                    self.output_class_deserialize_for_encoding(name, *encoding)?;
721                }
722            }
723        }
724        // Equality
725        write!(self.out, "\npublic boolean equals(Object obj) {{")?;
726        self.out.indent();
727        writeln!(
728            self.out,
729            r#"
730if (this == obj) return true;
731if (obj == null) return false;
732if (getClass() != obj.getClass()) return false;
733{0} other = ({0}) obj;"#,
734            name,
735        )?;
736        for field in fields {
737            writeln!(
738                self.out,
739                "if (!java.util.Objects.equals(this.{0}, other.{0})) {{ return false; }}",
740                &field.name,
741            )?;
742        }
743        writeln!(self.out, "return true;")?;
744        self.out.unindent();
745        writeln!(self.out, "}}")?;
746        // Hashing
747        writeln!(self.out, "\npublic int hashCode() {{")?;
748        self.out.indent();
749        writeln!(self.out, "int value = 7;",)?;
750        for field in fields {
751            writeln!(
752                self.out,
753                "value = 31 * value + (this.{0} != null ? this.{0}.hashCode() : 0);",
754                &field.name
755            )?;
756        }
757        writeln!(self.out, "return value;")?;
758        self.out.unindent();
759        writeln!(self.out, "}}")?;
760        // Builder
761        self.output_struct_or_variant_container_builder(name, fields)?;
762        // Custom code
763        self.output_custom_code()?;
764        // End of class
765        self.leave_class(reserved_names);
766        writeln!(self.out, "}}")
767    }
768
769    fn output_struct_or_variant_container_builder(
770        &mut self,
771        name: &str,
772        fields: &[Named<Format>],
773    ) -> Result<()> {
774        // Beginning of builder class
775        writeln!(self.out)?;
776        writeln!(self.out, "public static final class Builder {{")?;
777        let reserved_names = &[];
778        self.enter_class("Builder", reserved_names);
779        // Fields
780        for field in fields {
781            writeln!(
782                self.out,
783                "public {} {};",
784                self.quote_type(&field.value),
785                field.name
786            )?;
787        }
788        if !fields.is_empty() {
789            writeln!(self.out)?;
790        }
791        // Finalization
792        writeln!(
793            self.out,
794            r#"public {0} build() {{
795    return new {0}({1}
796    );
797}}"#,
798            name,
799            fields
800                .iter()
801                .map(|f| format!("\n        {}", f.name))
802                .collect::<Vec<_>>()
803                .join(",")
804        )?;
805        // Custom code
806        self.output_custom_code()?;
807        // End of class
808        self.leave_class(reserved_names);
809        writeln!(self.out, "}}")
810    }
811
812    fn output_enum_container(
813        &mut self,
814        name: &str,
815        variants: &BTreeMap<u32, Named<VariantFormat>>,
816    ) -> Result<()> {
817        writeln!(self.out)?;
818        self.output_comment(name)?;
819        writeln!(self.out, "public abstract class {} {{", name)?;
820        let reserved_names = variants
821            .values()
822            .map(|v| v.name.as_str())
823            .collect::<Vec<_>>();
824        self.enter_class(name, &reserved_names);
825        if self.generator.config.serialization {
826            writeln!(
827                self.out,
828                "\nabstract public void serialize(com.novi.serde.Serializer serializer) throws com.novi.serde.SerializationError;"
829            )?;
830            write!(
831                self.out,
832                "\npublic static {} deserialize(com.novi.serde.Deserializer deserializer) throws com.novi.serde.DeserializationError {{",
833                name
834            )?;
835            self.out.indent();
836            writeln!(
837                self.out,
838                r#"
839int index = deserializer.deserialize_variant_index();
840switch (index) {{"#,
841            )?;
842            self.out.indent();
843            for (index, variant) in variants {
844                writeln!(
845                    self.out,
846                    "case {}: return {}.load(deserializer);",
847                    index, variant.name,
848                )?;
849            }
850            writeln!(
851                self.out,
852                "default: throw new com.novi.serde.DeserializationError(\"Unknown variant index for {}: \" + index);",
853                name,
854            )?;
855            self.out.unindent();
856            writeln!(self.out, "}}")?;
857            self.out.unindent();
858            writeln!(self.out, "}}")?;
859
860            for encoding in &self.generator.config.encodings {
861                self.output_class_serialize_for_encoding(*encoding)?;
862                self.output_class_deserialize_for_encoding(name, *encoding)?;
863            }
864        }
865
866        self.output_variants(name, variants)?;
867        self.leave_class(&reserved_names);
868        writeln!(self.out, "}}\n")
869    }
870
871    fn output_class_serialize_for_encoding(&mut self, encoding: Encoding) -> Result<()> {
872        writeln!(
873            self.out,
874            r#"
875public byte[] {0}Serialize() throws com.novi.serde.SerializationError {{
876    com.novi.serde.Serializer serializer = new com.novi.{0}.{1}Serializer();
877    serialize(serializer);
878    return serializer.get_bytes();
879}}"#,
880            encoding.name(),
881            encoding.name().to_camel_case()
882        )
883    }
884
885    fn output_class_deserialize_for_encoding(
886        &mut self,
887        name: &str,
888        encoding: Encoding,
889    ) -> Result<()> {
890        writeln!(
891            self.out,
892            r#"
893public static {0} {1}Deserialize(byte[] input) throws com.novi.serde.DeserializationError {{
894    if (input == null) {{
895         throw new com.novi.serde.DeserializationError("Cannot deserialize null array");
896    }}
897    com.novi.serde.Deserializer deserializer = new com.novi.{1}.{2}Deserializer(input);
898    {0} value = deserialize(deserializer);
899    if (deserializer.get_buffer_offset() < input.length) {{
900         throw new com.novi.serde.DeserializationError("Some input bytes were not read");
901    }}
902    return value;
903}}"#,
904            name,
905            encoding.name(),
906            encoding.name().to_camel_case()
907        )
908    }
909
910    fn output_container(&mut self, name: &str, format: &ContainerFormat) -> Result<()> {
911        use ContainerFormat::*;
912        let fields = match format {
913            UnitStruct => Vec::new(),
914            NewTypeStruct(format) => vec![Named {
915                name: "value".to_string(),
916                value: format.as_ref().clone(),
917            }],
918            TupleStruct(formats) => formats
919                .iter()
920                .enumerate()
921                .map(|(i, f)| Named {
922                    name: format!("field{}", i),
923                    value: f.clone(),
924                })
925                .collect::<Vec<_>>(),
926            Struct(fields) => fields.clone(),
927            Enum(variants) => {
928                self.output_enum_container(name, variants)?;
929                return Ok(());
930            }
931        };
932        self.output_struct_or_variant_container(None, None, name, &fields)
933    }
934}
935
936/// Installer for generated source files in Java.
937pub struct Installer {
938    install_dir: PathBuf,
939}
940
941impl Installer {
942    pub fn new(install_dir: PathBuf) -> Self {
943        Installer { install_dir }
944    }
945
946    fn install_runtime(
947        &self,
948        source_dir: include_dir::Dir,
949        path: &str,
950    ) -> std::result::Result<(), Box<dyn std::error::Error>> {
951        let dir_path = self.install_dir.join(path);
952        std::fs::create_dir_all(&dir_path)?;
953        for entry in source_dir.files() {
954            let mut file = std::fs::File::create(dir_path.join(entry.path()))?;
955            file.write_all(entry.contents())?;
956        }
957        Ok(())
958    }
959}
960
961impl crate::SourceInstaller for Installer {
962    type Error = Box<dyn std::error::Error>;
963
964    fn install_module(
965        &self,
966        config: &CodeGeneratorConfig,
967        registry: &Registry,
968    ) -> std::result::Result<(), Self::Error> {
969        let generator = CodeGenerator::new(config);
970        generator.write_source_files(self.install_dir.clone(), registry)?;
971        Ok(())
972    }
973
974    fn install_serde_runtime(&self) -> std::result::Result<(), Self::Error> {
975        self.install_runtime(
976            include_directory!("runtime/java/com/novi/serde"),
977            "com/novi/serde",
978        )
979    }
980
981    fn install_bincode_runtime(&self) -> std::result::Result<(), Self::Error> {
982        self.install_runtime(
983            include_directory!("runtime/java/com/novi/bincode"),
984            "com/novi/bincode",
985        )
986    }
987
988    fn install_bcs_runtime(&self) -> std::result::Result<(), Self::Error> {
989        self.install_runtime(
990            include_directory!("runtime/java/com/novi/bcs"),
991            "com/novi/bcs",
992        )
993    }
994}