Skip to content

Commit 3c4a54d

Browse files
committed
refactor(writeObject): Обновлены классы и методы для записи метаданных в форматах EDT и Designer
- Добавлены аннотации @nonnull и @nullable для параметров методов в классе MDClasses, что улучшает обработку null-значений. - Обновлены комментарии в методах writeObject для более точного описания поддерживаемых форматов и типов объектов. - Введены изменения в класс MDCWriteSettings для поддержки null-значений в параметре кодировки. - Обновлены конвертеры для записи объектов Catalog и Configuration, добавлены новые свойства и улучшена обработка данных. - Реализована атомарная запись в формате EDT с использованием временных файлов для повышения надежности. - Добавлены новые тесты для проверки корректности записи и обработки исключений.
1 parent 24d5cf8 commit 3c4a54d

15 files changed

Lines changed: 264 additions & 128 deletions

src/main/java/com/github/_1c_syntax/bsl/mdclasses/MDCWriteSettings.java

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,23 +22,30 @@
2222
package com.github._1c_syntax.bsl.mdclasses;
2323

2424
import lombok.Builder;
25+
import org.jspecify.annotations.Nullable;
26+
27+
import java.nio.charset.StandardCharsets;
2528

2629
/**
27-
* Настройки записи MDC
30+
* Настройки записи объектов метаданных в файлы (EDT и Designer).
31+
* Используется при вызове {@link com.github._1c_syntax.bsl.mdclasses.MDClasses#writeObject(java.nio.file.Path, Object, MDCWriteSettings)}.
2832
*
29-
* @param encoding Кодировка файлов (по умолчанию UTF-8)
33+
* @param encoding Кодировка записываемых файлов (по умолчанию UTF-8)
3034
*/
3135
@Builder
32-
public record MDCWriteSettings(String encoding) {
36+
public record MDCWriteSettings(@Nullable String encoding) {
3337

3438
/**
35-
* Настройки по умолчанию (UTF-8)
39+
* Настройки по умолчанию: кодировка UTF-8.
3640
*/
3741
public static final MDCWriteSettings DEFAULT = MDCWriteSettings.builder()
38-
.encoding("UTF-8")
42+
.encoding(StandardCharsets.UTF_8.name())
3943
.build();
4044

45+
/**
46+
* Возвращает кодировку для записи файлов; при null в настройках возвращается UTF-8.
47+
*/
4148
public String encoding() {
42-
return encoding != null ? encoding : "UTF-8";
49+
return encoding != null ? encoding : StandardCharsets.UTF_8.name();
4350
}
4451
}

src/main/java/com/github/_1c_syntax/bsl/mdclasses/MDClasses.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
import lombok.experimental.UtilityClass;
2929
import lombok.extern.slf4j.Slf4j;
3030
import org.apache.commons.io.FilenameUtils;
31+
import org.jspecify.annotations.NonNull;
32+
import org.jspecify.annotations.Nullable;
3133

3234
import java.io.IOException;
3335
import java.nio.file.Files;
@@ -68,13 +70,13 @@ public ExternalSource createExternalReport() {
6870
}
6971

7072
/**
71-
* Записывает объект метаданных в файл (формат определяется по расширению пути: .mdo — EDT).
73+
* Записывает объект метаданных в файл (формат по расширению пути: .mdo — EDT, .xml — Designer).
7274
*
73-
* @param path Путь к файлу (например, .../Subsystems/Name/Name.mdo)
74-
* @param object Объект метаданных (для EDT поддерживается Subsystem)
75+
* @param path Путь к файлу (например, .../Subsystems/Name/Name.mdo или .../Subsystems/Name.xml)
76+
* @param object Объект метаданных (поддерживается Subsystem, Catalog, Configuration)
7577
* @throws IOException при ошибке записи
7678
*/
77-
public void writeObject(Path path, Object object) throws IOException {
79+
public void writeObject(@NonNull Path path, @NonNull Object object) throws IOException {
7880
MDOWriter.writeObject(path, object);
7981
}
8082

@@ -86,7 +88,7 @@ public void writeObject(Path path, Object object) throws IOException {
8688
* @param writeSettings Настройки записи
8789
* @throws IOException при ошибке записи
8890
*/
89-
public void writeObject(Path path, Object object, MDCWriteSettings writeSettings) throws IOException {
91+
public void writeObject(@NonNull Path path, @NonNull Object object, @Nullable MDCWriteSettings writeSettings) throws IOException {
9092
MDOWriter.writeObject(path, object, writeSettings);
9193
}
9294

src/main/java/com/github/_1c_syntax/bsl/writer/MDOWriter.java

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,25 +25,23 @@
2525
import com.github._1c_syntax.bsl.writer.designer.DesignerWriter;
2626
import com.github._1c_syntax.bsl.writer.edt.EDTWriter;
2727
import lombok.experimental.UtilityClass;
28-
import lombok.extern.slf4j.Slf4j;
2928
import org.apache.commons.io.FilenameUtils;
3029

3130
import java.io.IOException;
3231
import java.nio.file.Path;
3332

3433
/**
35-
* Фасад записи объектов метаданных в файлы (EDT .mdo, в перспективе Designer .xml).
34+
* Фасад записи объектов метаданных в файлы (EDT .mdo и Designer .xml).
3635
*/
3736
@UtilityClass
38-
@Slf4j
3937
public class MDOWriter {
4038

4139
/**
4240
* Записывает объект метаданных в файл.
43-
* Формат определяется по расширению пути: .mdo — EDT.
41+
* Формат определяется по расширению пути: .mdo — EDT, .xml — Designer.
4442
*
45-
* @param path Путь к файлу (например, .../Subsystems/Name/Name.mdo)
46-
* @param object Объект метаданных (поддерживается Subsystem для EDT)
43+
* @param path Путь к файлу (например, .../Subsystems/Name/Name.mdo или .../Subsystems/Name.xml)
44+
* @param object Объект метаданных (Subsystem, Catalog, Configuration)
4745
* @throws IOException при ошибке записи
4846
* @throws UnsupportedOperationException если формат или тип объекта не поддерживается
4947
*/
@@ -54,10 +52,10 @@ public void writeObject(Path path, Object object) throws IOException {
5452
/**
5553
* Записывает объект метаданных в файл с настройками.
5654
*
57-
* @param path Путь к файлу
58-
* @param object Объект метаданных
59-
* @param writeSettings Настройки записи
60-
* @throws IOException при ошибке записи
55+
* @param path Путь к файлу (расширение .mdo или .xml определяет формат)
56+
* @param object Объект метаданных (Subsystem, Catalog, Configuration)
57+
* @param writeSettings Настройки записи (кодировка и др.); может быть null — тогда используются настройки по умолчанию
58+
* @throws IOException при ошибке записи
6159
* @throws UnsupportedOperationException если формат или тип объекта не поддерживается
6260
*/
6361
public void writeObject(Path path, Object object, MDCWriteSettings writeSettings) throws IOException {

src/main/java/com/github/_1c_syntax/bsl/writer/ReadWriteDemo.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,11 @@ public final class ReadWriteDemo {
4444
private ReadWriteDemo() {
4545
}
4646

47+
/**
48+
* Точка входа: создаёт примеры Subsystem, Catalog, Configuration и записывает их в EDT и Designer.
49+
*
50+
* @param args необязательный путь к каталогу вывода; по умолчанию build/read-write-demo-output
51+
*/
4752
public static void main(String[] args) throws Exception {
4853
var baseDir = args.length > 0 ? Paths.get(args[0]) : Paths.get("build", "read-write-demo-output");
4954
var edtDir = baseDir.resolve("edt");

src/main/java/com/github/_1c_syntax/bsl/writer/designer/CatalogDesignerWriteConverter.java

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,12 @@
2222
package com.github._1c_syntax.bsl.writer.designer;
2323

2424
import com.github._1c_syntax.bsl.mdo.Catalog;
25+
import com.github._1c_syntax.bsl.types.MdoReference;
2526
import com.github._1c_syntax.bsl.types.MultiLanguageString;
2627
import com.thoughtworks.xstream.converters.Converter;
28+
29+
import java.util.List;
30+
import java.util.stream.Collectors;
2731
import com.thoughtworks.xstream.converters.MarshallingContext;
2832
import com.thoughtworks.xstream.converters.UnmarshallingContext;
2933
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
@@ -32,6 +36,8 @@
3236
/**
3337
* Конвертер записи справочника в формате Конфигуратора (Designer .xml).
3438
* MVP: Name, Synonym, Comment, базовые свойства (UseStandardCommands, LevelCount, CodeLength и т.д.).
39+
* Часть свойств (Hierarchical, HierarchyType, LevelCount, CodeLength и т.д.) задаётся значениями по умолчанию,
40+
* так как в модели {@link com.github._1c_syntax.bsl.mdo.Catalog} пока нет соответствующих полей; при их появлении нужно перейти на чтение из catalog.
3541
*/
3642
public class CatalogDesignerWriteConverter implements Converter {
3743

@@ -44,6 +50,7 @@ public class CatalogDesignerWriteConverter implements Converter {
4450
private static final String V8_CONTENT = "v8:content";
4551
private static final String FALSE = "false";
4652

53+
/** Сериализует справочник в Designer XML (Properties: Name, Synonym, Comment и др.). */
4754
@Override
4855
public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {
4956
var catalog = (Catalog) source;
@@ -55,13 +62,14 @@ public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingC
5562
writeElement(writer, NAME, catalog.getName());
5663
writeSynonym(writer, catalog.getSynonym());
5764
writeElement(writer, COMMENT, catalog.getComment() != null ? catalog.getComment() : "");
65+
// Catalog model only has getOwners(), getCodeSeries(), isCheckUnique() for these; rest are defaults until model is extended
5866
writeElement(writer, "Hierarchical", "true");
5967
writeElement(writer, "HierarchyType", "HierarchyFoldersAndItems");
6068
writeElement(writer, "LimitLevelCount", FALSE);
6169
writeElement(writer, "LevelCount", "2");
6270
writeElement(writer, "FoldersOnTop", "true");
6371
writeElement(writer, "UseStandardCommands", "true");
64-
writeElement(writer, "Owners", "");
72+
writeElement(writer, "Owners", formatOwners(catalog.getOwners()));
6573
writeElement(writer, "SubordinationUse", "ToItems");
6674
writeElement(writer, "CodeLength", "9");
6775
writeElement(writer, "DescriptionLength", "25");
@@ -88,31 +96,32 @@ private static void writeSynonym(HierarchicalStreamWriter writer, MultiLanguageS
8896
writer.endNode();
8997
}
9098

99+
private static String formatOwners(List<MdoReference> owners) {
100+
if (owners == null || owners.isEmpty()) {
101+
return "";
102+
}
103+
return owners.stream()
104+
.filter(ref -> ref != null && ref.getMdoRef() != null && !ref.getMdoRef().isEmpty())
105+
.map(MdoReference::getMdoRef)
106+
.collect(Collectors.joining(", "));
107+
}
108+
91109
private static void writeElement(HierarchicalStreamWriter writer, String nodeName, String text) {
92110
if (text == null) {
93111
return;
94112
}
95113
writer.startNode(nodeName);
96-
writer.setValue(escapeXml(text));
114+
writer.setValue(text);
97115
writer.endNode();
98116
}
99117

100-
private static String escapeXml(String s) {
101-
if (s == null) {
102-
return "";
103-
}
104-
return s.replace("&", "&amp;")
105-
.replace("<", "&lt;")
106-
.replace(">", "&gt;")
107-
.replace("\"", "&quot;")
108-
.replace("'", "&apos;");
109-
}
110-
118+
/** Конвертер только для записи; чтение не поддерживается. */
111119
@Override
112120
public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
113121
throw new UnsupportedOperationException("CatalogDesignerWriteConverter is for writing only");
114122
}
115123

124+
/** Поддерживается только тип {@link com.github._1c_syntax.bsl.mdo.Catalog}. */
116125
@Override
117126
public boolean canConvert(Class type) {
118127
return Catalog.class.isAssignableFrom(type);

src/main/java/com/github/_1c_syntax/bsl/writer/designer/ConfigurationDesignerWriteConverter.java

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ public class ConfigurationDesignerWriteConverter implements Converter {
4848
private static final String V8_LANG = "v8:lang";
4949
private static final String V8_CONTENT = "v8:content";
5050

51+
/** Сериализует конфигурацию в Designer XML (Properties, ChildObjects). */
5152
@Override
5253
public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {
5354
var config = (Configuration) source;
@@ -79,14 +80,18 @@ public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingC
7980
writeChildList(writer, config.getSessionParameters());
8081
writeChildList(writer, config.getSettingsStorages());
8182
writeChildList(writer, config.getFunctionalOptions());
83+
writeChildList(writer, config.getBots());
84+
writeChildList(writer, config.getFunctionalOptionsParameters());
8285
writeChildList(writer, config.getDefinedTypes());
8386
writeChildList(writer, config.getCommonTemplates());
8487
writeChildList(writer, config.getCommonPictures());
8588
writeChildList(writer, config.getCommonAttributes());
8689
writeChildList(writer, config.getXDTOPackages());
8790
writeChildList(writer, config.getWebServices());
91+
writeChildList(writer, config.getWebSocketClients());
8892
writeChildList(writer, config.getHttpServices());
8993
writeChildList(writer, config.getWsReferences());
94+
writeChildList(writer, config.getIntegrationServices());
9095
writeChildList(writer, config.getEventSubscriptions());
9196
writeChildList(writer, config.getScheduledJobs());
9297
writeChildList(writer, config.getDocumentNumerators());
@@ -106,6 +111,7 @@ public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingC
106111
writeChildList(writer, config.getStyleItems());
107112
writeChildList(writer, config.getLanguages());
108113
writeChildList(writer, config.getCommandGroups());
114+
writeChildList(writer, config.getPaletteColors());
109115
writer.endNode(); // ChildObjects
110116
}
111117

@@ -142,26 +148,17 @@ private static void writeElement(HierarchicalStreamWriter writer, String nodeNam
142148
return;
143149
}
144150
writer.startNode(nodeName);
145-
writer.setValue(escapeXml(text));
151+
writer.setValue(text);
146152
writer.endNode();
147153
}
148154

149-
private static String escapeXml(String s) {
150-
if (s == null) {
151-
return "";
152-
}
153-
return s.replace("&", "&amp;")
154-
.replace("<", "&lt;")
155-
.replace(">", "&gt;")
156-
.replace("\"", "&quot;")
157-
.replace("'", "&apos;");
158-
}
159-
155+
/** Конвертер только для записи; чтение не поддерживается. */
160156
@Override
161157
public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
162158
throw new UnsupportedOperationException("ConfigurationDesignerWriteConverter is for writing only");
163159
}
164160

161+
/** Поддерживается только тип {@link Configuration}. */
165162
@Override
166163
public boolean canConvert(Class type) {
167164
return Configuration.class.isAssignableFrom(type);

src/main/java/com/github/_1c_syntax/bsl/writer/designer/DesignerWriter.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@
3939

4040
/**
4141
* Запись объектов метаданных в формате Конфигуратора (Designer .xml).
42-
* Поддерживаются: Subsystem, Catalog, Configuration.
42+
* Поддерживаются только типы: Subsystem, Catalog, Configuration.
43+
* ConfigurationExtension и другие реализации CF в данной версии не поддерживаются.
4344
*/
4445
@Slf4j
4546
public class DesignerWriter {
@@ -50,6 +51,11 @@ public class DesignerWriter {
5051
private final XStream xstream;
5152
private final MDCWriteSettings writeSettings;
5253

54+
/**
55+
* Создаёт писатель Designer XML с заданными настройками.
56+
*
57+
* @param writeSettings настройки записи (кодировка и др.); null заменяется на {@link MDCWriteSettings#DEFAULT}
58+
*/
5359
public DesignerWriter(MDCWriteSettings writeSettings) {
5460
this.writeSettings = writeSettings != null ? writeSettings : MDCWriteSettings.DEFAULT;
5561
this.xstream = createXStream();
@@ -59,8 +65,9 @@ public DesignerWriter(MDCWriteSettings writeSettings) {
5965
* Записывает объект в файл .xml (формат Конфигуратора).
6066
*
6167
* @param path Путь к файлу .xml (родительские каталоги создаются при необходимости)
62-
* @param object Объект метаданных (поддерживается Subsystem)
68+
* @param object Объект метаданных (поддерживаются только Subsystem, Catalog, Configuration)
6369
* @throws IOException при ошибке записи
70+
* @throws UnsupportedOperationException если тип object не Subsystem, Catalog или Configuration
6471
*/
6572
public void write(Path path, Object object) throws IOException {
6673
if (object == null) {

0 commit comments

Comments
 (0)