Skip to content

feat: API записи объектов метаданных (Subsystem, Catalog, Configuration) в формате конфигуратора (JAXB)#597

Open
johnnyshut wants to merge 1 commit into1c-syntax:developfrom
johnnyshut:feature/meta-writer
Open

feat: API записи объектов метаданных (Subsystem, Catalog, Configuration) в формате конфигуратора (JAXB)#597
johnnyshut wants to merge 1 commit into1c-syntax:developfrom
johnnyshut:feature/meta-writer

Conversation

@johnnyshut
Copy link
Contributor

@johnnyshut johnnyshut commented Mar 20, 2026

Описание

TODO

Связанные задачи

Closes #158

Чеклист

Общие

  • Ветка PR обновлена из develop
  • Отладочные, закомментированные и прочие, не имеющие смысла участки кода удалены
  • Изменения покрыты тестами
  • Обязательные действия перед коммитом выполнены (запускал команду gradlew precommit)

Дополнительно

Summary by CodeRabbit

  • New Features

    • Added support for writing 1C metadata objects in Designer XML format
    • New capability to export entire configuration to folder structure with automatic path resolution
    • Optional filtering of metadata types during export
    • Support for serializing multiple metadata object types including configuration, catalogs, documents, roles, and subsystems
  • Dependencies

    • Added Jakarta JAXB support for XML serialization

@coderabbitai
Copy link

coderabbitai bot commented Mar 20, 2026

📝 Walkthrough

Walkthrough

Added JAXB-based XML writing support for 1C metadata objects. This PR introduces XSD schemas for multiple v8.x namespaces, JAXB configuration bindings, infrastructure classes for marshalling metadata to Designer XML format, type-specific converters for each metadata object kind, and comprehensive tests validating output generation.

Changes

Cohort / File(s) Summary
Build Configuration
build.gradle.kts
Added Jakarta JAXB dependencies (jakarta.xml.bind-api, jaxb-runtime), configured XJC code generation task (xjcMDClasses) to generate Java sources from XSD under src/main/xsd/v8.5, and integrated generated sources into compilation and JAR packaging.
Core JAXB Infrastructure
src/main/java/.../jaxb/write/JaxbWriteDefaults.java, JaxbWriteUtils.java, DesignerNamespacePrefixMapper.java
Added utility classes providing default JAXB object factories, namespace prefix mapping for Designer XML output, and multi-language string content extraction helpers.
JAXB Writer & Path Resolution
src/main/java/.../jaxb/write/DesignerJaxbWriter.java, DesignerPathResolver.java, MDClassesJaxbWriter.java, WriteOptions.java
Added JAXB marshalling infrastructure, Designer XML post-processing (namespace/format adjustments, InternalInfo injection), filesystem path resolution for output files, and a registry-based converter dispatch system with selective export filtering via WriteOptions.
Metadata Type Converters (30+ classes)
src/main/java/.../jaxb/write/*ToJaxbConverter.java, package-info.java
Added converter classes (e.g., ConfigurationToJaxbConverter, CatalogToJaxbConverter, DocumentToJaxbConverter, etc.) that transform domain models into JAXB DTOs. Each converter follows a consistent pattern: building properties with defaults and null-to-empty-string fallbacks, constructing child object collections, and wrapping results in the root MetaDataObject.
XSD Schemas (v8.3.27)
src/main/xsd/v8.3.27/v8.1c.ru-*.xsd, catalog.xml, bindings.xjb
Added comprehensive XSD definitions for core data types, enterprise structures, UI elements, BSL metadata, spreadsheet documents, managed application layouts, CMI configurations, and MDClasses metadata across multiple v8.x namespaces; included OASIS XML catalog for URI-to-file resolution and JAXB external bindings for namespace-to-package mapping.
XSD Schemas (v8.5)
src/main/xsd/v8.5/v8.1c.ru-*.xsd, catalog.xml, bindings.xjb
Duplicated XSD schema set (v8.3.27 counterparts) under v8.5 directory structure with identical content and JAXB binding configuration for code generation into dedicated package namespaces.
Integration Tests
src/test/java/.../jaxb/write/*Test.java
Added JUnit 5 test classes validating JAXB writing for multiple object types (Subsystem, Catalog, Configuration, Role, Document), verifying XML structure/content, path resolution, type filtering, folder export with nested subsystems and catalog forms, and error handling for unsupported types.

Sequence Diagram(s)

sequenceDiagram
    participant App as Application
    participant Converter as Type Converter<br/>(e.g., CatalogToJaxbConverter)
    participant Factory as JAXB<br/>ObjectFactory
    participant Marshaller as JAXB<br/>Marshaller
    participant PostProcessor as XML<br/>Post-Processor
    participant File as Output<br/>File

    App->>Converter: toMetaDataObject(domainObject)
    Converter->>Factory: create MetaDataObject
    Factory-->>Converter: jaxbRoot
    Converter->>Factory: create inner JAXB DTO
    Factory-->>Converter: innerDto
    Converter->>Converter: buildProperties(domainObject)
    Converter->>Converter: buildChildObjects(domainObject)
    Converter-->>App: MetaDataObject tree
    
    App->>Marshaller: marshal MetaDataObject
    Marshaller->>PostProcessor: transform XML string
    PostProcessor->>PostProcessor: adjust namespaces
    PostProcessor->>PostProcessor: inject InternalInfo blocks
    PostProcessor->>PostProcessor: strip formatVersion from config
    PostProcessor-->>Marshaller: processed XML
    Marshaller->>File: write UTF-8 XML
    File-->>App: File written
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • PR #524: Changes to MultiLanguageString representation and enum/name type structures are foundational to how the new converter classes extract and format localized content in JAXB output.

Poem

🐇 Hoppity-hop! The writers now bloom,
From Java beans to XML room,
Metadata flows both ways with glee,
Read and write—symmetric decree!

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 17

Note

Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.

🟡 Minor comments (10)
src/test/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/DesignerPathResolverTest.java-50-65 (1)

50-65: ⚠️ Potential issue | 🟡 Minor

Test silently passes if nested subsystem data is missing.

The early return on lines 56-58 means if the test fixture has no child subsystems, the test passes without validating nested path resolution. This could mask regressions if test data changes.

Consider using assumeTrue to skip explicitly, or assert that children exist to fail fast:

Proposed fix
     var children = parentSub.getSubsystems();
-    if (children == null || children.isEmpty()) {
-      return;
-    }
+    assertThat(children).as("Expected nested subsystems in test fixture").isNotEmpty();
     MD child = children.get(0);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/test/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/DesignerPathResolverTest.java`
around lines 50 - 65, The test pathForObjectNestedSubsystem currently returns
early when parentSub.getSubsystems() is null or empty, hiding missing test data;
replace the early return with an explicit precondition/assertion such as using
assumeTrue(children != null && !children.isEmpty()) to skip the test when
fixtures are missing or assertThat(children).isNotEmpty() to fail fast,
referencing the test method pathForObjectNestedSubsystem and the children
variable (parentSub.getSubsystems()) so downstream code always exercises
DesignerPathResolver.pathForObject when child subsystems are present.
src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/CommonModuleToJaxbConverter.java-55-58 (1)

55-58: ⚠️ Potential issue | 🟡 Minor

Potential IllegalArgumentException from enum fromValue().

ReturnValuesReuse.fromValue(...) may throw IllegalArgumentException if the English name doesn't match any JAXB enum value. Consider wrapping in try-catch or validating the value first.

Proposed defensive handling
     ReturnValueReuse rvr = c.getReturnValuesReuse();
     if (rvr != null && rvr != ReturnValueReuse.UNKNOWN && rvr.fullName() != null) {
-      p.setReturnValuesReuse(com.github._1c_syntax.bsl.mdclasses.jaxb.v8_3_xcf_enums.ReturnValuesReuse.fromValue(rvr.fullName().getEn()));
+      try {
+        p.setReturnValuesReuse(
+          com.github._1c_syntax.bsl.mdclasses.jaxb.v8_3_xcf_enums.ReturnValuesReuse.fromValue(rvr.fullName().getEn()));
+      } catch (IllegalArgumentException ignored) {
+        // Skip if enum value doesn't map to JAXB enum
+      }
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/CommonModuleToJaxbConverter.java`
around lines 55 - 58, ReturnValuesReuse.fromValue(...) can throw
IllegalArgumentException when the English name doesn't match a JAXB enum; update
the block that reads ReturnValueReuse rvr in CommonModuleToJaxbConverter to
defensively handle invalid values (reference symbols: ReturnValueReuse, rvr,
p.setReturnValuesReuse, ReturnValuesReuse.fromValue, rvr.fullName().getEn()).
Wrap the fromValue call in a try-catch (catch IllegalArgumentException) or
pre-validate/mapping the string to a known JAXB enum value, and only call
p.setReturnValuesReuse(...) when a valid enum is resolved; on invalid value,
skip setting or log/debug the unexpected name so conversion won't throw.
src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/CommonModuleToJaxbConverter.java-45-45 (1)

45-45: ⚠️ Potential issue | 🟡 Minor

Missing null check for name property.

Same issue as in AccumulationRegisterToJaxbConverter - name should have a null check for consistency with other string properties.

Proposed fix
-    p.setName(c.getName());
+    p.setName(c.getName() != null ? c.getName() : "");
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/CommonModuleToJaxbConverter.java`
at line 45, In CommonModuleToJaxbConverter, the call p.setName(c.getName())
lacks a null check; update the converter to mirror the pattern used for other
string properties (as in AccumulationRegisterToJaxbConverter) by only calling
p.setName(...) when c.getName() is non-null (e.g., check c.getName() != null
before invoking p.setName), ensuring you reference the same variables/methods
(p, c, getName, setName) within the CommonModuleToJaxbConverter class.
src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/AccumulationRegisterToJaxbConverter.java-47-47 (1)

47-47: ⚠️ Potential issue | 🟡 Minor

Missing null check for name property.

Unlike other properties in this method (e.g., comment on line 49), name is set directly without a null check. This inconsistency could lead to null values in the output XML.

Proposed fix
-    p.setName(ar.getName());
+    p.setName(ar.getName() != null ? ar.getName() : "");
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/AccumulationRegisterToJaxbConverter.java`
at line 47, The assignment p.setName(ar.getName()) in
AccumulationRegisterToJaxbConverter should be guarded like the other properties
to avoid emitting nulls; update the conversion logic to check ar.getName() for
null (e.g., if (ar.getName() != null) p.setName(ar.getName()); or use a safe
default) when setting the JAXB property on p so name is only set when non-null.
src/main/xsd/v8.3.27/v8.1c.ru-8.2-managed-application-cmi.xsd-104-115 (1)

104-115: ⚠️ Potential issue | 🟡 Minor

This is a confirmed typo inherited from the official 1C platform schema.

CommansShortCutInfo and CommansShortCutInfoVector contain a spelling error ("Commans" instead of "Commands"). This appears in the official 1C schema namespace (http://v8.1c.ru/8.2/managed-application/cmi) and is mirrored across multiple versions (v8.3.27 and v8.5). The web search found no evidence of "CommansShortCutInfo" in official 1C documentation or EDT API, confirming this is a typo from the upstream source rather than an intentional naming convention.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/xsd/v8.3.27/v8.1c.ru-8.2-managed-application-cmi.xsd` around lines
104 - 115, Rename the misspelled complexType names CommansShortCutInfo and
CommansShortCutInfoVector to CommandsShortCutInfo and
CommandsShortCutInfoVector, update every reference to tns:CommansShortCutInfo
(and the vector type) across the schema to use tns:CommandsShortCutInfo, and
update the element declarations that reference those types (e.g., the "info"
element). To preserve backward compatibility, add a deprecated alias complexType
named CommansShortCutInfo that extends or references the new
CommandsShortCutInfo (and similarly for the vector) so existing consumers still
resolve the old name while new code uses the corrected names.
src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/WriteOptions.java-22-28 (1)

22-28: ⚠️ Potential issue | 🟡 Minor

Defensive copy needed for typeFilter to ensure immutability.

The typeFilter Set is stored and returned by reference, allowing external mutation of the "immutable" WriteOptions. Consider making a defensive copy in the constructor and returning an unmodifiable view from the getter.

🛡️ Proposed fix for immutability
 import com.github._1c_syntax.bsl.types.MDOType;
 
+import java.util.Collections;
 import java.util.Set;
 
 ...
 
   private WriteOptions(Builder builder) {
     this.useShortNamesInChildObjects = builder.useShortNamesInChildObjects;
     this.version = builder.version;
-    this.typeFilter = builder.typeFilter;
+    this.typeFilter = builder.typeFilter != null ? Set.copyOf(builder.typeFilter) : null;
   }

 ...
 
   public Set<MDOType> getTypeFilter() {
-    return typeFilter;
+    return typeFilter;  // Already immutable from Set.copyOf()
   }

Also applies to: 50-52

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/WriteOptions.java`
around lines 22 - 28, The WriteOptions class currently stores the
Builder.typeFilter reference directly, allowing external mutation; in the
WriteOptions(Builder builder) constructor make a defensive copy of
builder.typeFilter (e.g., new HashSet<>(builder.typeFilter) or
Collections.emptySet() when null) and assign that to this.typeFilter, and update
the getTypeFilter() accessor to return an unmodifiable view
(Collections.unmodifiableSet(this.typeFilter)) to preserve immutability;
reference the WriteOptions constructor, the typeFilter field, the
Builder.typeFilter and the getTypeFilter() method when applying the change.
src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/ConfigurationToJaxbConverter.java-56-59 (1)

56-59: ⚠️ Potential issue | 🟡 Minor

Random UUID generation may cause non-deterministic output.

Generating a random UUID when the source UUID is missing makes the output non-reproducible across runs. Consider logging a warning or throwing an exception instead, or accepting the UUID as a parameter.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/ConfigurationToJaxbConverter.java`
around lines 56 - 59, The nonEmptyUuid method in ConfigurationToJaxbConverter
currently generates a random UUID when input is null/blank, causing
non-deterministic output; change this to fail fast instead: remove random UUID
generation and throw an IllegalArgumentException (or IllegalStateException) with
a clear message when uuid is null or blank, and optionally log a warning before
throwing; update any callers of nonEmptyUuid to handle or propagate this
exception so missing UUIDs are surfaced instead of silently inserting random
values.
src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/ChartOfAccountsToJaxbConverter.java-45-51 (1)

45-51: ⚠️ Potential issue | 🟡 Minor

Incomplete property mapping compared to other converters.

The buildProperties method only sets name, synonym, and comment. Other converters (e.g., AccountingRegisterToJaxbConverter) set many additional default properties like objectBelonging, useStandardCommands, standardAttributes, etc. This inconsistency may cause validation errors or incomplete XML output.

💡 Consider adding standard default properties
   private static ChartOfAccountsProperties buildProperties(ChartOfAccounts coa) {
     ChartOfAccountsProperties p = FACTORY.createChartOfAccountsProperties();
     p.setName(coa.getName());
     p.setSynonym(JaxbWriteDefaults.localStringType(JaxbWriteUtils.contentForLocalString(coa.getSynonym())));
     p.setComment(coa.getComment() != null ? coa.getComment() : "");
+    p.setObjectBelonging(JaxbWriteDefaults.objectBelongingNative());
+    p.setUseStandardCommands(false);
+    // Add other standard defaults as needed
     return p;
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/ChartOfAccountsToJaxbConverter.java`
around lines 45 - 51, The buildProperties method in
ChartOfAccountsToJaxbConverter only sets name, synonym and comment; update
ChartOfAccountsToJaxbConverter.buildProperties to populate the same
standard/default JAXB fields other converters set (for example see
AccountingRegisterToJaxbConverter): set objectBelonging, useStandardCommands,
standardAttributes, useStandardAccounting, standardAccumulation, and any other
default boolean/string/list properties your other converters initialize; use the
same helper utilities (JaxbWriteDefaults.* and
JaxbWriteUtils.contentForLocalString) to create default values and local strings
so the ChartOfAccountsProperties object matches the shape produced by the other
converters and avoids validation/serialization gaps.
src/test/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/DesignerJaxbWriterTest.java-97-103 (1)

97-103: ⚠️ Potential issue | 🟡 Minor

Avoid filesystem writes outside @TempDir in negative-path test.

At Line 102, using Path.of("out.xml") ties the test to process working directory and can create flaky side effects. Prefer @TempDir-scoped output even when expecting an exception.

Suggested fix
-  void writeUnsupportedTypeThrows() {
+  void writeUnsupportedTypeThrows(`@TempDir` Path tempDir) {
...
-    assertThatThrownBy(() -> MDClassesJaxbWriter.writeObjectJaxb(Path.of("out.xml"), mdo))
+    Path out = tempDir.resolve("out.xml");
+    assertThatThrownBy(() -> MDClassesJaxbWriter.writeObjectJaxb(out, mdo))
       .isInstanceOf(IllegalArgumentException.class)
       .hasMessageContaining("does not support type");
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/test/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/DesignerJaxbWriterTest.java`
around lines 97 - 103, The test writeUnsupportedTypeThrows should avoid writing
to the process CWD; update the test to accept a JUnit `@TempDir` Path parameter
(e.g., Path tempDir) and replace the hardcoded Path.of("out.xml") when calling
MDClassesJaxbWriter.writeObjectJaxb with tempDir.resolve("out.xml") so the
attempted write/exception is scoped to the temporary directory while preserving
the assertThatThrownBy(...).isInstanceOf(IllegalArgumentException.class)
behavior.
src/main/xsd/v8.3.27/v8.1c.ru-8.2-managed-application-logform.xsd-1239-1258 (1)

1239-1258: ⚠️ Potential issue | 🟡 Minor

Add type declarations to untyped attributes in GanttChartFieldData.

Lines 1254-1257 define four attributes without type specifications:

  • valuesSelectionMode
  • intervalsSelectionMode
  • showHorizontalLinesFlag
  • showVerticalLinesFlag

Without explicit types, these default to xs:anySimpleType. Based on naming conventions elsewhere in this schema, consider adding types:

Suggested fix
-		<xs:attribute name="valuesSelectionMode"/>
-		<xs:attribute name="intervalsSelectionMode"/>
-		<xs:attribute name="showHorizontalLinesFlag"/>
-		<xs:attribute name="showVerticalLinesFlag"/>
+		<xs:attribute name="valuesSelectionMode" type="tns:GanttChartValuesSelectionMode"/>
+		<xs:attribute name="intervalsSelectionMode" type="tns:GanttChartIntervalsSelectionMode"/>
+		<xs:attribute name="showHorizontalLinesFlag" type="xs:boolean"/>
+		<xs:attribute name="showVerticalLinesFlag" type="xs:boolean"/>

If this matches the original 1C:Enterprise schema exactly, keep as-is for compatibility.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/xsd/v8.3.27/v8.1c.ru-8.2-managed-application-logform.xsd` around
lines 1239 - 1258, The four untyped attributes on the GanttChartFieldData
complexType need explicit types: update the attributes valuesSelectionMode and
intervalsSelectionMode to use the schema's selection-mode type (e.g.
tns:SelectionMode or the equivalent selection enum used elsewhere) and set
showHorizontalLinesFlag and showVerticalLinesFlag to xs:boolean; modify the
attributes named valuesSelectionMode, intervalsSelectionMode,
showHorizontalLinesFlag and showVerticalLinesFlag inside the GanttChartFieldData
complexType accordingly (or if a different specific enum type exists for
value/interval selection in this XSD, use that existing tns:... type).
🧹 Nitpick comments (21)
src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/SettingsStorageToJaxbConverter.java (1)

32-41: Add null validation for consistency.

Same recommendation: add null check for ss parameter.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/SettingsStorageToJaxbConverter.java`
around lines 32 - 41, The toMetaDataObject(SettingsStorage ss) method in
SettingsStorageToJaxbConverter lacks a null check for the ss parameter; add
validation at the start of the method to handle null input (e.g., throw
IllegalArgumentException or return a sensible default) so subsequent calls like
ss.getUuid() and buildProperties(ss) cannot NPE; update the method signature
body in SettingsStorageToJaxbConverter.toMetaDataObject to perform this null
check and document the behavior (exception type or return behavior) consistently
with other converters.
src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/LanguageToJaxbConverter.java (1)

32-40: Add null validation for language parameter.

Consistent with other converters, add a null guard.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/LanguageToJaxbConverter.java`
around lines 32 - 40, Add a null guard at the start of
LanguageToJaxbConverter.toMetaDataObject to validate the language parameter
(consistent with other converters); e.g., call Objects.requireNonNull(language,
"language") or throw an IllegalArgumentException when language is null, then
proceed with existing logic that creates MetaDataObject, sets version, creates
and populates the inner Language (inner.setUuid(...) and
inner.setProperties(...)), and returns root.
src/main/xsd/v8.5/v8.1c.ru-8.2-managed-application-modules.xsd (2)

71-71: Add trailing newline.

The file is missing a trailing newline at the end, which is a common convention for text files and helps with version control diffs.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/xsd/v8.5/v8.1c.ru-8.2-managed-application-modules.xsd` at line 71,
The file ends with the closing XML tag </xs:schema> but lacks a trailing
newline; open the file containing the </xs:schema> element and add a single
newline character after that closing tag so the file ends with a trailing
newline.

1-1: Remove UTF-8 BOM from XSD file.

The file starts with a UTF-8 BOM (). While technically valid, BOMs in XML can cause issues with some parsers and tools. Consider removing it for broader compatibility.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/xsd/v8.5/v8.1c.ru-8.2-managed-application-modules.xsd` at line 1,
Remove the leading UTF-8 BOM character from the top of the XSD so the file
begins directly with the XML declaration "<?xml version=\"1.0\"
encoding=\"UTF-8\"?>"; open the file
(v8.1c.ru-8.2-managed-application-modules.xsd), delete the invisible BOM
character preceding the XML declaration, save the file with UTF-8 encoding
without BOM to ensure parsers and tools don't choke on the hidden
byte-order-mark.
src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/JaxbWriteDefaults.java (1)

35-35: Consider consolidating duplicate DEFAULT_LANG constant.

DEFAULT_LANG = "ru" is also defined in JaxbWriteUtils (line 18). Consider extracting this to a single shared location to avoid duplication and ensure consistency if the default language ever changes.

♻️ Suggested approach

Either expose one constant publicly and reference it from the other class, or extract to a common constants class:

 public final class JaxbWriteDefaults {
   public static final String DEFAULT_FORMAT_VERSION = "2.20";
-  private static final String DEFAULT_LANG = "ru";
+  public static final String DEFAULT_LANG = "ru";

Then in JaxbWriteUtils:

-  private static final String DEFAULT_LANG = "ru";
+  // Use JaxbWriteDefaults.DEFAULT_LANG instead
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/JaxbWriteDefaults.java`
at line 35, There are duplicate DEFAULT_LANG = "ru" constants in
JaxbWriteDefaults (DEFAULT_LANG) and JaxbWriteUtils; consolidate by exposing one
shared constant and removing the other: either make DEFAULT_LANG public in one
class (e.g., JaxbWriteUtils.DEFAULT_LANG) and reference it from the other, or
create a new common constant holder (e.g., class
JaxbWriteConstants.DEFAULT_LANG) and update both JaxbWriteDefaults and
JaxbWriteUtils to use that single source of truth, then delete the duplicate
definition.
src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/ReportToJaxbConverter.java (2)

1-62: Consider extracting common converter logic.

This converter shares nearly identical structure with DataProcessorToJaxbConverter and likely other converters. While the current approach is acceptable, a future refactor could extract common patterns (null-safe UUID, properties building, form iteration) into a base helper to reduce boilerplate.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/ReportToJaxbConverter.java`
around lines 1 - 62, Extract shared conversion patterns into a reusable helper
or base class to reduce duplication between ReportToJaxbConverter and
DataProcessorToJaxbConverter: pull out null-safe UUID handling (used in
toMetaDataObject), local-string wrapping (JaxbWriteDefaults.localStringType +
JaxbWriteUtils.contentForLocalString used in buildProperties), null-safe
comment/name defaults, and collection-to-JAXB-list iteration (as in
buildChildObjects iterating r.getForms()). Create a small utility class (e.g.,
JaxbConverterUtils or an abstract BaseToJaxbConverter) with methods like
safeUuid(String), safeString(String), toLocalString(String), and
addCollectionItems(Collection, Consumer<String>) then update
ReportToJaxbConverter (toMetaDataObject, buildProperties, buildChildObjects) and
DataProcessorToJaxbConverter to delegate to these helpers.

34-43: Same null validation concern as DataProcessorToJaxbConverter.

Consider adding a null guard for the report parameter to fail fast with a clear message rather than NPE.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/ReportToJaxbConverter.java`
around lines 34 - 43, The toMetaDataObject(Report report) method lacks a null
guard for its report parameter, which can cause a generic NPE; add an explicit
null check at the start of toMetaDataObject and throw an
IllegalArgumentException (or NullPointerException with a clear message) when
report is null so callers fail fast with a descriptive error; update the method
that constructs the MetaDataObject and references to report.getUuid(),
buildProperties(report), and buildChildObjects(report) accordingly to rely on
the validated non-null report.
src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/DataProcessorToJaxbConverter.java (1)

34-43: Consider adding null check for input parameter.

The method doesn't validate that dp is non-null. A NullPointerException will occur at dp.getUuid() if null is passed. Consider adding an early guard or using @NonNull annotation per coding guidelines.

🛡️ Proposed fix
 public static MetaDataObject toMetaDataObject(DataProcessor dp) {
+  if (dp == null) {
+    throw new IllegalArgumentException("DataProcessor cannot be null");
+  }
   MetaDataObject root = FACTORY.createMetaDataObject();

Or use Objects.requireNonNull(dp, "DataProcessor cannot be null").

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/DataProcessorToJaxbConverter.java`
around lines 34 - 43, Add a null-check at the start of toMetaDataObject to
validate the DataProcessor argument (dp) before dereferencing it: ensure dp is
non-null (e.g., use Objects.requireNonNull(dp, "DataProcessor cannot be null")
or an explicit if (dp == null) throw/return) so calls like dp.getUuid(),
buildProperties(dp) and buildChildObjects(dp) don't cause a NPE; update
toMetaDataObject accordingly and keep existing behavior of creating
FACTORY.createMetaDataObject() and the inner DataProcessor population.
src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/BusinessProcessToJaxbConverter.java (1)

43-61: Consider importing JAXB types for consistency.

This converter uses fully qualified class names (com.github._1c_syntax.bsl.mdclasses.jaxb.mdclasses.BusinessProcessProperties, etc.) while other converters in this PR import these types. Using imports would improve readability and maintain consistency across the codebase.

♻️ Suggested imports
 import com.github._1c_syntax.bsl.mdo.BusinessProcess;
 import com.github._1c_syntax.bsl.mdo.children.ObjectForm;
+import com.github._1c_syntax.bsl.mdclasses.jaxb.mdclasses.BusinessProcessChildObjects;
+import com.github._1c_syntax.bsl.mdclasses.jaxb.mdclasses.BusinessProcessProperties;
 import com.github._1c_syntax.bsl.mdclasses.jaxb.mdclasses.MetaDataObject;
 import com.github._1c_syntax.bsl.mdclasses.jaxb.mdclasses.ObjectFactory;

Then simplify the method signatures:

-  private static com.github._1c_syntax.bsl.mdclasses.jaxb.mdclasses.BusinessProcessProperties buildProperties(BusinessProcess bp) {
-    com.github._1c_syntax.bsl.mdclasses.jaxb.mdclasses.BusinessProcessProperties p =
-      FACTORY.createBusinessProcessProperties();
+  private static BusinessProcessProperties buildProperties(BusinessProcess bp) {
+    BusinessProcessProperties p = FACTORY.createBusinessProcessProperties();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/BusinessProcessToJaxbConverter.java`
around lines 43 - 61, Replace the fully-qualified JAXB types with imports and
simplify the method signatures/locals: add imports for BusinessProcessProperties
and BusinessProcessChildObjects (and any other mdclasses types used), then
update buildProperties and buildChildObjects to return and declare variables
using the imported types (e.g., BusinessProcessProperties p =
FACTORY.createBusinessProcessProperties(); and BusinessProcessChildObjects
childObjects = FACTORY.createBusinessProcessChildObjects();), and also update
any other fully-qualified mdclasses usages in this file to the imported short
names to match other converters.
src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/ExchangePlanToJaxbConverter.java (1)

21-62: LGTM, but consider extracting shared conversion logic.

This converter (and 6+ others in this PR) repeats nearly identical patterns:

  • Root creation with version default
  • UUID null-to-empty fallback
  • Properties building (name, synonym via localStringType, comment null fallback)
  • ChildObjects forms iteration

A shared abstract base or helper class could reduce duplication and ensure consistent behavior. For example:

// Example helper in JaxbWriteUtils
public static void populateCommonProperties(
    Consumer<String> nameSetter,
    Consumer<LocalStringType> synonymSetter,
    Consumer<String> commentSetter,
    String name, LocalString synonym, String comment) {
  nameSetter.accept(name);
  synonymSetter.accept(JaxbWriteDefaults.localStringType(
      contentForLocalString(synonym)));
  commentSetter.accept(comment != null ? comment : "");
}

This is a recommended refactor that could be deferred if preferred.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/ExchangePlanToJaxbConverter.java`
around lines 21 - 62, The converter ExchangePlanToJaxbConverter duplicates
common JAXB conversion logic (root/version setup, UUID null->empty, properties
mapping, forms iteration); refactor by extracting shared helper(s) (e.g., in
JaxbWriteUtils) to centralize: a method to create/populate the MetaDataObject
root with version and setExchangePlan, a helper to map UUID with ep.getUuid() ->
"" fallback, and a populateCommonProperties helper to replace buildProperties
(handling name, synonym via
JaxbWriteDefaults.localStringType(JaxbWriteUtils.contentForLocalString(...)),
and comment null->""), plus a helper to append forms for buildChildObjects; then
update toMetaDataObject, buildProperties and buildChildObjects to call these
helpers so behavior is consistent across converters like
ExchangePlanToJaxbConverter.
src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/DesignerNamespacePrefixMapper.java (1)

20-26: Redundant ternary expression.

Line 25 suggestion != null ? suggestion : null always returns suggestion. Simplify:

♻️ Proposed fix
   `@Override`
   public String getPreferredPrefix(String namespaceUri, String suggestion, boolean requirePrefix) {
     if (MDCLASSES_NS.equals(namespaceUri)) {
       return requirePrefix ? "v8" : "";
     }
-    return suggestion != null ? suggestion : null;
+    return suggestion;
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/DesignerNamespacePrefixMapper.java`
around lines 20 - 26, In DesignerNamespacePrefixMapper's getPreferredPrefix
method the return expression "suggestion != null ? suggestion : null" is
redundant; simplify by returning suggestion directly. Update the method so that
when MDCLASSES_NS.equals(namespaceUri) it returns requirePrefix ? "v8" : "" and
otherwise return suggestion; keep use of MDCLASSES_NS and method name
getPreferredPrefix unchanged.
src/test/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/JaxbWriterExampleTest.java (1)

46-49: Consider cleaning up output directory before test run.

Without cleanup, stale files from previous runs may cause false positives. Add a @BeforeEach or cleanup in the test:

♻️ Proposed cleanup addition
import org.junit.jupiter.api.BeforeEach;
import org.apache.commons.io.FileUtils;

`@BeforeEach`
void setUp() throws Exception {
    if (Files.exists(OUTPUT_DIR)) {
        FileUtils.deleteDirectory(OUTPUT_DIR.toFile());
    }
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/test/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/JaxbWriterExampleTest.java`
around lines 46 - 49, Add a test cleanup that deletes the OUTPUT_DIR before each
run to avoid stale files affecting writeExampleToBuildDir; implement a
`@BeforeEach` method (e.g., setUp) that checks Files.exists(OUTPUT_DIR) and if
present uses FileUtils.deleteDirectory(OUTPUT_DIR.toFile()) (or equivalent safe
recursive delete) so MDClassesJaxbWriter.writeConfigurationToFolder and the test
method run against a clean directory.
build.gradle.kts (1)

105-122: Consider ensuring output directory exists before XJC runs.

The XJC task may fail on first run if build/generated/sources/xjc-mdclasses doesn't exist. Add directory creation in doFirst:

♻️ Proposed fix
 tasks.register<JavaExec>("xjcMDClasses") {
     group = "Build"
     description = "Generate JAXB classes from v8.5 MDClasses XSD"
     classpath = xjc
     mainClass = "com.sun.tools.xjc.Driver"
     workingDir = xsdV85Dir.asFile
     doFirst {
+        xjcOutputMDClasses.get().asFile.mkdirs()
         args(
             "-extension",
             "-catalog", "catalog.xml",
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@build.gradle.kts` around lines 105 - 122, The xjcMDClasses JavaExec task can
fail if the output directory referenced by xjcOutputMDClasses doesn't exist;
modify the task's doFirst block in the xjcMDClasses registration to create the
destination directory before invoking XJC (use xjcOutputMDClasses.get().asFile
or its absolutePath) so the directory exists, then proceed to set args and run;
ensure you call mkdirs() (or equivalent) on that File before setting args.
src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/InformationRegisterToJaxbConverter.java (1)

45-51: Converter appears incomplete — only basic properties mapped.

The buildProperties method only maps name, synonym, and comment. Information registers typically have many more properties (periodicity, write mode, dimensions, resources, etc.). If this is intentional for an MVP, consider adding a TODO comment.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/InformationRegisterToJaxbConverter.java`
around lines 45 - 51, The buildProperties method currently only maps name,
synonym and comment for InformationRegister -> InformationRegisterProperties;
update buildProperties (in InformationRegisterToJaxbConverter) to map the
remaining register properties (e.g., periodicity, writeMode, dimensions,
resources, accumulationType, owner, and any flags present on
InformationRegister) into the corresponding setters on
InformationRegisterProperties, or if this reduced mapping is intentional for an
MVP add a clear TODO comment inside buildProperties stating which fields are
intentionally omitted and referencing the missing property names so future work
can complete them. Ensure you reference the InformationRegister getters and the
InformationRegisterProperties setters when adding mappings or the TODO.
src/main/xsd/v8.3.27/v8.1c.ru-8.2-data-bsl.xsd (1)

1-2: Remove UTF-8 BOM character at file start.

The file begins with a UTF-8 BOM (), which may cause issues with some XML parsers or tooling. Consider saving without BOM.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/xsd/v8.3.27/v8.1c.ru-8.2-data-bsl.xsd` around lines 1 - 2, The file
begins with a UTF-8 BOM character before the XML declaration which can break XML
parsers; open the file that contains the XML declaration "<?xml version="1.0"
encoding="UTF-8"?>" and remove the leading BOM character so the file starts
exactly with the "<?xml" token (save the file without BOM / as UTF-8 without
signature).
src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/DesignerJaxbWriter.java (1)

54-88: Extract magic ClassId constants.

The hardcoded ClassId GUIDs (e.g., 9cd510cd-abfc-11d4-9434-004095e12fc7) are platform constants. Consider extracting them to named constants with documentation explaining their purpose for maintainability.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/DesignerJaxbWriter.java`
around lines 54 - 88, The hardcoded GUID strings inside
buildConfigurationInternalInfoBlock() should be extracted into well-named static
final constants (e.g., CLASS_ID_COMMONS, CLASS_ID_SOME_NAME) with a Javadoc
comment explaining each GUID's platform meaning; replace the literal GUID values
in the XML template with those constants (referencing
buildConfigurationInternalInfoBlock and the xr:ClassId occurrences) and keep the
UUID.randomUUID() objectId generation as-is—this improves maintainability and
documents the platform constants.
src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/DesignerPathResolver.java (1)

48-53: Path manipulation can be simplified using Path API.

The combination of FilenameUtils.getFullPathNoEndSeparator and FilenameUtils.getBaseName with Paths.get is verbose. The Path API can handle this more elegantly.

Simplified path resolution
     if (type == MDOType.SUBSYSTEM && parentSubsystemPath != null) {
-      Path parentDir = Paths.get(
-        FilenameUtils.getFullPathNoEndSeparator(parentSubsystemPath.toString()),
-        FilenameUtils.getBaseName(parentSubsystemPath.toString()));
+      // Parent directory + base name without extension
+      Path parentDir = parentSubsystemPath.resolveSibling(
+        parentSubsystemPath.getFileName().toString().replace(".xml", ""));
       return parentDir.resolve(type.groupName()).resolve(name + ".xml");
     }

Or even more robustly:

String baseName = parentSubsystemPath.getFileName().toString();
int dotIndex = baseName.lastIndexOf('.');
if (dotIndex > 0) {
  baseName = baseName.substring(0, dotIndex);
}
Path parentDir = parentSubsystemPath.resolveSibling(baseName);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/DesignerPathResolver.java`
around lines 48 - 53, In DesignerPathResolver where you handle MDOType.SUBSYSTEM
(the block referencing parentSubsystemPath, parentDir, FilenameUtils.*), replace
the FilenameUtils/Paths.get dance with pure Path API: obtain the file name via
parentSubsystemPath.getFileName().toString(), strip the extension by finding
lastIndexOf('.') (if present) to produce baseName, compute parentDir using
parentSubsystemPath.resolveSibling(baseName), then continue with
parentDir.resolve(type.groupName()).resolve(name + ".xml"); update the variables
type, parentSubsystemPath, parentDir, and name usage accordingly.
src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/CalculationRegisterToJaxbConverter.java (1)

75-83: Consider exporting additional child object types.

The buildChildObjects method currently only exports forms. CalculationRegisters may also have resources, dimensions, and recalculations that could need export. If this is intentional for the initial implementation scope, consider adding a TODO comment for future expansion.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/CalculationRegisterToJaxbConverter.java`
around lines 75 - 83, The buildChildObjects method currently only handles forms
(CalculationRegisterChildObjects co built from CalculationRegister.getForms());
update it to also export other child object types present on CalculationRegister
— e.g., iterate and add names from getResources(), getDimensions(), and
getRecalculations() into the appropriate lists on
CalculationRegisterChildObjects (using FACTORY as needed) or, if intentionally
omitted for now, add a clear TODO comment inside buildChildObjects referencing
the missing types (resources, dimensions, recalculations) so future maintainers
know to implement exporting for those collections.
src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/ConfigurationToJaxbConverter.java (1)

107-127: Fallback to values()[0] is fragile.

Using values()[0] as the default depends on enum declaration order, which could change. Consider using an explicit named constant for the default value.

♻️ Proposed fix using explicit defaults
   private static com.github._1c_syntax.bsl.mdclasses.jaxb.v8_3_xcf_enums.CompatibilityMode safeCompatibilityMode(String value) {
     if (value == null || value.isEmpty()) {
-      return com.github._1c_syntax.bsl.mdclasses.jaxb.v8_3_xcf_enums.CompatibilityMode.values()[0];
+      return com.github._1c_syntax.bsl.mdclasses.jaxb.v8_3_xcf_enums.CompatibilityMode.DONT_USE; // or appropriate default
     }
     try {
       return com.github._1c_syntax.bsl.mdclasses.jaxb.v8_3_xcf_enums.CompatibilityMode.fromValue(value);
     } catch (IllegalArgumentException e) {
-      return com.github._1c_syntax.bsl.mdclasses.jaxb.v8_3_xcf_enums.CompatibilityMode.values()[0];
+      return com.github._1c_syntax.bsl.mdclasses.jaxb.v8_3_xcf_enums.CompatibilityMode.DONT_USE;
     }
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/ConfigurationToJaxbConverter.java`
around lines 107 - 127, Replace the fragile values()[0] fallback in
safeCompatibilityMode and safeScriptVariant with an explicit, named default enum
constant (e.g.,
com.github._1c_syntax.bsl.mdclasses.jaxb.v8_3_xcf_enums.CompatibilityMode.DEFAULT
and
com.github._1c_syntax.bsl.mdclasses.jaxb.v8_3_xcf_enums.ScriptVariant.DEFAULT);
if such a constant doesn't exist in the enum definitions, add a clear default
constant to each enum and use that constant in both
safeCompatibilityMode(String) and safeScriptVariant(String) instead of
values()[0], keeping the current null/empty check and try/catch behavior.
src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/MDClassesJaxbWriter.java (2)

133-207: Annotate the public null contract.

configuration, options, and parentSubsystemPath are intentionally nullable here, but the signatures leave that implicit. Adding @NonNull/@Nullable would make the contract obvious to callers and tooling.

As per coding guidelines "Use @Nullable and @NonNull annotations from org.jspecify for null safety".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/MDClassesJaxbWriter.java`
around lines 133 - 207, Add org.jspecify nullability annotations to make
nullable/nonnull contracts explicit: mark parameters that may be null as
`@Nullable` (e.g., the Configuration parameter in writeObjectJaxb(Path, MD,
Configuration) and writeConfigurationToFolder(Path, Configuration,
WriteOptions), the options parameter in writeConfigurationToFolder, and
parentSubsystemPath in getPathForObject(Path, MD, Path)), and mark non-null
return values and non-null parameters as `@NonNull` where appropriate (e.g., Path
rootPath, MD md, Configuration in writeConfigurationJaxb). Import annotations
from org.jspecify.annotations and update the method signatures for
writeObjectJaxb, writeConfigurationJaxb, getPathForObject (both overloads) and
writeConfigurationToFolder to reflect these annotations consistently.

40-40: Refactor the writer API to be serializer-neutral.

MDClassesJaxbWriter, method names write*Jaxb, and the JAXBException checked exception expose the serialization implementation as part of the public contract. While the implementation is functional, the API design couples clients to JAXB. Consider creating a neutral facade (e.g., MDClassesWriter or ConfigurationWriter) with internal exception translation, keeping JAXB details in the .jaxb.write subpackage. This aligns with the codebase pattern where XStream is abstracted in reader implementations.

Also applies to: lines 55–55, 133–163

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/MDClassesJaxbWriter.java`
at line 40, MDClassesJaxbWriter and its write*Jaxb methods leak JAXB into the
public API (exposed via method names and the checked JAXBException); refactor by
introducing a serializer-neutral interface/class (suggest MDClassesWriter or
ConfigurationWriter) that declares generic write methods (e.g., write(MDClasses,
OutputStream) or write(Configuration, Writer)) and translate/wrap JAXBException
into an unchecked or domain-specific exception inside the .jaxb.write package;
move JAXB-specific implementation into the existing .jaxb.write subpackage (keep
MDClassesJaxbWriter as an internal adapter implementing the new interface) and
update callers to depend on the neutral MDClassesWriter contract rather than
JAXB types or write*Jaxb method names.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 7015a8be-3bd5-4849-b97d-0308c24e10c1

📥 Commits

Reviewing files that changed from the base of the PR and between 5c5b064 and 12aa02b.

📒 Files selected for processing (68)
  • build.gradle.kts
  • src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/AccountingRegisterToJaxbConverter.java
  • src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/AccumulationRegisterToJaxbConverter.java
  • src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/BusinessProcessToJaxbConverter.java
  • src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/CalculationRegisterToJaxbConverter.java
  • src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/CatalogToJaxbConverter.java
  • src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/ChartOfAccountsToJaxbConverter.java
  • src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/ChartOfCalculationTypesToJaxbConverter.java
  • src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/ChartOfCharacteristicTypesToJaxbConverter.java
  • src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/CommandGroupToJaxbConverter.java
  • src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/CommonModuleToJaxbConverter.java
  • src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/ConfigurationToJaxbConverter.java
  • src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/DataProcessorToJaxbConverter.java
  • src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/DesignerJaxbWriter.java
  • src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/DesignerNamespacePrefixMapper.java
  • src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/DesignerPathResolver.java
  • src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/DocumentJournalToJaxbConverter.java
  • src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/DocumentToJaxbConverter.java
  • src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/EnumToJaxbConverter.java
  • src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/ExchangePlanToJaxbConverter.java
  • src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/FilterCriterionToJaxbConverter.java
  • src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/FormToJaxbConverter.java
  • src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/InformationRegisterToJaxbConverter.java
  • src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/JaxbWriteDefaults.java
  • src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/JaxbWriteUtils.java
  • src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/LanguageToJaxbConverter.java
  • src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/MDClassesJaxbWriter.java
  • src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/ReportToJaxbConverter.java
  • src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/RoleToJaxbConverter.java
  • src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/SettingsStorageToJaxbConverter.java
  • src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/SubsystemToJaxbConverter.java
  • src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/TaskToJaxbConverter.java
  • src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/WriteOptions.java
  • src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/package-info.java
  • src/main/xsd/v8.3.27/catalog.xml
  • src/main/xsd/v8.3.27/v8.1c.ru-8.1-data-core.xsd
  • src/main/xsd/v8.3.27/v8.1c.ru-8.1-data-enterprise.xsd
  • src/main/xsd/v8.3.27/v8.1c.ru-8.1-data-ui.xsd
  • src/main/xsd/v8.3.27/v8.1c.ru-8.2-data-bsl.xsd
  • src/main/xsd/v8.3.27/v8.1c.ru-8.2-data-spreadsheet.xsd
  • src/main/xsd/v8.3.27/v8.1c.ru-8.2-managed-application-cmi.xsd
  • src/main/xsd/v8.3.27/v8.1c.ru-8.2-managed-application-core.xsd
  • src/main/xsd/v8.3.27/v8.1c.ru-8.2-managed-application-logform.xsd
  • src/main/xsd/v8.3.27/v8.1c.ru-8.2-managed-application-modules.xsd
  • src/main/xsd/v8.3.27/v8.1c.ru-8.2-uobjects.xsd
  • src/main/xsd/v8.3.27/v8.1c.ru-8.3-MDClasses.xsd
  • src/main/xsd/v8.3.27/v8.1c.ru-8.3-xcf-enums.xsd
  • src/main/xsd/v8.3.27/v8.1c.ru-8.3-xcf-predef.xsd
  • src/main/xsd/v8.3.27/v8.1c.ru-8.3-xcf-readable.xsd
  • src/main/xsd/v8.5/bindings.xjb
  • src/main/xsd/v8.5/catalog.xml
  • src/main/xsd/v8.5/v8.1c.ru-8.1-data-core.xsd
  • src/main/xsd/v8.5/v8.1c.ru-8.1-data-enterprise.xsd
  • src/main/xsd/v8.5/v8.1c.ru-8.1-data-ui.xsd
  • src/main/xsd/v8.5/v8.1c.ru-8.2-data-bsl.xsd
  • src/main/xsd/v8.5/v8.1c.ru-8.2-data-spreadsheet.xsd
  • src/main/xsd/v8.5/v8.1c.ru-8.2-managed-application-cmi.xsd
  • src/main/xsd/v8.5/v8.1c.ru-8.2-managed-application-core.xsd
  • src/main/xsd/v8.5/v8.1c.ru-8.2-managed-application-logform.xsd
  • src/main/xsd/v8.5/v8.1c.ru-8.2-managed-application-modules.xsd
  • src/main/xsd/v8.5/v8.1c.ru-8.2-uobjects.xsd
  • src/main/xsd/v8.5/v8.1c.ru-8.3-MDClasses.xsd
  • src/main/xsd/v8.5/v8.1c.ru-8.3-xcf-enums.xsd
  • src/main/xsd/v8.5/v8.1c.ru-8.3-xcf-predef.xsd
  • src/main/xsd/v8.5/v8.1c.ru-8.3-xcf-readable.xsd
  • src/test/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/DesignerJaxbWriterTest.java
  • src/test/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/DesignerPathResolverTest.java
  • src/test/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/JaxbWriterExampleTest.java

p.setUseStandardCommands(false);
p.setDefaultListForm("");
p.setAuxiliaryListForm("");
p.setRegisterType(JaxbWriteDefaults.accumulationRegisterTypeBalance());
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if AccumulationRegister has registerType property
rg -n "getRegisterType|registerType" --type java -g "**/mdo/AccumulationRegister.java"

Repository: 1c-syntax/mdclasses

Length of output: 45


🏁 Script executed:

#!/bin/bash
# First, let's find the AccumulationRegister class
find . -name "AccumulationRegister.java" -type f 2>/dev/null | head -20

Repository: 1c-syntax/mdclasses

Length of output: 134


🏁 Script executed:

#!/bin/bash
# List files in the mdo directory to understand structure
fd -t f "AccumulationRegister" | head -20

Repository: 1c-syntax/mdclasses

Length of output: 392


🏁 Script executed:

#!/bin/bash
# Check the converter file to see the current implementation
cat -n src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/AccumulationRegisterToJaxbConverter.java | head -80

Repository: 1c-syntax/mdclasses

Length of output: 4014


🏁 Script executed:

#!/bin/bash
# Check AccumulationRegister class for registerType property
cat -n src/main/java/com/github/_1c_syntax/bsl/mdo/AccumulationRegister.java | head -100

Repository: 1c-syntax/mdclasses

Length of output: 3865


🏁 Script executed:

#!/bin/bash
# Search for registerType in AccumulationRegister class
rg -n "registerType" src/main/java/com/github/_1c_syntax/bsl/mdo/AccumulationRegister.java

Repository: 1c-syntax/mdclasses

Length of output: 45


🏁 Script executed:

#!/bin/bash
# Continue reading AccumulationRegister to see all fields
cat -n src/main/java/com/github/_1c_syntax/bsl/mdo/AccumulationRegister.java | tail -n +100 | head -100

Repository: 1c-syntax/mdclasses

Length of output: 745


🏁 Script executed:

#!/bin/bash
# Check the Register interface
find . -name "Register.java" -type f 2>/dev/null | xargs cat -n | head -100

Repository: 1c-syntax/mdclasses

Length of output: 1830


🏁 Script executed:

#!/bin/bash
# Check if any other register types have registerType property
rg -n "registerType" --type java | head -30

Repository: 1c-syntax/mdclasses

Length of output: 45


🏁 Script executed:

#!/bin/bash
# Search for AccumulationRegisterType or similar enum
rg -n "registerType|RegisterType|Balance|Turnovers" --type java | grep -i "accumulation\|register.*type" | head -40

Repository: 1c-syntax/mdclasses

Length of output: 847


🏁 Script executed:

#!/bin/bash
# Check the test file to understand the expected behavior
cat src/test/java/com/github/_1c_syntax/bsl/mdo/AccumulationRegisterTest.java

Repository: 1c-syntax/mdclasses

Length of output: 2292


🏁 Script executed:

#!/bin/bash
# Check the JSON fixture file to see if registerType is in the source data
cat src/test/resources/fixtures/mdclasses/AccumulationRegisters.РегистрНакопления1.json | head -100

Repository: 1c-syntax/mdclasses

Length of output: 3464


🏁 Script executed:

#!/bin/bash
# Search for how AccumulationRegisterType enum is used elsewhere
rg -n "AccumulationRegisterType" --type java -A 3 -B 1

Repository: 1c-syntax/mdclasses

Length of output: 1794


🏁 Script executed:

#!/bin/bash
# Check if registerType is parsed from the 1C metadata files anywhere
rg -n "registerType" --type java -B 5 -A 5 | head -100

Repository: 1c-syntax/mdclasses

Length of output: 45


🏁 Script executed:

#!/bin/bash
# Look for AccumulationRegisterType enum values
find . -name "AccumulationRegisterType.java" -type f 2>/dev/null | xargs cat -n

Repository: 1c-syntax/mdclasses

Length of output: 45


🏁 Script executed:

#!/bin/bash
# Search for AccumulationRegisterType in all file types
find . -name "*AccumulationRegisterType*" -type f 2>/dev/null

Repository: 1c-syntax/mdclasses

Length of output: 45


🏁 Script executed:

#!/bin/bash
# Check what methods are available in AccumulationRegisterType enum
rg -n "BALANCE|TURNOVERS" --type java | head -20

Repository: 1c-syntax/mdclasses

Length of output: 534


🏁 Script executed:

#!/bin/bash
# Look at how Designer XML is parsed from the input side (read operations)
find . -name "*read*" -type d | head -10

Repository: 1c-syntax/mdclasses

Length of output: 160


🏁 Script executed:

#!/bin/bash
# Check the reader directory for AccumulationRegister parsing
find ./src/main/java/com/github/_1c_syntax/bsl/reader -name "*Accumulation*" -type f 2>/dev/null

Repository: 1c-syntax/mdclasses

Length of output: 45


🏁 Script executed:

#!/bin/bash
# Look at the write converters to understand the pattern - check other register converters
find ./src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write -name "*RegisterToJaxbConverter.java" -type f 2>/dev/null | head -10

Repository: 1c-syntax/mdclasses

Length of output: 474


🏁 Script executed:

#!/bin/bash
# Check what registerType value should be for different register types
rg -n "setRegisterType\|RegisterType" --type java src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/ -B 2 -A 2

Repository: 1c-syntax/mdclasses

Length of output: 45


🏁 Script executed:

#!/bin/bash
# Check InformationRegisterToJaxbConverter to understand the pattern
cat -n ./src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/InformationRegisterToJaxbConverter.java | head -80

Repository: 1c-syntax/mdclasses

Length of output: 2968


🏁 Script executed:

#!/bin/bash
# Check AccountingRegisterToJaxbConverter which might have registerType
cat -n ./src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/AccountingRegisterToJaxbConverter.java | grep -A 5 -B 5 "registerType\|RegisterType"

Repository: 1c-syntax/mdclasses

Length of output: 45


🏁 Script executed:

#!/bin/bash
# Check if there's a field or property related to register type in any 1C metadata format
rg -n "registerType\|RegisterType\|balance\|turnovers" --type java src/main/java/com/github/_1c_syntax/bsl/reader/ -B 2 -A 2 | head -60

Repository: 1c-syntax/mdclasses

Length of output: 45


🏁 Script executed:

#!/bin/bash
# Check the JAXB generated classes to see what AccumulationRegisterType values exist
find . -path "*/jaxb/v8_3_xcf_enums*" -name "AccumulationRegisterType*" -type f 2>/dev/null

Repository: 1c-syntax/mdclasses

Length of output: 45


🏁 Script executed:

#!/bin/bash
# Look for JAXB classes directory structure
find . -path "*/jaxb/*enums*" -type d 2>/dev/null | head -5

Repository: 1c-syntax/mdclasses

Length of output: 45


🏁 Script executed:

#!/bin/bash
# Check if there are any Designer XML examples or test files that show accumulation register structure
find . -path "*/test*" -name "*.xml" -type f 2>/dev/null | xargs grep -l "AccumulationRegister\|registerType\|balance\|turnovers" 2>/dev/null | head -10

Repository: 1c-syntax/mdclasses

Length of output: 922


🏁 Script executed:

#!/bin/bash
# Check the Designer XML files for registerType values
cat ./src/test/resources/ext/designer/mdclasses_3_25/src/cf/AccumulationRegisters/РегистрНакопления1.xml | grep -A 5 -B 5 "registerType\|RegisterType" | head -50

Repository: 1c-syntax/mdclasses

Length of output: 469


🏁 Script executed:

#!/bin/bash
# Check what's in the actual Designer XML accumulation register files
cat ./src/test/resources/ext/designer/mdclasses_3_25/src/cf/AccumulationRegisters/РегистрНакопления2.xml | head -100

Repository: 1c-syntax/mdclasses

Length of output: 4776


🏁 Script executed:

#!/bin/bash
# Check all accumulation register XML files for registerType
grep -n "registerType" ./src/test/resources/ext/designer/mdclasses_3_25/src/cf/AccumulationRegisters/*.xml

Repository: 1c-syntax/mdclasses

Length of output: 45


RegisterType hardcoding causes data loss during round-trip conversion.

The Designer XML format supports two accumulation register types: "Balance" (остатки) and "Turnovers" (обороты). The converter hardcodes accumulationRegisterTypeBalance() at line 54, ignoring the actual registerType value from source metadata. Test fixtures confirm both types exist (РегистрНакопления1.xml has "Balance", РегистрНакопления2.xml has "Turnovers"), but the AccumulationRegister model lacks a registerType field to preserve this information, making round-trip conversion lossy.

Add registerType field to AccumulationRegister and update the converter to use the actual value.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/AccumulationRegisterToJaxbConverter.java`
at line 54, The converter currently hardcodes
JaxbWriteDefaults.accumulationRegisterTypeBalance() in
AccumulationRegisterToJaxbConverter, causing loss of the original registerType;
add a registerType field (enum or String matching Designer values, e.g.,
"Balance"/"Turnovers") to the AccumulationRegister model with getter/setter,
populate it when parsing, and then change AccumulationRegisterToJaxbConverter to
call p.setRegisterType(accumulationRegister.getRegisterType()) (or map the enum
to the correct JAXB value) instead of using the hardcoded
JaxbWriteDefaults.accumulationRegisterTypeBalance(); ensure any constructors,
equals/hashCode/serialization logic and tests are updated to account for the new
field.

Comment on lines +64 to +75
public static MetaDataObject toMetaDataObject(Catalog catalog) {
return toMetaDataObject(catalog, null);
}

/**
* Собирает JAXB MetaDataObject из справочника mdclasses с указанием группы команд по умолчанию.
*
* @param catalog справочник из модели mdclasses
* @param defaultCommandGroupRef MDO-ссылка группы команд (например, "CommandGroup.ГруппаКоманд1") для команд без группы
* @return корневой элемент для маршаллинга в Designer XML
*/
public static MetaDataObject toMetaDataObject(Catalog catalog, String defaultCommandGroupRef) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Annotate public API nullability contract.

Public converter entrypoints should explicitly declare nullability for parameters.

Proposed fix
+import org.jspecify.annotations.NonNull;
+import org.jspecify.annotations.Nullable;
...
-  public static MetaDataObject toMetaDataObject(Catalog catalog) {
+  public static MetaDataObject toMetaDataObject(`@NonNull` Catalog catalog) {
     return toMetaDataObject(catalog, null);
   }
...
-  public static MetaDataObject toMetaDataObject(Catalog catalog, String defaultCommandGroupRef) {
+  public static MetaDataObject toMetaDataObject(
+    `@NonNull` Catalog catalog,
+    `@Nullable` String defaultCommandGroupRef
+  ) {

As per coding guidelines: "Use @Nullable and @NonNull annotations from org.jspecify for null safety".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/CatalogToJaxbConverter.java`
around lines 64 - 75, The public API lacks nullability annotations: annotate the
two converter entrypoints toMetaDataObject(Catalog) and
toMetaDataObject(Catalog, String defaultCommandGroupRef) using org.jspecify
annotations—mark the Catalog parameter as `@NonNull` (or `@Nullable` if null is
acceptable) and the defaultCommandGroupRef parameter as `@Nullable`, and annotate
the return type appropriately (`@NonNull` or `@Nullable`); add the corresponding
import for org.jspecify.annotations.Nullable/@NonNull at the top of
CatalogToJaxbConverter.java and adjust any callers/tests if their nullability
expectations change.

Comment on lines +86 to +148
private static CatalogProperties buildProperties(Catalog c) {
CatalogProperties p = FACTORY.createCatalogProperties();
p.setName(c.getName());
p.setSynonym(JaxbWriteDefaults.localStringType(JaxbWriteUtils.contentForLocalString(c.getSynonym())));
p.setComment(c.getComment() != null ? c.getComment() : "");
p.setObjectBelonging(JaxbWriteDefaults.objectBelongingNative());
p.setHierarchical(false);
p.setHierarchyType(HierarchyType.HIERARCHY_FOLDERS_AND_ITEMS);
p.setLimitLevelCount(false);
p.setLevelCount(BigDecimal.ONE);
p.setFoldersOnTop(true);
p.setUseStandardCommands(true);
p.setOwners(buildOwners(c));
p.setSubordinationUse(SubordinationUse.TO_FOLDERS_AND_ITEMS);
p.setCodeLength(BigDecimal.valueOf(9));
p.setDescriptionLength(BigDecimal.valueOf(150));
p.setCodeType(CatalogCodeType.STRING);
p.setCodeAllowedLength(AllowedLength.VARIABLE);
p.setCodeSeries(codeSeriesToJaxb(c.getCodeSeries()));
p.setCheckUnique(c.isCheckUnique());
p.setAutonumbering(false);
p.setDefaultPresentation(CatalogMainPresentation.AS_DESCRIPTION);
p.setStandardAttributes(JaxbWriteDefaults.emptyStandardAttributeDescriptions());
p.setCharacteristics(JaxbWriteDefaults.emptyCharacteristicsDescriptions());
p.setPredefined("");
p.setPredefinedDataUpdate(PredefinedDataUpdate.DONT_AUTO_UPDATE);
p.setEditType(EditType.IN_LIST);
p.setQuickChoice(false);
p.setChoiceMode(JaxbWriteDefaults.choiceModeFromForm());
p.setInputByString(JaxbWriteDefaults.emptyFieldList());
p.setSearchStringModeOnInputByString(SearchStringModeOnInputByString.ANY_PART);
p.setFullTextSearchOnInputByString(FullTextSearchOnInputByString.USE);
p.setChoiceDataGetModeOnInputByString(ChoiceDataGetModeOnInputByString.DIRECTLY);
p.setDefaultObjectForm(EMPTY_REF);
p.setDefaultFolderForm(EMPTY_REF);
p.setDefaultListForm(EMPTY_REF);
p.setDefaultChoiceForm(EMPTY_REF);
p.setDefaultFolderChoiceForm(EMPTY_REF);
p.setAuxiliaryObjectForm(EMPTY_REF);
p.setAuxiliaryFolderForm(EMPTY_REF);
p.setAuxiliaryListForm(EMPTY_REF);
p.setAuxiliaryChoiceForm(EMPTY_REF);
p.setAuxiliaryFolderChoiceForm(EMPTY_REF);
p.setObjectModule(EMPTY_REF);
p.setManagerModule(EMPTY_REF);
p.setIncludeHelpInContents(false);
p.setHelp(EMPTY_REF);
p.setBasedOn(JaxbWriteDefaults.emptyMDListType());
p.setDataLockFields(JaxbWriteDefaults.emptyFieldList());
p.setDataLockControlMode(JaxbWriteDefaults.defaultDataLockControlModeAutomatic());
p.setFullTextSearch(JaxbWriteDefaults.fullTextSearchDontUse());
p.setObjectPresentation(JaxbWriteDefaults.localStringType(""));
p.setExtendedObjectPresentation(JaxbWriteDefaults.localStringType(""));
p.setListPresentation(JaxbWriteDefaults.localStringType(""));
p.setExtendedListPresentation(JaxbWriteDefaults.localStringType(""));
p.setExplanation(JaxbWriteDefaults.localStringType(JaxbWriteUtils.contentForLocalString(c.getExplanation())));
p.setCreateOnInput(CreateOnInput.DONT_USE);
p.setChoiceHistoryOnInput(JaxbWriteDefaults.choiceHistoryOnInputAuto());
p.setDataHistory(DataHistoryUse.DONT_USE);
p.setUpdateDataHistoryImmediatelyAfterWrite(false);
p.setExecuteAfterWriteDataHistoryVersionProcessing(false);
p.setAdditionalIndexes(EMPTY_REF);
return p;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 1) Locate Catalog model class and list available getters.
CATALOG_FILE="$(fd 'Catalog.java' src/main/java | head -n1)"
echo "Catalog file: ${CATALOG_FILE}"
rg -nP '\b(public|protected)\s+[A-Za-z0-9_<>, ?]+\s+(get|is)[A-Z][A-Za-z0-9_]*\s*\(' "${CATALOG_FILE}"

# 2) List all property assignments currently hardcoded in converter.
rg -nP 'p\.set[A-Z][A-Za-z0-9_]*\(' src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/CatalogToJaxbConverter.java

Repository: 1c-syntax/mdclasses

Length of output: 133


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Check the size of Catalog.java first
wc -l src/main/java/com/github/_1c_syntax/bsl/mdo/Catalog.java

# Get first part of file to understand structure
head -100 src/main/java/com/github/_1c_syntax/bsl/mdo/Catalog.java

Repository: 1c-syntax/mdclasses

Length of output: 3303


🏁 Script executed:

#!/bin/bash
# Search for public getters/isters in Catalog.java with simpler pattern
rg -n 'public.*\(get|is\)[A-Z]' src/main/java/com/github/_1c_syntax/bsl/mdo/Catalog.java | head -50

Repository: 1c-syntax/mdclasses

Length of output: 45


🏁 Script executed:

#!/bin/bash
# Extract all p.set* calls from the converter to list what's being hardcoded
rg 'p\.set[A-Z]' src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/CatalogToJaxbConverter.java | sed -n '86,148p'

Repository: 1c-syntax/mdclasses

Length of output: 45


🏁 Script executed:

#!/bin/bash
# Read the converter file to see the buildProperties method
cat -n src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/CatalogToJaxbConverter.java | sed -n '86,148p'

Repository: 1c-syntax/mdclasses

Length of output: 3867


🏁 Script executed:

#!/bin/bash
# Read complete Catalog.java to see all fields
cat -n src/main/java/com/github/_1c_syntax/bsl/mdo/Catalog.java

Repository: 1c-syntax/mdclasses

Length of output: 6640


Use the Catalog.objectBelonging field instead of hardcoding to objectBelongingNative().

Line 91 sets p.setObjectBelonging(JaxbWriteDefaults.objectBelongingNative()) as a hardcoded default. The Catalog model has an objectBelonging field (defined with @Default ObjectBelonging objectBelonging = ObjectBelonging.OWN), so the current code drops user-provided values during serialization. This should be changed to p.setObjectBelonging(JaxbWriteDefaults.objectBelongingToJaxb(c.getObjectBelonging())) or equivalent to preserve the model's state.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/CatalogToJaxbConverter.java`
around lines 86 - 148, The buildProperties method in CatalogToJaxbConverter
currently hardcodes object belonging via
p.setObjectBelonging(JaxbWriteDefaults.objectBelongingNative()), which discards
the Catalog.model value; change this to use the Catalog instance: call
p.setObjectBelonging(JaxbWriteDefaults.objectBelongingToJaxb(c.getObjectBelonging()))
(or the equivalent helper that converts Catalog.getObjectBelonging()) so the
Catalog.objectBelonging field is preserved during conversion.

Comment on lines +210 to +217
private static void addAttributes(CatalogChildObjects co, Catalog c) {
if (c.getAttributes() == null) {
return;
}
for (Attribute attr : c.getAttributes()) {
if (attr.getName() == null || STANDARD_CATALOG_ATTRIBUTE_NAMES.contains(attr.getName())) {
continue;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Skip blank attribute names before writing attributes.

Line 215 checks only null; "" still passes and produces unnamed metadata attributes.

Proposed fix
-      if (attr.getName() == null || STANDARD_CATALOG_ATTRIBUTE_NAMES.contains(attr.getName())) {
+      if (attr.getName() == null || attr.getName().isBlank()
+        || STANDARD_CATALOG_ATTRIBUTE_NAMES.contains(attr.getName())) {
         continue;
       }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
private static void addAttributes(CatalogChildObjects co, Catalog c) {
if (c.getAttributes() == null) {
return;
}
for (Attribute attr : c.getAttributes()) {
if (attr.getName() == null || STANDARD_CATALOG_ATTRIBUTE_NAMES.contains(attr.getName())) {
continue;
}
private static void addAttributes(CatalogChildObjects co, Catalog c) {
if (c.getAttributes() == null) {
return;
}
for (Attribute attr : c.getAttributes()) {
if (attr.getName() == null || attr.getName().isBlank()
|| STANDARD_CATALOG_ATTRIBUTE_NAMES.contains(attr.getName())) {
continue;
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/CatalogToJaxbConverter.java`
around lines 210 - 217, The addAttributes method is allowing empty-string names
because it only checks attr.getName() == null; update the guard in addAttributes
(working on CatalogChildObjects, Catalog, Attribute) to skip attributes whose
name is null or blank (e.g., trim and check isEmpty()) in addition to filtering
STANDARD_CATALOG_ATTRIBUTE_NAMES so unnamed/whitespace-only Attribute instances
are not written.

Comment on lines +164 to +187
private static String makeMDClassesDefaultNamespace(String xml) {
xml = xml.replace("xmlns=\"" + NS_XCF_READABLE + "\"", "xmlns:xr=\"" + NS_XCF_READABLE + "\"");
xml = xml.replace("xmlns:ns2=\"" + NS_MDCLASSES + "\"", "xmlns=\"" + NS_MDCLASSES + "\"");
xml = xml.replace("<ns2:", "<");
xml = xml.replace("</ns2:", "</");
// Как в фикстурах: у Configuration только uuid, без formatVersion
xml = xml.replace(" formatVersion=\"2.20\"", "");
// Configuration: InternalInfo с ContainedObject (как в фикстурах платформы)
xml = xml.replaceFirst(
"(<Configuration uuid=\"[^\"]+\">)\\s*\\n\\s*<Properties>",
"$1\n " + buildConfigurationInternalInfoBlock() + "\n <Properties>");
// Catalog: InternalInfo с GeneratedType (Object, Ref, Selection, List, Manager)
xml = xml.replaceFirst(
"(<Catalog uuid=\"[^\"]+\">)\\s*\\n\\s*<Properties>",
"$1\n " + buildCatalogInternalInfoBlock() + "\n <Properties>");
// Подставить имя справочника из первого тега <Name>
if (xml.contains(CATALOG_NAME_PLACEHOLDER)) {
Matcher m = NAME_TAG.matcher(xml);
if (m.find()) {
xml = xml.replace(CATALOG_NAME_PLACEHOLDER, m.group(1));
}
}
return xml;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

String-based XML post-processing is fragile.

The namespace and InternalInfo injection relies on specific XML formatting (whitespace patterns like ">\\s*\\n\\s*<Properties>"). If the JAXB marshaller changes its output formatting, or if properties are reordered, these replacements will silently fail or produce malformed XML.

Consider using a proper XML transformation approach (DOM/SAX post-processing or XSLT) for more robust manipulation.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/DesignerJaxbWriter.java`
around lines 164 - 187, The current makeMDClassesDefaultNamespace method
performs fragile string-based XML edits (namespace swaps, removing
formatVersion, and injecting InternalInfo blocks via regex/replaceFirst) which
break if JAXB formatting changes; replace this logic by parsing the XML into a
DOM (or using StAX/XSLT), programmatically rename/attach namespaces and
elements, remove the formatVersion attribute via the DOM API, and insert the
nodes produced by buildConfigurationInternalInfoBlock() and
buildCatalogInternalInfoBlock() as actual XML Elements into Configuration and
Catalog elements; also locate the first <Name> element via the DOM and replace
CATALOG_NAME_PLACEHOLDER with its text content instead of using NAME_TAG regex,
ensuring all changes are done with proper namespace-aware APIs in
makeMDClassesDefaultNamespace.

Comment on lines +602 to +680
<xs:complexType name="SpreadsheetDocument">
<xs:choice>
<xs:element name="distributedKey" type="xs:string" minOccurs="0"/>
<xs:element name="languageSettings" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:element name="currentLanguage" type="xs:string"/>
<xs:element name="defaultLanguage" type="xs:string"/>
<xs:element name="languageInfo" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="id" type="xs:string"/>
<xs:element name="code" type="xs:string"/>
<xs:element name="description" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="languageCode" type="xs:string" minOccurs="0"/>
<xs:element name="columns" type="tns:Columns" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="rowsItem" type="tns:RowsItem" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="drawing" type="tns:Drawing" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="backPicture" minOccurs="0"/>
<xs:element name="fixedBackground" type="xs:boolean" minOccurs="0"/>
<xs:element name="leftHeader" type="tns:Cell" minOccurs="0"/>
<xs:element name="centerHeader" type="tns:Cell" minOccurs="0"/>
<xs:element name="rightHeader" type="tns:Cell" minOccurs="0"/>
<xs:element name="leftFooter" type="tns:Cell" minOccurs="0"/>
<xs:element name="centerFooter" type="tns:Cell" minOccurs="0"/>
<xs:element name="rightFooter" type="tns:Cell" minOccurs="0"/>
<xs:element name="templateMode" type="xs:boolean" minOccurs="0"/>
<xs:element name="stepDirection" type="tns:SpreadsheetDocumentStepDirectionType" minOccurs="0"/>
<xs:element name="totalsRight" type="xs:boolean" minOccurs="0"/>
<xs:element name="totalsBelow" type="xs:boolean" minOccurs="0"/>
<xs:element name="defaultFormatIndex" type="xs:decimal" minOccurs="0"/>
<xs:element name="height" type="xs:decimal" minOccurs="0"/>
<xs:element name="vgLevels" type="xs:decimal" minOccurs="0"/>
<xs:element name="vgRows" type="xs:decimal" minOccurs="0"/>
<xs:element name="vg" type="tns:Group" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="hg" type="tns:Group" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="verticalPageBreak" type="tns:PageBreak" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="horizontalPageBreak" type="tns:PageBreak" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="merge" type="tns:Merge" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="verticalUnmerge" type="tns:Merge" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="horizontalUnmerge" type="tns:Merge" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="namedItem" type="tns:NamedItem" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="printSettingsName" type="xs:string" minOccurs="0"/>
<xs:element name="printSettings" type="tns:PrintSettings" minOccurs="0"/>
<xs:element name="printArea" type="tns:Area" minOccurs="0"/>
<xs:element name="repeatRows" type="tns:Area" minOccurs="0"/>
<xs:element name="repeatColumns" type="tns:Area" minOccurs="0"/>
<xs:element name="drawingDataSource" type="tns:DrawingsDataSource" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="groupsBackColor" type="ns2:Color" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="groupsColor" type="ns2:Color" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="headersBackColor" type="ns2:Color" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="headersColor" type="ns2:Color" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="saveViewSettings" type="xs:boolean" minOccurs="0"/>
<xs:element name="viewSettings" type="tns:ViewSettings" minOccurs="0"/>
<xs:element name="embeddedTable" type="tns:EmbeddedTableItem" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="line" type="ns2:Line" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="font" type="ns2:Font" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="format" type="tns:Format" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="picture" type="tns:Picture" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="usedFileName" type="xs:string" minOccurs="0"/>
<xs:element name="output" type="ns2:UseOutput" minOccurs="0"/>
<xs:element name="nextInsertionRow" type="xs:decimal" minOccurs="0"/>
<xs:element name="nextInsertionCol" type="xs:decimal" minOccurs="0"/>
<xs:element name="readOnly" type="xs:boolean" minOccurs="0"/>
<xs:element name="protection" type="xs:boolean" minOccurs="0"/>
<xs:element name="baseSheet" type="tns:SpreadsheetDocument" minOccurs="0"/>
<xs:element name="extensionMethod" type="tns:SpreadsheetDocumentExtensionAlgorithm" minOccurs="0"/>
<xs:element name="isCompactMode" type="xs:boolean" minOccurs="0"/>
<xs:element name="originalSheet" type="tns:SpreadsheetDocument" minOccurs="0"/>
<xs:element name="textDirection" type="ns2:TextDirection" minOccurs="0"/>
<xs:element name="savedPicturesDensity" type="tns:SpreadsheetDocumentSavedPicturesDensity" minOccurs="0"/>
</xs:choice>
</xs:complexType>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
python - <<'PY'
import xml.etree.ElementTree as ET
from pathlib import Path

ns = {'xs': 'http://www.w3.org/2001/XMLSchema'}

for path in [
    Path('src/main/xsd/v8.5/v8.1c.ru-8.2-data-spreadsheet.xsd'),
    Path('src/main/xsd/v8.3.27/v8.1c.ru-8.2-data-spreadsheet.xsd'),
]:
    root = ET.parse(path).getroot()
    ct = next(
        ct for ct in root.findall('xs:complexType', ns)
        if ct.get('name') == 'SpreadsheetDocument'
    )
    choice = ct.find('xs:choice', ns)
    children = [el.get('name') for el in choice.findall('xs:element', ns)]
    print(path)
    print('  choice.maxOccurs =', repr(choice.get('maxOccurs')))
    print('  child_count =', len(children))
    print('  sample_children =', children[:10])
PY

Repository: 1c-syntax/mdclasses

Length of output: 605


Fix the SpreadsheetDocument content model to allow multiple sections.

The xs:choice compositor at lines 605–679 has an implicit maxOccurs="1" constraint, meaning a SpreadsheetDocument can contain only one of: columns, rowsItem, format, drawing, etc., but not a combination. This makes any spreadsheet requiring both layout (columns) and content (rows) invalid against the schema. Either change the compositor to xs:sequence or xs:all, or set maxOccurs="unbounded" on the choice to allow repeated mixed sections.

The identical issue exists in the mirrored src/main/xsd/v8.3.27/v8.1c.ru-8.2-data-spreadsheet.xsd file; both versions should be updated together.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/xsd/v8.5/v8.1c.ru-8.2-data-spreadsheet.xsd` around lines 602 - 680,
The SpreadsheetDocument complexType uses an xs:choice with its implicit
maxOccurs="1", preventing multiple child sections; update the compositor in the
SpreadsheetDocument definition (the xs:choice surrounding elements like columns,
rowsItem, drawing, format, etc.) to allow multiple mixed children—either replace
xs:choice with xs:sequence or add maxOccurs="unbounded" to xs:choice so the
document can contain multiple sections; apply the same edit to the mirrored
SpreadsheetDocument definition in the other XSD (v8.3.27) as well.

Comment on lines +105 to +116
<xs:complexType name="CommansShortCutInfo">
<xs:sequence>
<xs:element name="shortCut" type="ns2:ShortCutType"/>
<xs:element name="fragments" type="tns:SubsystemAndPanel" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="commandId" type="ns1:CompositeID"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="CommansShortCutInfoVector">
<xs:sequence>
<xs:element name="info" type="tns:CommansShortCutInfo" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

1C v8.2 managed application CMI schema CommansShortCutInfo

💡 Result:

In 1C:Enterprise 8.2 managed applications, CMI refers to the Command Interface Model (com._1c.g5.v8.dt.cmi.model package in 1C EDT), an EMF-based schema used in the development tools (EDT) for modeling the command interface. This includes classes like CommandInterface, CommandsVisibility, CommandsOrder, etc., which define the structure, visibility, order, and placement of commands in the UI. No exact class or element named "CommansShortCutInfo" (likely a misspelling of "CommandsShortCutInfo") exists in the CMI schema. However, command information in related form layout models includes a "shortCut" field of type String, as seen in ICommandsManagerInfo.CommandInfo. This field stores the keyboard shortcut representation for commands (e.g., "Ctrl+Shift+F1"). The command interface supports keyboard shortcuts via command properties, but shortcuts are not a dedicated CMI schema element. They are part of command metadata and runtime info for managed forms. Official docs describe command interface structure via subsystems, command groups, and properties like visibility and order, with no specific "CommansShortCutInfo" structure identified.

Citations:


🏁 Script executed:

# First, check if the file exists and read its contents
cat -n src/main/xsd/v8.5/v8.1c.ru-8.2-managed-application-cmi.xsd | head -120 | tail -30

Repository: 1c-syntax/mdclasses

Length of output: 1512


🏁 Script executed:

# Also get the full context around lines 105-116 and check for any comments
wc -l src/main/xsd/v8.5/v8.1c.ru-8.2-managed-application-cmi.xsd

Repository: 1c-syntax/mdclasses

Length of output: 125


🏁 Script executed:

# Search for other occurrences of "Commans" in the codebase
rg "Commans" --type xml

Repository: 1c-syntax/mdclasses

Length of output: 1168


🏁 Script executed:

# Check the XSD file header for any notes about source or origin
head -50 src/main/xsd/v8.5/v8.1c.ru-8.2-managed-application-cmi.xsd

Repository: 1c-syntax/mdclasses

Length of output: 2861


Correct the typo in type names from "Commans" to "Commands".

The type names CommansShortCutInfo and CommansShortCutInfoVector contain a typo. The official 1C CMI schema documentation does not reference a "CommansShortCutInfo" type; no such element exists in the official platform schema. This appears to be an unintentional mistake rather than a preserved compatibility issue. Correct these to CommandsShortCutInfo and CommandsShortCutInfoVector to match the intended naming pattern and official conventions.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/xsd/v8.5/v8.1c.ru-8.2-managed-application-cmi.xsd` around lines 105
- 116, Rename the misspelled complexType names and any references from
CommansShortCutInfo to CommandsShortCutInfo and from CommansShortCutInfoVector
to CommandsShortCutInfoVector; update the type attributes on the <xs:complexType
name="CommansShortCutInfo"> and <xs:complexType
name="CommansShortCutInfoVector"> declarations and update any element/type
references such as type="tns:CommansShortCutInfo" to use the corrected
identifiers so all definitions and usages (e.g., the <xs:element name="info"
type="tns:CommansShortCutInfo" .../>) remain consistent.

Comment on lines +126 to +136
<xs:complexType name="CollectionOperations">
<xs:choice>
<xs:element name="add" type="tns:CollectionOperationAdd" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="addRange" type="tns:CollectionOperationAddRange" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="remove" type="tns:CollectionOperationRemove" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="removeRange" type="tns:CollectionOperationRemoveRange" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="swap" type="tns:CollectionOperationSwap" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="move" type="tns:CollectionOperationMove" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="clear" type="tns:CollectionOperationClear" minOccurs="0" maxOccurs="unbounded"/>
</xs:choice>
</xs:complexType>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
python - <<'PY'
import xml.etree.ElementTree as ET
from pathlib import Path

ns = {'xs': 'http://www.w3.org/2001/XMLSchema'}
targets = ('CollectionOperations', 'TreeOperations')

for path in [
    Path('src/main/xsd/v8.5/v8.1c.ru-8.2-uobjects.xsd'),
    Path('src/main/xsd/v8.3.27/v8.1c.ru-8.2-uobjects.xsd'),
]:
    root = ET.parse(path).getroot()
    print(path)
    for name in targets:
        ct = next(
            ct for ct in root.findall('xs:complexType', ns)
            if ct.get('name') == name
        )
        choice = ct.find('xs:choice', ns)
        children = [el.get('name') for el in choice.findall('xs:element', ns)]
        print(f'  {name}: choice.maxOccurs={choice.get("maxOccurs")!r}, children={children}')
PY

Repository: 1c-syntax/mdclasses

Length of output: 645


Fix non-repeating xs:choice in operation content models.

The xs:choice elements in CollectionOperations (lines 126–136) and TreeOperations (lines 360–370) have no maxOccurs attribute, defaulting to 1. This permits only a single operation per block. If mixed operations like add + move are valid, add maxOccurs="unbounded" to allow repeating choices. The same issue exists in the mirrored file src/main/xsd/v8.3.27/v8.1c.ru-8.2-uobjects.xsd and both versions must stay aligned.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/xsd/v8.5/v8.1c.ru-8.2-uobjects.xsd` around lines 126 - 136, The
xs:choice in the CollectionOperations and TreeOperations complexTypes currently
lacks maxOccurs, restricting the block to a single operation; update the
xs:choice element inside the CollectionOperations and the xs:choice inside
TreeOperations to include maxOccurs="unbounded" so multiple operation elements
(e.g., add + move) can appear, and mirror the same change in the corresponding
file under v8.3.27 to keep both versions aligned; locate the choice nodes by the
complexType names CollectionOperations and TreeOperations and add the maxOccurs
attribute to each xs:choice.

Comment on lines +259 to +262
<xs:complexType name="ValueList">
<xs:sequence>
<xs:element name="Item" type="tns:ValueListItem"/>
</xs:sequence>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

ValueList currently allows only one item.

Line 261 should allow repeated Item entries; otherwise list serialization is artificially capped at one value.

Proposed fix
 <xs:complexType name="ValueList">
 	<xs:sequence>
-		<xs:element name="Item" type="tns:ValueListItem"/>
+		<xs:element name="Item" type="tns:ValueListItem" minOccurs="0" maxOccurs="unbounded"/>
 	</xs:sequence>
 </xs:complexType>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<xs:complexType name="ValueList">
<xs:sequence>
<xs:element name="Item" type="tns:ValueListItem"/>
</xs:sequence>
<xs:complexType name="ValueList">
<xs:sequence>
<xs:element name="Item" type="tns:ValueListItem" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/xsd/v8.5/v8.1c.ru-8.3-xcf-readable.xsd` around lines 259 - 262, The
ValueList complexType currently defines a single xs:element name="Item"
(type="tns:ValueListItem") so lists are capped at one; update the Item element
declaration inside the ValueList xs:sequence to allow multiple entries (e.g.,
set maxOccurs="unbounded" and adjust minOccurs if needed) so ValueList can
contain repeated Item elements, ensuring to modify the xs:element with name
"Item" in the ValueList complexType.

Comment on lines +51 to +63
Path configPath = OUTPUT_DIR.resolve("Configuration.xml");
assert Files.exists(configPath) : "Configuration.xml";
assert Files.exists(OUTPUT_DIR.resolve("Languages").resolve("Русский.xml")) : "Languages/Русский.xml";
assert Files.exists(OUTPUT_DIR.resolve("Subsystems").resolve("ПерваяПодсистема.xml")) : "Subsystems/ПерваяПодсистема.xml";
assert Files.exists(OUTPUT_DIR.resolve("Subsystems").resolve("ВтораяПодсистема.xml")) : "Subsystems/ВтораяПодсистема.xml";
Path nestedSub = OUTPUT_DIR.resolve("Subsystems").resolve("ПерваяПодсистема").resolve("Subsystems").resolve("ПодчиненнаяПодсистема.xml");
assert Files.exists(nestedSub) : "Subsystems/ПерваяПодсистема/Subsystems/ПодчиненнаяПодсистема.xml";
assert Files.exists(OUTPUT_DIR.resolve("Catalogs").resolve("Справочник1.xml")) : "Catalogs/Справочник1.xml";
Path formsDir = OUTPUT_DIR.resolve("Catalogs").resolve("Справочник1").resolve("Forms");
assert Files.exists(formsDir.resolve("ФормаЭлемента.xml")) : "Catalogs/Справочник1/Forms/ФормаЭлемента.xml";
assert Files.exists(formsDir.resolve("ФормаСписка.xml")) : "Catalogs/Справочник1/Forms/ФормаСписка.xml";
assert Files.exists(formsDir.resolve("ФормаВыбора.xml")) : "Catalogs/Справочник1/Forms/ФормаВыбора.xml";
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Use AssertJ assertions instead of raw assert statements.

Raw Java assert statements are disabled by default at runtime and don't provide the fluent API or detailed failure messages that AssertJ offers. As per coding guidelines: "Use JUnit 5 for testing with AssertJ for fluent assertions."

♻️ Proposed fix using AssertJ
+import static org.assertj.core.api.Assertions.assertThat;
+
 `@Test`
 void writeExampleToBuildDir() throws Exception {
     Configuration cf = (Configuration) MDClasses.createConfiguration(DESIGNER_CF, MDCReadSettings.DEFAULT);
     MDClassesJaxbWriter.writeConfigurationToFolder(OUTPUT_DIR, cf);

     Path configPath = OUTPUT_DIR.resolve("Configuration.xml");
-    assert Files.exists(configPath) : "Configuration.xml";
-    assert Files.exists(OUTPUT_DIR.resolve("Languages").resolve("Русский.xml")) : "Languages/Русский.xml";
-    assert Files.exists(OUTPUT_DIR.resolve("Subsystems").resolve("ПерваяПодсистема.xml")) : "Subsystems/ПерваяПодсистема.xml";
-    assert Files.exists(OUTPUT_DIR.resolve("Subsystems").resolve("ВтораяПодсистема.xml")) : "Subsystems/ВтораяПодсистема.xml";
+    assertThat(configPath).exists();
+    assertThat(OUTPUT_DIR.resolve("Languages").resolve("Русский.xml")).exists();
+    assertThat(OUTPUT_DIR.resolve("Subsystems").resolve("ПерваяПодсистема.xml")).exists();
+    assertThat(OUTPUT_DIR.resolve("Subsystems").resolve("ВтораяПодсистема.xml")).exists();
     Path nestedSub = OUTPUT_DIR.resolve("Subsystems").resolve("ПерваяПодсистема").resolve("Subsystems").resolve("ПодчиненнаяПодсистема.xml");
-    assert Files.exists(nestedSub) : "Subsystems/ПерваяПодсистема/Subsystems/ПодчиненнаяПодсистема.xml";
-    assert Files.exists(OUTPUT_DIR.resolve("Catalogs").resolve("Справочник1.xml")) : "Catalogs/Справочник1.xml";
+    assertThat(nestedSub).exists();
+    assertThat(OUTPUT_DIR.resolve("Catalogs").resolve("Справочник1.xml")).exists();
     Path formsDir = OUTPUT_DIR.resolve("Catalogs").resolve("Справочник1").resolve("Forms");
-    assert Files.exists(formsDir.resolve("ФормаЭлемента.xml")) : "Catalogs/Справочник1/Forms/ФормаЭлемента.xml";
-    assert Files.exists(formsDir.resolve("ФормаСписка.xml")) : "Catalogs/Справочник1/Forms/ФормаСписка.xml";
-    assert Files.exists(formsDir.resolve("ФормаВыбора.xml")) : "Catalogs/Справочник1/Forms/ФормаВыбора.xml";
+    assertThat(formsDir.resolve("ФормаЭлемента.xml")).exists();
+    assertThat(formsDir.resolve("ФормаСписка.xml")).exists();
+    assertThat(formsDir.resolve("ФормаВыбора.xml")).exists();
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/test/java/com/github/_1c_syntax/bsl/mdclasses/jaxb/write/JaxbWriterExampleTest.java`
around lines 51 - 63, Replace raw Java assert statements in
JaxbWriterExampleTest with AssertJ fluent assertions: for each occurrence like
assert Files.exists(path) : "msg" or checking existence of Paths (e.g.,
configPath, nestedSub, formsDir.resolve(...)), use
org.assertj.core.api.Assertions.assertThat(...) with a descriptive assertion
(for Path use assertThat(path).as("...").exists() or
assertThat(Files.exists(path)).as("...").isTrue()) so failures show clear
messages; update imports to include AssertJ (Assertions) and remove reliance on
JVM-enabled assertions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

API для записи объектов метаданных из стороннего приложения

1 participant