From c7b4e70e2b220fc4c960b9b4bfbf426684731c8f Mon Sep 17 00:00:00 2001 From: Richard Eckart de Castilho Date: Mon, 8 Apr 2024 19:52:39 +0200 Subject: [PATCH] #4699 - Ability to export all layers as JSON - Cleaning up code --- .../export/TagsetImportExportUtils.java | 107 ------------- .../export/model/ExportedAnnotationLayer.java | 33 +--- .../inception-project-initializers/pom.xml | 4 + .../CoreferenceRelationTagSetInitializer.java | 2 +- .../CoreferenceTypeTagSetInitializer.java | 2 +- .../DependencyTypeTagSetInitializer.java | 2 +- .../NamedEntityTagSetInitializer.java | 2 +- .../PartOfSpeechTagSetInitializer.java | 2 +- .../schema/exporters/LayerExporter.java | 13 +- .../exporters}/LayerImportExportUtils.java | 29 ++-- .../schema/exporters/TagSetExporter.java | 23 ++- .../exporters/TagsetImportExportUtils.java} | 145 +++++++++++++----- .../ui/project/layers/LayerDetailForm.java | 24 +-- .../ui/project/layers/ProjectLayersPanel.java | 54 +++---- .../webanno/ui/tagsets/TagSetImportPanel.java | 12 +- inception/inception-versioning/pom.xml | 9 +- .../versioning/VersioningServiceImpl.java | 14 +- 17 files changed, 197 insertions(+), 280 deletions(-) delete mode 100644 inception/inception-export/src/main/java/de/tudarmstadt/ukp/inception/export/TagsetImportExportUtils.java rename inception/{inception-export/src/main/java/de/tudarmstadt/ukp/inception/export => inception-schema/src/main/java/de/tudarmstadt/ukp/inception/schema/exporters}/LayerImportExportUtils.java (93%) rename inception/{inception-export/src/main/java/de/tudarmstadt/ukp/inception/export/JsonImportUtil.java => inception-schema/src/main/java/de/tudarmstadt/ukp/inception/schema/exporters/TagsetImportExportUtils.java} (65%) diff --git a/inception/inception-export/src/main/java/de/tudarmstadt/ukp/inception/export/TagsetImportExportUtils.java b/inception/inception-export/src/main/java/de/tudarmstadt/ukp/inception/export/TagsetImportExportUtils.java deleted file mode 100644 index 654d285d355..00000000000 --- a/inception/inception-export/src/main/java/de/tudarmstadt/ukp/inception/export/TagsetImportExportUtils.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Licensed to the Technische Universität Darmstadt under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The Technische Universität Darmstadt - * licenses this file to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.tudarmstadt.ukp.inception.export; - -import static java.nio.charset.StandardCharsets.UTF_8; - -import java.io.IOException; -import java.io.InputStream; - -import org.apache.commons.io.IOUtils; - -import de.tudarmstadt.ukp.clarin.webanno.model.Project; -import de.tudarmstadt.ukp.clarin.webanno.model.Tag; -import de.tudarmstadt.ukp.clarin.webanno.model.TagSet; -import de.tudarmstadt.ukp.inception.schema.api.AnnotationSchemaService; - -public class TagsetImportExportUtils -{ - public static TagSet importTagsetFromTabSeparated(AnnotationSchemaService annotationService, - Project project, InputStream aInputStream, boolean aOverwrite) - throws IOException - { - var text = IOUtils.toString(aInputStream, UTF_8); - var tabbedTagsetFromFile = LayerImportExportUtils.getTagSetFromFile(text); - - var listOfTagsFromFile = tabbedTagsetFromFile.keySet(); - var i = 0; - var tagSetName = ""; - var tagSetDescription = ""; - var tagsetLanguage = ""; - de.tudarmstadt.ukp.clarin.webanno.model.TagSet tagSet = null; - for (String key : listOfTagsFromFile) { - // the first key is the tagset name and its - // description - if (i == 0) { - tagSetName = key; - tagSetDescription = tabbedTagsetFromFile.get(key); - } - // the second key is the tagset language - else if (i == 1) { - tagsetLanguage = key; - // remove and replace the tagset if it - // exist - if (annotationService.existsTagSet(tagSetName, project)) { - // If overwrite is enabled - if (aOverwrite) { - tagSet = annotationService.getTagSet(tagSetName, project); - annotationService.removeAllTags(tagSet); - } - else { - tagSet = new TagSet(); - tagSet.setName(JsonImportUtil.copyTagSetName(annotationService, tagSetName, - project)); - } - } - else { - tagSet = new TagSet(); - tagSet.setName(tagSetName); - } - tagSet.setDescription(tagSetDescription.replace("\\n", "\n")); - tagSet.setLanguage(tagsetLanguage); - tagSet.setProject(project); - annotationService.createTagSet(tagSet); - } - // otherwise it is a tag entry, add the tag to the tagset - else { - Tag tag = new Tag(); - tag.setName(key); - tag.setDescription(tabbedTagsetFromFile.get(key).replace("\\n", "\n")); - tag.setRank(i); - tag.setTagSet(tagSet); - annotationService.createTag(tag); - } - i++; - } - - return tagSet; - } - - public static TagSet importTagsetFromJson(AnnotationSchemaService annotationService, - Project project, InputStream aInputStream, boolean aOverwrite) - throws IOException - { - if (aOverwrite) { - return JsonImportUtil.importTagSetFromJsonWithOverwrite(project, aInputStream, - annotationService); - } - else { - return JsonImportUtil.importTagSetFromJson(project, aInputStream, annotationService); - } - } -} diff --git a/inception/inception-model-export/src/main/java/de/tudarmstadt/ukp/clarin/webanno/export/model/ExportedAnnotationLayer.java b/inception/inception-model-export/src/main/java/de/tudarmstadt/ukp/clarin/webanno/export/model/ExportedAnnotationLayer.java index 34566d1e979..9a634dcf61a 100644 --- a/inception/inception-model-export/src/main/java/de/tudarmstadt/ukp/clarin/webanno/export/model/ExportedAnnotationLayer.java +++ b/inception/inception-model-export/src/main/java/de/tudarmstadt/ukp/clarin/webanno/export/model/ExportedAnnotationLayer.java @@ -91,15 +91,9 @@ public class ExportedAnnotationLayer @JsonProperty("multiple_tokens") private boolean multipleTokens; - @JsonProperty("project_name") - private String projectName; - @JsonProperty("linked_list_behavior") private boolean linkedListBehavior; - @JsonProperty("on_click_javascript_action") - private String onClickJavascriptAction; - @JsonProperty("traits") private String traits; @@ -315,16 +309,6 @@ public void setAttachFeature(ExportedAnnotationFeatureReference attachFeature) this.attachFeature = attachFeature; } - public String isProjectName() - { - return projectName; - } - - public void setProjectName(String projectName) - { - this.projectName = projectName; - } - public boolean isLinkedListBehavior() { return linkedListBehavior; @@ -345,16 +329,6 @@ public void setReadonly(boolean aReadonly) readonly = aReadonly; } - public String getOnClickJavascriptAction() - { - return onClickJavascriptAction; - } - - public void setOnClickJavascriptAction(String onClickAction) - { - this.onClickJavascriptAction = onClickAction; - } - public String getTraits() { return traits; @@ -371,14 +345,15 @@ public boolean equals(final Object other) if (!(other instanceof ExportedAnnotationLayer)) { return false; } - ExportedAnnotationLayer castOther = (ExportedAnnotationLayer) other; + + var castOther = (ExportedAnnotationLayer) other; return new EqualsBuilder().append(name, castOther.name).append(type, castOther.type) - .append(projectName, castOther.projectName).isEquals(); + .isEquals(); } @Override public int hashCode() { - return new HashCodeBuilder().append(name).append(type).append(projectName).toHashCode(); + return new HashCodeBuilder().append(name).append(type).toHashCode(); } } diff --git a/inception/inception-project-initializers/pom.xml b/inception/inception-project-initializers/pom.xml index e97d7adafbf..de11c173395 100644 --- a/inception/inception-project-initializers/pom.xml +++ b/inception/inception-project-initializers/pom.xml @@ -41,6 +41,10 @@ de.tudarmstadt.ukp.inception.app inception-schema-api + + de.tudarmstadt.ukp.inception.app + inception-schema + de.tudarmstadt.ukp.inception.app inception-support diff --git a/inception/inception-project-initializers/src/main/java/de/tudarmstadt/ukp/clarin/webanno/project/initializers/CoreferenceRelationTagSetInitializer.java b/inception/inception-project-initializers/src/main/java/de/tudarmstadt/ukp/clarin/webanno/project/initializers/CoreferenceRelationTagSetInitializer.java index 2489a844f9f..5a7679741cd 100644 --- a/inception/inception-project-initializers/src/main/java/de/tudarmstadt/ukp/clarin/webanno/project/initializers/CoreferenceRelationTagSetInitializer.java +++ b/inception/inception-project-initializers/src/main/java/de/tudarmstadt/ukp/clarin/webanno/project/initializers/CoreferenceRelationTagSetInitializer.java @@ -17,7 +17,7 @@ */ package de.tudarmstadt.ukp.clarin.webanno.project.initializers; -import static de.tudarmstadt.ukp.inception.export.JsonImportUtil.importTagSetFromJson; +import static de.tudarmstadt.ukp.inception.schema.exporters.TagsetImportExportUtils.importTagSetFromJson; import java.io.IOException; import java.util.Collections; diff --git a/inception/inception-project-initializers/src/main/java/de/tudarmstadt/ukp/clarin/webanno/project/initializers/CoreferenceTypeTagSetInitializer.java b/inception/inception-project-initializers/src/main/java/de/tudarmstadt/ukp/clarin/webanno/project/initializers/CoreferenceTypeTagSetInitializer.java index b33ee901289..e9d93dd3683 100644 --- a/inception/inception-project-initializers/src/main/java/de/tudarmstadt/ukp/clarin/webanno/project/initializers/CoreferenceTypeTagSetInitializer.java +++ b/inception/inception-project-initializers/src/main/java/de/tudarmstadt/ukp/clarin/webanno/project/initializers/CoreferenceTypeTagSetInitializer.java @@ -17,7 +17,7 @@ */ package de.tudarmstadt.ukp.clarin.webanno.project.initializers; -import static de.tudarmstadt.ukp.inception.export.JsonImportUtil.importTagSetFromJson; +import static de.tudarmstadt.ukp.inception.schema.exporters.TagsetImportExportUtils.importTagSetFromJson; import java.io.IOException; import java.util.Collections; diff --git a/inception/inception-project-initializers/src/main/java/de/tudarmstadt/ukp/clarin/webanno/project/initializers/DependencyTypeTagSetInitializer.java b/inception/inception-project-initializers/src/main/java/de/tudarmstadt/ukp/clarin/webanno/project/initializers/DependencyTypeTagSetInitializer.java index 7622e09bf08..2f84a323e7f 100644 --- a/inception/inception-project-initializers/src/main/java/de/tudarmstadt/ukp/clarin/webanno/project/initializers/DependencyTypeTagSetInitializer.java +++ b/inception/inception-project-initializers/src/main/java/de/tudarmstadt/ukp/clarin/webanno/project/initializers/DependencyTypeTagSetInitializer.java @@ -17,7 +17,7 @@ */ package de.tudarmstadt.ukp.clarin.webanno.project.initializers; -import static de.tudarmstadt.ukp.inception.export.JsonImportUtil.importTagSetFromJson; +import static de.tudarmstadt.ukp.inception.schema.exporters.TagsetImportExportUtils.importTagSetFromJson; import java.io.IOException; import java.util.Collections; diff --git a/inception/inception-project-initializers/src/main/java/de/tudarmstadt/ukp/clarin/webanno/project/initializers/NamedEntityTagSetInitializer.java b/inception/inception-project-initializers/src/main/java/de/tudarmstadt/ukp/clarin/webanno/project/initializers/NamedEntityTagSetInitializer.java index 7ae9e2c1478..474d6a48774 100644 --- a/inception/inception-project-initializers/src/main/java/de/tudarmstadt/ukp/clarin/webanno/project/initializers/NamedEntityTagSetInitializer.java +++ b/inception/inception-project-initializers/src/main/java/de/tudarmstadt/ukp/clarin/webanno/project/initializers/NamedEntityTagSetInitializer.java @@ -17,7 +17,7 @@ */ package de.tudarmstadt.ukp.clarin.webanno.project.initializers; -import static de.tudarmstadt.ukp.inception.export.JsonImportUtil.importTagSetFromJson; +import static de.tudarmstadt.ukp.inception.schema.exporters.TagsetImportExportUtils.importTagSetFromJson; import java.io.IOException; import java.util.Collections; diff --git a/inception/inception-project-initializers/src/main/java/de/tudarmstadt/ukp/clarin/webanno/project/initializers/PartOfSpeechTagSetInitializer.java b/inception/inception-project-initializers/src/main/java/de/tudarmstadt/ukp/clarin/webanno/project/initializers/PartOfSpeechTagSetInitializer.java index f24b252e474..54d9cd8957a 100644 --- a/inception/inception-project-initializers/src/main/java/de/tudarmstadt/ukp/clarin/webanno/project/initializers/PartOfSpeechTagSetInitializer.java +++ b/inception/inception-project-initializers/src/main/java/de/tudarmstadt/ukp/clarin/webanno/project/initializers/PartOfSpeechTagSetInitializer.java @@ -17,7 +17,7 @@ */ package de.tudarmstadt.ukp.clarin.webanno.project.initializers; -import static de.tudarmstadt.ukp.inception.export.JsonImportUtil.importTagSetFromJson; +import static de.tudarmstadt.ukp.inception.schema.exporters.TagsetImportExportUtils.importTagSetFromJson; import java.io.IOException; import java.util.Collections; diff --git a/inception/inception-schema/src/main/java/de/tudarmstadt/ukp/inception/schema/exporters/LayerExporter.java b/inception/inception-schema/src/main/java/de/tudarmstadt/ukp/inception/schema/exporters/LayerExporter.java index 9ba76ac1dc6..32bc776e994 100644 --- a/inception/inception-schema/src/main/java/de/tudarmstadt/ukp/inception/schema/exporters/LayerExporter.java +++ b/inception/inception-schema/src/main/java/de/tudarmstadt/ukp/inception/schema/exporters/LayerExporter.java @@ -141,7 +141,6 @@ private ExportedAnnotationLayer exportLayerDetails( exLayer.setValidationMode(aLayer.getValidationMode()); exLayer.setLinkedListBehavior(aLayer.isLinkedListBehavior()); exLayer.setName(aLayer.getName()); - exLayer.setProjectName(aLayer.getProject().getName()); exLayer.setType(aLayer.getType()); exLayer.setUiName(aLayer.getUiName()); exLayer.setTraits(aLayer.getTraits()); @@ -151,9 +150,9 @@ private ExportedAnnotationLayer exportLayerDetails( } // Export features - List exFeatures = new ArrayList<>(); - for (AnnotationFeature feature : annotationService.listAnnotationFeature(aLayer)) { - ExportedAnnotationFeature exFeature = exportFeatureDetails(feature); + var exFeatures = new ArrayList(); + for (var feature : annotationService.listAnnotationFeature(aLayer)) { + var exFeature = exportFeatureDetails(feature); exFeatures.add(exFeature); if (aFeatureToExFeature != null) { @@ -167,7 +166,7 @@ private ExportedAnnotationLayer exportLayerDetails( private ExportedAnnotationFeature exportFeatureDetails(AnnotationFeature feature) { - ExportedAnnotationFeature exFeature = new ExportedAnnotationFeature(); + var exFeature = new ExportedAnnotationFeature(); exFeature.setDescription(feature.getDescription()); exFeature.setEnabled(feature.isEnabled()); exFeature.setRemember(feature.isRemember()); @@ -189,10 +188,10 @@ private ExportedAnnotationFeature exportFeatureDetails(AnnotationFeature feature exFeature.setRank(feature.getRank()); if (feature.getTagset() != null) { - TagSet tagSet = feature.getTagset(); + var tagSet = feature.getTagset(); // We export only the name here as a stub. The actual tag set is exported by // the TagSetExporter. - ExportedTagSet exTagSet = new ExportedTagSet(); + var exTagSet = new ExportedTagSet(); exTagSet.setName(tagSet.getName()); exFeature.setTagSet(exTagSet); } diff --git a/inception/inception-export/src/main/java/de/tudarmstadt/ukp/inception/export/LayerImportExportUtils.java b/inception/inception-schema/src/main/java/de/tudarmstadt/ukp/inception/schema/exporters/LayerImportExportUtils.java similarity index 93% rename from inception/inception-export/src/main/java/de/tudarmstadt/ukp/inception/export/LayerImportExportUtils.java rename to inception/inception-schema/src/main/java/de/tudarmstadt/ukp/inception/schema/exporters/LayerImportExportUtils.java index b6cbac33823..5d5e5178151 100644 --- a/inception/inception-export/src/main/java/de/tudarmstadt/ukp/inception/export/LayerImportExportUtils.java +++ b/inception/inception-schema/src/main/java/de/tudarmstadt/ukp/inception/schema/exporters/LayerImportExportUtils.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.tudarmstadt.ukp.inception.export; +package de.tudarmstadt.ukp.inception.schema.exporters; import static de.tudarmstadt.ukp.clarin.webanno.model.OverlapMode.ANY_OVERLAP; import static de.tudarmstadt.ukp.clarin.webanno.model.OverlapMode.OVERLAP_ONLY; @@ -64,14 +64,14 @@ public static String exportLayerToJson(AnnotationSchemaService aSchemaService, { var exLayers = new ArrayList(); - var exMainLayer = exportLayerDetails(null, null, layer, aSchemaService); + var exMainLayer = exportLayerDetails(layer, aSchemaService); exLayers.add(exMainLayer); // If the layer is attached to another layer, then we also have to export // that, otherwise we would be missing it during re-import. if (layer.getAttachType() != null) { var attachLayer = layer.getAttachType(); - var exAttachLayer = exportLayerDetails(null, null, attachLayer, aSchemaService); + var exAttachLayer = exportLayerDetails(attachLayer, aSchemaService); exMainLayer .setAttachType(new ExportedAnnotationLayerReference(exAttachLayer.getName())); exLayers.add(exAttachLayer); @@ -101,7 +101,7 @@ public static Map getTagSetFromFile(String aLineSeparatedTags) } @Deprecated - private static void createTagSet(TagSet aTagSet, ExportedTagSet aExTagSet, Project aProject, + private static void importTagSet(TagSet aTagSet, ExportedTagSet aExTagSet, Project aProject, AnnotationSchemaService aAnnotationService) throws IOException { @@ -117,7 +117,7 @@ private static void createTagSet(TagSet aTagSet, ExportedTagSet aExTagSet, Proje if (aAnnotationService.existsTag(exTag.getName(), aTagSet)) { continue; } - Tag tag = new Tag(); + var tag = new Tag(); tag.setDescription(exTag.getDescription()); tag.setTagSet(aTagSet); tag.setName(exTag.getName()); @@ -220,11 +220,11 @@ private static AnnotationLayer createLayer(AnnotationSchemaService annotationSer TagSet tagSet = null; if (exTagset != null && annotationService.existsTagSet(exTagset.getName(), project)) { tagSet = annotationService.getTagSet(exTagset.getName(), project); - createTagSet(tagSet, exTagset, project, annotationService); + importTagSet(tagSet, exTagset, project, annotationService); } else if (exTagset != null) { tagSet = new TagSet(); - createTagSet(tagSet, exTagset, project, annotationService); + importTagSet(tagSet, exTagset, project, annotationService); } if (annotationService.existsFeature(exfeature.getName(), layer)) { AnnotationFeature feature = annotationService.getFeature(exfeature.getName(), @@ -284,10 +284,8 @@ else if (Token._TypeName.equals(aFeature.getLayer().getName()) } @Deprecated - public static ExportedAnnotationLayer exportLayerDetails( - Map aLayerToExLayer, - Map aFeatureToExFeature, - AnnotationLayer aLayer, AnnotationSchemaService aAnnotationService) + public static ExportedAnnotationLayer exportLayerDetails(AnnotationLayer aLayer, + AnnotationSchemaService aAnnotationService) { var exLayer = new ExportedAnnotationLayer(); exLayer.setAllowStacking(aLayer.isAllowStacking()); @@ -303,15 +301,10 @@ public static ExportedAnnotationLayer exportLayerDetails( exLayer.setValidationMode(aLayer.getValidationMode()); exLayer.setLinkedListBehavior(aLayer.isLinkedListBehavior()); exLayer.setName(aLayer.getName()); - exLayer.setProjectName(aLayer.getProject().getName()); exLayer.setType(aLayer.getType()); exLayer.setUiName(aLayer.getUiName()); exLayer.setTraits(aLayer.getTraits()); - if (aLayerToExLayer != null) { - aLayerToExLayer.put(aLayer, exLayer); - } - var exFeatures = new ArrayList(); for (var feature : aAnnotationService.listAnnotationFeature(aLayer)) { var exFeature = new ExportedAnnotationFeature(); @@ -352,10 +345,8 @@ public static ExportedAnnotationLayer exportLayerDetails( exTagSet.setTags(exportedTags); exFeature.setTagSet(exTagSet); } + exFeatures.add(exFeature); - if (aFeatureToExFeature != null) { - aFeatureToExFeature.put(feature, exFeature); - } } exLayer.setFeatures(exFeatures); diff --git a/inception/inception-schema/src/main/java/de/tudarmstadt/ukp/inception/schema/exporters/TagSetExporter.java b/inception/inception-schema/src/main/java/de/tudarmstadt/ukp/inception/schema/exporters/TagSetExporter.java index 29a31dcccfa..48f161d3dea 100644 --- a/inception/inception-schema/src/main/java/de/tudarmstadt/ukp/inception/schema/exporters/TagSetExporter.java +++ b/inception/inception-schema/src/main/java/de/tudarmstadt/ukp/inception/schema/exporters/TagSetExporter.java @@ -21,7 +21,6 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; -import java.util.Set; import java.util.stream.Collectors; import java.util.zip.ZipFile; @@ -64,17 +63,17 @@ public TagSetExporter(AnnotationSchemaService aAnnotationService) public void exportData(FullProjectExportRequest aRequest, ProjectExportTaskMonitor aMonitor, ExportedProject aExProject, File aStage) { - List extTagSets = new ArrayList<>(); - for (TagSet tagSet : annotationService.listTagSets(aRequest.getProject())) { - ExportedTagSet exTagSet = new ExportedTagSet(); + var extTagSets = new ArrayList(); + for (var tagSet : annotationService.listTagSets(aRequest.getProject())) { + var exTagSet = new ExportedTagSet(); exTagSet.setCreateTag(tagSet.isCreateTag()); exTagSet.setDescription(tagSet.getDescription()); exTagSet.setLanguage(tagSet.getLanguage()); exTagSet.setName(tagSet.getName()); - List exTags = new ArrayList<>(); - for (Tag tag : annotationService.listTags(tagSet)) { - ExportedTag exTag = new ExportedTag(); + var exTags = new ArrayList(); + for (var tag : annotationService.listTags(tagSet)) { + var exTag = new ExportedTag(); exTag.setDescription(tag.getDescription()); exTag.setName(tag.getName()); exTags.add(exTag); @@ -100,7 +99,7 @@ public void importData(ProjectImportRequest aRequest, Project aProject, return; } - for (ExportedTagSet exTagSet : aExProject.getTagSets()) { + for (var exTagSet : aExProject.getTagSets()) { importTagSet(new TagSet(), exTagSet, aProject); } } @@ -173,18 +172,18 @@ private void importTagSet(TagSet aTagSet, ExportedTagSet aExTagSet, Project aPro aTagSet.setProject(aProject); annotationService.createTagSet(aTagSet); - Set existingTags = annotationService.listTags(aTagSet).stream() // + var existingTags = annotationService.listTags(aTagSet).stream() // .map(Tag::getName) // .collect(Collectors.toSet()); - List tags = new ArrayList<>(); - for (ExportedTag exTag : aExTagSet.getTags()) { + var tags = new ArrayList(); + for (var exTag : aExTagSet.getTags()) { // do not duplicate tag if (existingTags.contains(exTag.getName())) { continue; } - Tag tag = new Tag(); + var tag = new Tag(); tag.setTagSet(aTagSet); tag.setName(exTag.getName()); tag.setDescription(exTag.getDescription()); diff --git a/inception/inception-export/src/main/java/de/tudarmstadt/ukp/inception/export/JsonImportUtil.java b/inception/inception-schema/src/main/java/de/tudarmstadt/ukp/inception/schema/exporters/TagsetImportExportUtils.java similarity index 65% rename from inception/inception-export/src/main/java/de/tudarmstadt/ukp/inception/export/JsonImportUtil.java rename to inception/inception-schema/src/main/java/de/tudarmstadt/ukp/inception/schema/exporters/TagsetImportExportUtils.java index 827973a333d..71d479ccd95 100644 --- a/inception/inception-export/src/main/java/de/tudarmstadt/ukp/inception/export/JsonImportUtil.java +++ b/inception/inception-schema/src/main/java/de/tudarmstadt/ukp/inception/schema/exporters/TagsetImportExportUtils.java @@ -15,7 +15,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.tudarmstadt.ukp.inception.export; +package de.tudarmstadt.ukp.inception.schema.exporters; + +import static java.nio.charset.StandardCharsets.UTF_8; import java.io.IOException; import java.io.InputStream; @@ -30,8 +32,68 @@ import de.tudarmstadt.ukp.inception.schema.api.AnnotationSchemaService; import de.tudarmstadt.ukp.inception.support.json.JSONUtil; -public class JsonImportUtil +public class TagsetImportExportUtils { + public static TagSet importTagsetFromTabSeparated(AnnotationSchemaService annotationService, + Project project, InputStream aInputStream, boolean aOverwrite) + throws IOException + { + var text = IOUtils.toString(aInputStream, UTF_8); + var tabbedTagsetFromFile = LayerImportExportUtils.getTagSetFromFile(text); + + var listOfTagsFromFile = tabbedTagsetFromFile.keySet(); + var i = 0; + var tagSetName = ""; + var tagSetDescription = ""; + var tagsetLanguage = ""; + TagSet tagSet = null; + for (var key : listOfTagsFromFile) { + // the first key is the tagset name and its + // description + if (i == 0) { + tagSetName = key; + tagSetDescription = tabbedTagsetFromFile.get(key); + } + // the second key is the tagset language + else if (i == 1) { + tagsetLanguage = key; + // remove and replace the tagset if it + // exist + if (annotationService.existsTagSet(tagSetName, project)) { + // If overwrite is enabled + if (aOverwrite) { + tagSet = annotationService.getTagSet(tagSetName, project); + annotationService.removeAllTags(tagSet); + } + else { + tagSet = new TagSet(); + tagSet.setName(copyTagSetName(annotationService, tagSetName, project)); + } + } + else { + tagSet = new TagSet(); + tagSet.setName(tagSetName); + } + tagSet.setDescription(tagSetDescription.replace("\\n", "\n")); + tagSet.setLanguage(tagsetLanguage); + tagSet.setProject(project); + annotationService.createTagSet(tagSet); + } + // otherwise it is a tag entry, add the tag to the tagset + else { + Tag tag = new Tag(); + tag.setName(key); + tag.setDescription(tabbedTagsetFromFile.get(key).replace("\\n", "\n")); + tag.setRank(i); + tag.setTagSet(tagSet); + annotationService.createTag(tag); + } + i++; + } + + return tagSet; + } + /** * Works for scenarios with overwrite enabled Checks if tagset already exists, then overwrites * otherwise works normally @@ -51,16 +113,50 @@ public static TagSet importTagSetFromJsonWithOverwrite(Project aProject, throws IOException { var importedTagSet = JSONUtil.fromJsonStream(ExportedTagSet.class, aInputStream); - + if (aAnnotationService.existsTagSet(importedTagSet.getName(), aProject)) { // A tagset exists so we'll have to replace it return replaceTagSet(aProject, importedTagSet, aAnnotationService); } - + // Proceed normally return createTagSet(aProject, importedTagSet, aAnnotationService); } + public static TagSet importTagSetFromJson(Project project, InputStream tagInputStream, + AnnotationSchemaService aAnnotationService) + throws IOException + { + var importedTagSet = JSONUtil.fromJsonStream(ExportedTagSet.class, tagInputStream); + return createTagSet(project, importedTagSet, aAnnotationService); + } + + /** + * Provides a new name if TagSet already exists. + * + * @param aAnnotationService + * annotation service to look up existing tagsets + * @param aName + * the suggested name + * @param aProject + * the project into which to import the tagset + * @return a unique tag set name + */ + private static String copyTagSetName(AnnotationSchemaService aAnnotationService, String aName, + Project aProject) + { + var betterTagSetName = "copy_of_" + aName; + int i = 1; + while (true) { + if (!aAnnotationService.existsTagSet(betterTagSetName, aProject)) { + return betterTagSetName; + } + + betterTagSetName = "copy_of_" + aName + "(" + i + ")"; + i++; + } + } + private static TagSet replaceTagSet(Project project, ExportedTagSet importedTagSet, AnnotationSchemaService aAnnotationService) throws IOException @@ -91,23 +187,14 @@ private static TagSet replaceTagSet(Project project, ExportedTagSet importedTagS return tagsetInUse; } - public static TagSet importTagSetFromJson(Project project, InputStream tagInputStream, - AnnotationSchemaService aAnnotationService) - throws IOException - { - var text = IOUtils.toString(tagInputStream, "UTF-8"); - - var importedTagSet = JSONUtil.getObjectMapper().readValue(text, ExportedTagSet.class); - return createTagSet(project, importedTagSet, aAnnotationService); - } - - public static TagSet createTagSet(Project project, ExportedTagSet aExTagSet, + private static TagSet createTagSet(Project project, ExportedTagSet aExTagSet, AnnotationSchemaService aAnnotationService) throws IOException { var exTagSetName = aExTagSet.getName(); if (aAnnotationService.existsTagSet(exTagSetName, project)) { - exTagSetName = copyTagSetName(aAnnotationService, exTagSetName, project); + exTagSetName = TagsetImportExportUtils.copyTagSetName(aAnnotationService, exTagSetName, + project); } var newTagSet = new TagSet(); @@ -132,30 +219,4 @@ public static TagSet createTagSet(Project project, ExportedTagSet aExTagSet, return newTagSet; } - - /** - * Provides a new name if TagSet already exists. - * - * @param aAnnotationService - * annotation service to look up existing tagsets - * @param aName - * the suggested name - * @param aProject - * the project into which to import the tagset - * @return a unique tag set name - */ - public static String copyTagSetName(AnnotationSchemaService aAnnotationService, String aName, - Project aProject) - { - var betterTagSetName = "copy_of_" + aName; - int i = 1; - while (true) { - if (!aAnnotationService.existsTagSet(betterTagSetName, aProject)) { - return betterTagSetName; - } - - betterTagSetName = "copy_of_" + aName + "(" + i + ")"; - i++; - } - } } diff --git a/inception/inception-ui-project/src/main/java/de/tudarmstadt/ukp/clarin/webanno/ui/project/layers/LayerDetailForm.java b/inception/inception-ui-project/src/main/java/de/tudarmstadt/ukp/clarin/webanno/ui/project/layers/LayerDetailForm.java index f1e0be01c03..b95f9441c4d 100644 --- a/inception/inception-ui-project/src/main/java/de/tudarmstadt/ukp/clarin/webanno/ui/project/layers/LayerDetailForm.java +++ b/inception/inception-ui-project/src/main/java/de/tudarmstadt/ukp/clarin/webanno/ui/project/layers/LayerDetailForm.java @@ -63,13 +63,13 @@ import de.tudarmstadt.ukp.dkpro.core.api.segmentation.type.Token; import de.tudarmstadt.ukp.inception.bootstrap.BootstrapModalDialog; import de.tudarmstadt.ukp.inception.documents.api.DocumentService; -import de.tudarmstadt.ukp.inception.export.LayerImportExportUtils; import de.tudarmstadt.ukp.inception.schema.api.AnnotationSchemaService; import de.tudarmstadt.ukp.inception.schema.api.config.AnnotationSchemaProperties; import de.tudarmstadt.ukp.inception.schema.api.event.LayerConfigurationChangedEvent; import de.tudarmstadt.ukp.inception.schema.api.layer.LayerSupport; import de.tudarmstadt.ukp.inception.schema.api.layer.LayerSupportRegistry; import de.tudarmstadt.ukp.inception.schema.api.layer.LayerType; +import de.tudarmstadt.ukp.inception.schema.exporters.LayerImportExportUtils; import de.tudarmstadt.ukp.inception.support.help.DocLink; import de.tudarmstadt.ukp.inception.support.lambda.LambdaAjaxButton; import de.tudarmstadt.ukp.inception.support.lambda.LambdaAjaxLink; @@ -96,16 +96,16 @@ public class LayerDetailForm private @SpringBean CasStorageService casStorageService; private @SpringBean ApplicationEventPublisherHolder applicationEventPublisherHolder; - private DropDownChoice layerTypeSelect; - private DropDownChoice attachTypeSelect; - private Label effectiveAttachType; - private TextField uiName; + private final DropDownChoice layerTypeSelect; + private final DropDownChoice attachTypeSelect; + private final Label effectiveAttachType; + private final TextField uiName; - private FeatureSelectionForm featureSelectionForm; - private FeatureDetailForm featureDetailForm; + private final FeatureSelectionForm featureSelectionForm; + private final FeatureDetailForm featureDetailForm; - private WebMarkupContainer traitsContainer; - private ModalDialog confirmationDialog; + private final WebMarkupContainer traitsContainer; + private final ModalDialog confirmationDialog; public LayerDetailForm(String id, IModel aSelectedLayer, FeatureSelectionForm aFeatureSelectionForm, FeatureDetailForm aFeatureDetailForm) @@ -359,7 +359,7 @@ private void actionSave(AjaxRequestTarget aTarget, Form aForm) } if (annotationSchemaProperties.isCrossLayerRelationEnabled()) { - if (layer.getType().equals(RELATION_TYPE) && layer.getAttachType() == null) { + if (RELATION_TYPE.equals(layer.getType()) && layer.getAttachType() == null) { error("A relation layer needs to attach to a span layer."); return; } @@ -411,7 +411,7 @@ private IResourceStream exportFullTypeSystemAsUimaXml() private IResourceStream exportAllLayersAsUimaXml() { - try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) { + try (var bos = new ByteArrayOutputStream()) { var tsd = annotationService.getAllProjectTypes(getModelObject().getProject()); tsd.toXML(bos); return new InputStreamResourceStream(new ByteArrayInputStream(bos.toByteArray()), @@ -426,7 +426,7 @@ private IResourceStream exportAllLayersAsUimaXml() private IResourceStream exportLayerAsJson() { try { - String json = LayerImportExportUtils.exportLayerToJson(annotationService, + var json = LayerImportExportUtils.exportLayerToJson(annotationService, getModelObject()); return new InputStreamResourceStream(new ByteArrayInputStream(json.getBytes(UTF_8)), "layer.json"); diff --git a/inception/inception-ui-project/src/main/java/de/tudarmstadt/ukp/clarin/webanno/ui/project/layers/ProjectLayersPanel.java b/inception/inception-ui-project/src/main/java/de/tudarmstadt/ukp/clarin/webanno/ui/project/layers/ProjectLayersPanel.java index 4298c5feb4f..e9ba5093bfe 100644 --- a/inception/inception-ui-project/src/main/java/de/tudarmstadt/ukp/clarin/webanno/ui/project/layers/ProjectLayersPanel.java +++ b/inception/inception-ui-project/src/main/java/de/tudarmstadt/ukp/clarin/webanno/ui/project/layers/ProjectLayersPanel.java @@ -28,7 +28,6 @@ import static java.util.Objects.nonNull; import static org.apache.commons.collections4.CollectionUtils.isEmpty; -import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; @@ -44,7 +43,6 @@ import org.apache.commons.lang3.exception.ExceptionUtils; import org.apache.uima.UIMAFramework; import org.apache.uima.resource.ResourceInitializationException; -import org.apache.uima.resource.metadata.TypeSystemDescription; import org.apache.uima.util.InvalidXMLException; import org.apache.uima.util.XMLInputSource; import org.apache.wicket.AttributeModifier; @@ -59,7 +57,6 @@ import org.apache.wicket.markup.html.form.ChoiceRenderer; import org.apache.wicket.markup.html.form.Form; import org.apache.wicket.markup.html.form.ListChoice; -import org.apache.wicket.markup.html.form.upload.FileUpload; import org.apache.wicket.markup.html.list.ListItem; import org.apache.wicket.markup.html.list.ListView; import org.apache.wicket.model.IModel; @@ -79,19 +76,18 @@ import de.tudarmstadt.ukp.clarin.webanno.project.initializers.SentenceLayerInitializer; import de.tudarmstadt.ukp.clarin.webanno.project.initializers.TokenLayerInitializer; import de.tudarmstadt.ukp.clarin.webanno.security.UserDao; -import de.tudarmstadt.ukp.clarin.webanno.security.model.User; import de.tudarmstadt.ukp.clarin.webanno.ui.core.settings.ProjectSettingsPanelBase; import de.tudarmstadt.ukp.dkpro.core.api.segmentation.type.Sentence; import de.tudarmstadt.ukp.dkpro.core.api.segmentation.type.Token; import de.tudarmstadt.ukp.inception.bootstrap.BootstrapFileInputField; import de.tudarmstadt.ukp.inception.bootstrap.BootstrapModalDialog; -import de.tudarmstadt.ukp.inception.export.LayerImportExportUtils; import de.tudarmstadt.ukp.inception.project.api.ProjectService; import de.tudarmstadt.ukp.inception.schema.api.AnnotationSchemaService; import de.tudarmstadt.ukp.inception.schema.api.config.AnnotationSchemaProperties; import de.tudarmstadt.ukp.inception.schema.api.event.LayerConfigurationChangedEvent; import de.tudarmstadt.ukp.inception.schema.api.feature.FeatureSupportRegistry; import de.tudarmstadt.ukp.inception.schema.api.layer.LayerSupportRegistry; +import de.tudarmstadt.ukp.inception.schema.exporters.LayerImportExportUtils; import de.tudarmstadt.ukp.inception.support.help.DocLink; import de.tudarmstadt.ukp.inception.support.lambda.LambdaAjaxButton; import de.tudarmstadt.ukp.inception.support.lambda.LambdaAjaxFormComponentUpdatingBehavior; @@ -121,9 +117,9 @@ public class ProjectLayersPanel private @SpringBean ApplicationEventPublisherHolder applicationEventPublisherHolder; private @SpringBean AnnotationSchemaProperties annotationEditorProperties; - private LayerSelectionPane layerSelectionPane; - private FeatureSelectionForm featureSelectionForm; - private LayerDetailForm layerDetailForm; + private final LayerSelectionPane layerSelectionPane; + private final FeatureSelectionForm featureSelectionForm; + private final LayerDetailForm layerDetailForm; private final FeatureDetailForm featureDetailForm; private final ImportLayerForm importLayerForm; @@ -378,8 +374,8 @@ public ImportLayerForm(String id) private void actionImport(AjaxRequestTarget aTarget, Form aForm) { - List uploadedFiles = fileUpload.getFileUploads(); - Project project = ProjectLayersPanel.this.getModelObject(); + var uploadedFiles = fileUpload.getFileUploads(); + var project = ProjectLayersPanel.this.getModelObject(); if (isEmpty(uploadedFiles)) { error("Please choose file with layer details before uploading"); @@ -389,9 +385,10 @@ else if (isNull(project.getId())) { error("Project not yet created, please save project details!"); return; } - for (FileUpload uploadedFile : uploadedFiles) { - try (BufferedInputStream bis = IOUtils.buffer(uploadedFile.getInputStream())) { - byte[] buf = new byte[5]; + + for (var uploadedFile : uploadedFiles) { + try (var bis = IOUtils.buffer(uploadedFile.getInputStream())) { + var buf = new byte[5]; bis.mark(buf.length + 1); bis.read(buf, 0, buf.length); bis.reset(); @@ -402,7 +399,7 @@ else if (isNull(project.getId())) { importUimaTypeSystemFile(bis); } else { - User user = userRepository.getCurrentUser(); + var user = userRepository.getCurrentUser(); var layer = LayerImportExportUtils.importLayerFile(annotationService, user, project, bis); layerDetailForm.setModelObject(layer); @@ -421,8 +418,8 @@ else if (isNull(project.getId())) { private void importUimaTypeSystemFile(InputStream aIS) throws IOException, InvalidXMLException, ResourceInitializationException { - Project project = ProjectLayersPanel.this.getModelObject(); - TypeSystemDescription tsd = UIMAFramework.getXMLParser() + var project = ProjectLayersPanel.this.getModelObject(); + var tsd = UIMAFramework.getXMLParser() .parseTypeSystemDescription(new XMLInputSource(aIS, null)); annotationService.importUimaTypeSystem(project, tsd); @@ -496,11 +493,10 @@ protected CharSequence getDefaultChoice(String aSelectedValue) btnMoveDown.add(visibleWhenModelIsNotNull(overviewList)); add(btnMoveDown); - LambdaAjaxLink createButton = new LambdaAjaxLink(CID_CREATE_FEATURE, - this::actionCreateFeature); + var createButton = new LambdaAjaxLink(CID_CREATE_FEATURE, this::actionCreateFeature); createButton.add(enabledWhen(() -> layerDetailForm.getModelObject() != null && !layerDetailForm.getModelObject().isBuiltIn() - && !layerDetailForm.getModelObject().getType().equals(CHAIN_TYPE) + && !CHAIN_TYPE.equals(layerDetailForm.getModelObject().getType()) )); add(createButton); @@ -558,7 +554,7 @@ private void actionCreateFeature(AjaxRequestTarget aTarget) // cancel selection of feature list selectedFeature.setObject(null); - AnnotationFeature newFeature = new AnnotationFeature(); + var newFeature = new AnnotationFeature(); newFeature.setLayer(layerDetailForm.getModelObject()); newFeature.setProject(ProjectLayersPanel.this.getModelObject()); featureDetailForm.setDefaultModelObject(newFeature); @@ -573,21 +569,17 @@ private void actionCreateFeature(AjaxRequestTarget aTarget) private List listFeatures() { - List features = annotationService + var features = annotationService .listAnnotationFeature(layerDetailForm.getModelObject()); + if (CHAIN_TYPE.equals(layerDetailForm.getModelObject().getType()) && !layerDetailForm.getModelObject().isLinkedListBehavior()) { - List filtered = new ArrayList<>(); - for (AnnotationFeature f : features) { - if (!COREFERENCE_RELATION_FEATURE.equals(f.getName())) { - filtered.add(f); - } - } - return filtered; - } - else { - return features; + return features.stream() // + .filter(f -> !COREFERENCE_RELATION_FEATURE.equals(f.getName())) // + .toList(); } + + return features; } @Override diff --git a/inception/inception-ui-tagsets/src/main/java/de/tudarmstadt/ukp/clarin/webanno/ui/tagsets/TagSetImportPanel.java b/inception/inception-ui-tagsets/src/main/java/de/tudarmstadt/ukp/clarin/webanno/ui/tagsets/TagSetImportPanel.java index e87cf540e69..25eefac2884 100644 --- a/inception/inception-ui-tagsets/src/main/java/de/tudarmstadt/ukp/clarin/webanno/ui/tagsets/TagSetImportPanel.java +++ b/inception/inception-ui-tagsets/src/main/java/de/tudarmstadt/ukp/clarin/webanno/ui/tagsets/TagSetImportPanel.java @@ -42,8 +42,8 @@ import de.tudarmstadt.ukp.clarin.webanno.model.TagSet; import de.tudarmstadt.ukp.clarin.webanno.ui.core.settings.ProjectSettingsPanelBase; import de.tudarmstadt.ukp.inception.bootstrap.BootstrapFileInputField; -import de.tudarmstadt.ukp.inception.export.TagsetImportExportUtils; import de.tudarmstadt.ukp.inception.schema.api.AnnotationSchemaService; +import de.tudarmstadt.ukp.inception.schema.exporters.TagsetImportExportUtils; import de.tudarmstadt.ukp.inception.support.lambda.LambdaAjaxButton; import de.tudarmstadt.ukp.inception.support.wicket.WicketExceptionUtil; @@ -101,8 +101,14 @@ private void actionImport(AjaxRequestTarget aTarget, Form aForm) is.reset(); TagSet tagset; if (firstChar == '{') { - tagset = TagsetImportExportUtils.importTagsetFromJson(annotationService, - selectedProject.getObject(), is, aForm.getModelObject().overwrite); + if (aForm.getModelObject().overwrite) { + tagset = TagsetImportExportUtils.importTagSetFromJsonWithOverwrite( + selectedProject.getObject(), is, annotationService); + } + else { + tagset = TagsetImportExportUtils.importTagSetFromJson( + selectedProject.getObject(), is, annotationService); + } } else { tagset = TagsetImportExportUtils.importTagsetFromTabSeparated(annotationService, diff --git a/inception/inception-versioning/pom.xml b/inception/inception-versioning/pom.xml index 02881ff9eb6..bd813173b1c 100644 --- a/inception/inception-versioning/pom.xml +++ b/inception/inception-versioning/pom.xml @@ -65,6 +65,10 @@ de.tudarmstadt.ukp.inception.app inception-schema-api + + de.tudarmstadt.ukp.inception.app + inception-schema + de.tudarmstadt.ukp.inception.app inception-annotation-storage @@ -162,11 +166,6 @@ inception-io-text test - - de.tudarmstadt.ukp.inception.app - inception-schema - test - org.hsqldb hsqldb diff --git a/inception/inception-versioning/src/main/java/de/tudarmstadt/ukp/inception/versioning/VersioningServiceImpl.java b/inception/inception-versioning/src/main/java/de/tudarmstadt/ukp/inception/versioning/VersioningServiceImpl.java index 880d95fd05a..ab71e116205 100644 --- a/inception/inception-versioning/src/main/java/de/tudarmstadt/ukp/inception/versioning/VersioningServiceImpl.java +++ b/inception/inception-versioning/src/main/java/de/tudarmstadt/ukp/inception/versioning/VersioningServiceImpl.java @@ -19,12 +19,12 @@ import static de.tudarmstadt.ukp.inception.project.api.ProjectService.DOCUMENT_FOLDER; import static de.tudarmstadt.ukp.inception.project.api.ProjectService.PROJECT_FOLDER; +import static java.nio.charset.StandardCharsets.UTF_8; import java.io.File; import java.io.IOException; import java.io.OutputStream; import java.net.URISyntaxException; -import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; @@ -59,9 +59,9 @@ import de.tudarmstadt.ukp.inception.curation.service.CurationDocumentService; import de.tudarmstadt.ukp.inception.documents.api.DocumentService; import de.tudarmstadt.ukp.inception.documents.api.RepositoryProperties; -import de.tudarmstadt.ukp.inception.export.LayerImportExportUtils; import de.tudarmstadt.ukp.inception.project.api.event.BeforeProjectRemovedEvent; import de.tudarmstadt.ukp.inception.schema.api.AnnotationSchemaService; +import de.tudarmstadt.ukp.inception.schema.exporters.LayerImportExportUtils; import de.tudarmstadt.ukp.inception.support.json.JSONUtil; import de.tudarmstadt.ukp.inception.support.uima.WebAnnoCasUtil; @@ -283,16 +283,14 @@ private void dumpLayers(File aFile, Project aProject) throws IOException List exLayers = new ArrayList<>(); for (AnnotationLayer layer : annotationService.listAnnotationLayer(aProject)) { - ExportedAnnotationLayer exMainLayer = LayerImportExportUtils.exportLayerDetails(null, - null, layer, annotationService); + var exMainLayer = LayerImportExportUtils.exportLayerDetails(layer, annotationService); exLayers.add(exMainLayer); // If the layer is attached to another layer, then we also have to export // that, otherwise we would be missing it during re-import. if (layer.getAttachType() != null) { - AnnotationLayer attachLayer = layer.getAttachType(); - ExportedAnnotationLayer exAttachLayer = LayerImportExportUtils - .exportLayerDetails(null, null, attachLayer, annotationService); + var attachLayer = layer.getAttachType(); + var exAttachLayer = LayerImportExportUtils.exportLayerDetails(attachLayer, annotationService); exMainLayer.setAttachType( new ExportedAnnotationLayerReference(exAttachLayer.getName())); exLayers.add(exAttachLayer); @@ -300,6 +298,6 @@ private void dumpLayers(File aFile, Project aProject) throws IOException } String json = JSONUtil.toPrettyJsonString(exLayers); - Files.write(aFile.toPath(), json.getBytes(StandardCharsets.UTF_8)); + Files.write(aFile.toPath(), json.getBytes(UTF_8)); } }