7.3 KiB
7.3 KiB
Paisy — Development Guidelines
Code Quality Standards
Logging
- Use
@Log4j2(Lombok) for existing modules that already use Log4j2 (e.g.,AbstractMeldung) - Use
@Slf4j(Lombok) for new code — this is the preferred default - Use parameterized logging:
log.debug("Value: {}", value)— never string concatenation - Some legacy code mixes styles:
log.debug("text " + var)— refactor to parameterized when touching these lines - Log levels:
debugfor flow tracing,warnfor recoverable issues,errorfor failures
Naming Conventions
- Package:
com.adp.de.paisy.modules.<module>for modules,com.adp.de.<module>for legacy - German domain terms preserved in class/field names:
Fehlzeiten,Lohnkonto,Vorlaufsatz,Nachlaufsatz,Meldekorrekturen - JAXB-generated classes use German XML element names as Java identifiers:
getAngabenZurPersonAV(),getBeschreibungTaetigkeitDE() - Constants use UPPER_SNAKE_CASE:
EMPTY_DATE_LONG,EMPTY_BBNR,MAX_DBFZ - Date formatters as
finalfields:bausteinf,pai022f,PAI_SHORT
Field Visibility
protectedfor fields shared with subclasses (common in abstract controllers)privatewith Lombok@Getter/@Setterfor DTOsstatic private finalfor constants (PDDI layer uses tab-indented style)
Structural Conventions
Module Entry Point Pattern
@Slf4j
@Service("module-name")
@Lazy
public class ModuleRunner implements ConsoleService {
@Override
public void run(String... args) throws Exception { /* ... */ }
}
Abstract Controller Pattern (5/5 files)
Business modules use abstract base classes for shared logic:
@Log4j2
public abstract class AbstractMeldung {
// Shared date formatters, parsers, PAISY interaction
protected Person person;
protected Fehlzeiten fz;
public Person initBaustein(Datenbaustein main, DBNA dbna, ...) { /* ... */ }
protected Lohnkonto parseLohnkonto(...) { /* ... */ }
}
Datenbaustein (Data Block) Pattern (5/5 files)
Core data exchange pattern — field-based data blocks with positional access:
Datenbaustein main = ...;
main.setValue("FEKZ", "0");
main.setValue("VSNR", person.getValue("VSNR"));
String value = d508b.getValue("F39-AVUWFWZ-10-50-8B");
ServiceCenter Singleton Pattern
Central access point for PAISY system interaction:
ServiceCenter.INSTANCE().getBaustein(Datengruppe.NAME, vorgangsID);
ServiceCenter.INSTANCE().getPaisy().pgmFunktionCall("S;" + bbnrvu + ";");
ServiceCenter.INSTANCE().getPaisy().pgmReadLine();
EMFactory Singleton Pattern
Each module has its own EntityManager factory:
EMFactoryEAU emFactory = EMFactoryEAU.getInstance();
FlywayController flyway = new FlywayController(emFactory);
flyway.migrate("EAU", "2024_09_08_17_48_11");
JAXB XML Binding Pattern (3/5 files)
JAXB-generated classes follow a strict pattern for GKV data exchange:
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = { "steuerungsdaten", "angabenZurPersonAV", ... })
@XmlRootElement(name = "A1_Ausnahmevereinbarung",
namespace = "http://www.gkv-datenaustausch.de/XMLSchema/A1_Ausnahme/2.0")
public class A1Ausnahmevereinbarung {
@XmlElement(name = "Steuerungsdaten",
namespace = "http://www.gkv-datenaustausch.de/XMLSchema/A1_Ausnahme/2.0",
required = true)
protected SteuerungsdatenAGV2Ctp steuerungsdaten;
}
Key rules:
- Nested
public static classfor complex type hierarchies - German Javadoc:
"Ruft den Wert der X-Eigenschaft ab"/"Legt den Wert der X-Eigenschaft fest" jakarta.xml.bind.annotation.*(Jakarta EE, not javax)XMLGregorianCalendarfor date fields,BigIntegerfor numeric codesKennzeichenAlphanumerischTypenum for J/N flag fields
PDF Generation Pattern (2/5 files)
Using OpenPDF (iText fork) for government-compliant PDF reports:
Document document = new Document(PageSize.A4, 50, 50, 50, 50);
PdfWriter writer = PdfWriter.getInstance(document, baos);
document.open();
// Header
Paragraph headline = new Paragraph("EuBP", getHeaderFont());
document.add(headline);
// Two-column table: Bezeichnung | Inhalt
PdfPTable table = new PdfPTable(2);
table.setWidthPercentage(75);
table.setHorizontalAlignment(Element.ALIGN_LEFT);
addTableHeader(table, new String[]{"Bezeichnung", "Inhalt"});
table.addCell(createCell("Verfahrensmerkmal"));
table.addCell(createCell(vorlaufsatz.getVerfahrensmerkmal().value));
document.add(table);
Font conventions:
- Header: Helvetica Bold 18pt
- Subheader: Helvetica Bold 14pt
- Bold: Helvetica Bold 12pt
- Normal: Helvetica 10pt
- Table header background:
new Color(220, 220, 220)
ISAM/Oracle Trigger Generation (1/5 files)
JavaScript code generator for Oracle INSTEAD OF triggers:
// gen_trigger.js — generates Oracle triggers for COBOL ISAM → Oracle mirroring
gen("YP_ABR_STEUER", `
,MUT_YP_ABR_STEUER.ABSCHNITT
,MUT_YP_ABR_STEUER.BEMERKUNG
...
`)
Pattern: IPW_<recname> view → MUT_<recname> mutation table, with ak_nr/pers_nr lookup from PS_YP_PERS_MAIN.
Binary Protocol Pattern (1/5 files)
Custom binary serialization for PDDI middleware (DocumentStream):
- Type-tagged byte protocol:
b_null='~',b_string='S',b_int='i',b_date='d' - Compact encoding: shorts for small ints, full 8 bytes only when needed
- Custom charset:
PaisyCharset.CHARSET(likely ISO-8859-1) - Inner classes:
BytesOutput,Output(stream-based),Input(stream-based)
Date Handling Patterns
// German user-facing format
DateTimeFormatter.ofPattern("dd.MM.yyyy")
// Internal PAISY format (8-digit)
DateTimeFormatter.ofPattern("yyyyMMdd")
// Short PAISY format (6-digit, 2-digit year)
DateTimeFormatter.ofPattern("yyMMdd")
// Null/empty date handling
if (value.equals("00.00.0000")) return LocalDate.MAX;
if (paidate.equals("0000000")) return LocalDate.MIN;
if (paidate.equals("9999999")) return LocalDate.MAX;
Error Handling
- Custom exceptions:
PaisyIOException,PaisyRuntimeException,AccessDeniedException,PaisyNotFoundException,UnauthorizedException - PAISY error responses start with
"F;"— check before parsing - Null-safe patterns: check for null before processing sections (PDF, data blocks)
- Reflection-based construction with explicit error messages for field count mismatches
Frequently Used Annotations
| Annotation | Usage | Frequency |
|---|---|---|
@Log4j2 / @Slf4j |
Logging | Every class |
@Getter / @Setter |
Lombok accessors | DTOs, models |
@XmlElement / @XmlAccessorType |
JAXB binding | XML model classes |
@XmlRootElement / @XmlType |
JAXB root types | Top-level XML types |
@XmlSchemaType |
JAXB schema mapping | XML fields |
@Service("name") / @Lazy |
Spring service registration | Module entry points |
@Transactional |
DB transactions | Service methods |
@Data / @Builder |
Lombok DTOs | Model classes |
Code Idioms
CommonRoutines.paidate2Datenbaustein()— convert PAISY date to Datenbaustein formatCommonRoutines.uuid()— generate unique dataset IDsCommonRoutines.getDocumentPath()— get output file pathServiceCenter.INSTANCE().getPaisy().nextPaisy(line)— iterate PAISY response linesline.split(";")— semicolon-delimited PAISY response parsing- Streams with
Collectors.toCollection(ArrayList::new)for mutable result lists