Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Use Jackson XML dataformat for JAXB data parser
- Update TMXWriterTest to check with system line separator It is because XML parser can automatically change /r/n into XML entity 
/n when System.lineSeparator() is /n - Update TMXReader2 to detect both "lang" and "xml:lang" some implementation return "lang" from "xml:lang" but other can return "xml:lang" as is. - as a workaround for FasterXML/jackson-modules-base#127 Add @JacksonXmlElementWrapper(useWrapping=false) for mask element for the parser of omegat.project file. Signed-off-by: Hiroshi Miura <[email protected]> diff --git a/src/gen/core/project/Masks.java b/src/gen/core/project/Masks.java index b48a97d08..9d8cafb88 100644 --- a/src/gen/core/project/Masks.java +++ b/src/gen/core/project/Masks.java @@ -1,10 +1,14 @@ package gen.core.project; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper; + import java.util.ArrayList; import java.util.List; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlElementWrapper; import javax.xml.bind.annotation.XmlType; @@ -33,6 +37,8 @@ import javax.xml.bind.annotation.XmlType; }) public class Masks { + // workaround FasterXML/jackson-modules-base#127 + @JacksonXmlElementWrapper(useWrapping=false) protected List<String> mask; /** diff --git a/src/org/omegat/convert/v20to21/Convert20to21.java b/src/org/omegat/convert/v20to21/Convert20to21.java index 6a67fd7ea..48bb5b07a 100644 --- a/src/org/omegat/convert/v20to21/Convert20to21.java +++ b/src/org/omegat/convert/v20to21/Convert20to21.java @@ -36,8 +36,8 @@ import java.io.InputStreamReader; import java.io.Serializable; import java.nio.charset.StandardCharsets; -import javax.xml.bind.JAXBContext; -import javax.xml.bind.Marshaller; +import com.fasterxml.jackson.dataformat.xml.XmlMapper; +import com.fasterxml.jackson.module.jaxb.JaxbAnnotationModule; import gen.core.filters.Files; import gen.core.filters.Filter; @@ -60,7 +60,6 @@ public final class Convert20to21 { * old config file * @param toFile * new config file - * @throws Exception */ public static void convertFiltersConfig(final File fromFile, final File toFile) throws Exception { if (!fromFile.exists()) { @@ -68,11 +67,8 @@ public final class Convert20to21 { } String c = read(fromFile); org.omegat.convert.v20to21.data.Filters filters; - XMLDecoder xmldec = new XMLDecoder(new ByteArrayInputStream(c.getBytes("UTF-8"))); - try { + try (XMLDecoder xmldec = new XMLDecoder(new ByteArrayInputStream(c.getBytes(StandardCharsets.UTF_8)))) { filters = (org.omegat.convert.v20to21.data.Filters) xmldec.readObject(); - } finally { - xmldec.close(); } Filters res = new Filters(); @@ -108,10 +104,9 @@ public final class Convert20to21 { convertTextFilter(res); convertHTMLFilter2(res); - JAXBContext ctx = JAXBContext.newInstance(Filters.class); - Marshaller m = ctx.createMarshaller(); - m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); - m.marshal(res, toFile); + XmlMapper mapper = new XmlMapper(); + mapper.registerModule(new JaxbAnnotationModule()); + mapper.writeValue(toFile, res); } /** diff --git a/src/org/omegat/core/statistics/StatsResult.java b/src/org/omegat/core/statistics/StatsResult.java index d1192558c..d79e8faf5 100644 --- a/src/org/omegat/core/statistics/StatsResult.java +++ b/src/org/omegat/core/statistics/StatsResult.java @@ -38,14 +38,17 @@ import java.util.Locale; import java.util.Set; import java.util.TimeZone; -import javax.xml.bind.JAXB; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.MapperFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SequenceWriter; +import com.fasterxml.jackson.dataformat.xml.XmlMapper; +import com.fasterxml.jackson.module.jaxb.JaxbAnnotationModule; import org.omegat.util.OStrings; import org.omegat.util.StaticUtils; import org.omegat.util.gui.TextUtil; @@ -248,11 +251,12 @@ public class StatsResult { * @return XML expression of stats data as String. */ @JsonIgnore - public String getXmlData() { + public String getXmlData() throws JsonProcessingException { setDate(); - StringWriter result = new StringWriter(); - JAXB.marshal(this, result); - return result.toString(); + XmlMapper mapper = new XmlMapper(); + mapper.registerModule(new JaxbAnnotationModule()); + mapper.enable(MapperFeature.USE_WRAPPER_NAME_AS_PROPERTY_NAME); + return mapper.writeValueAsString(this); } private void setDate() { diff --git a/src/org/omegat/filters2/master/FilterMaster.java b/src/org/omegat/filters2/master/FilterMaster.java index aa2f7eab7..0dc802536 100644 --- a/src/org/omegat/filters2/master/FilterMaster.java +++ b/src/org/omegat/filters2/master/FilterMaster.java @@ -47,10 +47,8 @@ import java.util.Map; import java.util.TreeMap; import java.util.regex.Pattern; -import javax.xml.bind.JAXBContext; -import javax.xml.bind.Marshaller; -import javax.xml.bind.Unmarshaller; - +import com.fasterxml.jackson.dataformat.xml.XmlMapper; +import com.fasterxml.jackson.module.jaxb.JaxbAnnotationModule; import org.apache.commons.io.FileUtils; import org.omegat.filters2.AbstractFilter; import org.omegat.filters2.FilterContext; @@ -88,8 +86,6 @@ public class FilterMaster { /** name of the filter configuration file */ public static final String FILE_FILTERS = "filters.xml"; - private static final JAXBContext CONFIG_CTX; - /** * There was no version of file filters support (1.4.5 Beta 1 -- 1.6.0 RC12). */ @@ -108,14 +104,6 @@ public class FilterMaster { /** Classes of all filters. */ static List<Class<?>> filtersClasses = Collections.emptyList(); - static { - try { - CONFIG_CTX = JAXBContext.newInstance(Filters.class); - } catch (Exception ex) { - throw new ExceptionInInitializerError(ex); - } - } - public static void setFilterClasses(List<Class<?>> classes) { filtersClasses = new ArrayList<>(classes); } @@ -437,8 +425,8 @@ public class FilterMaster { } Filters result; try { - Unmarshaller unm = CONFIG_CTX.createUnmarshaller(); - result = (Filters) unm.unmarshal(configFile); + XmlMapper mapper = new XmlMapper(); + result = mapper.readValue(configFile, Filters.class); } catch (Exception e) { Log.logErrorRB("FILTERMASTER_ERROR_LOADING_FILTERS_CONFIG"); Log.log(e); @@ -459,13 +447,13 @@ public class FilterMaster { */ public static void saveConfig(Filters config, File configFile) throws IOException { if (config == null) { - configFile.delete(); + boolean ignored = configFile.delete(); return; } try { - Marshaller m = CONFIG_CTX.createMarshaller(); - m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); - m.marshal(config, configFile); + XmlMapper mapper = new XmlMapper(); + mapper.registerModule(new JaxbAnnotationModule()); + mapper.writeValue(configFile, config); } catch (Exception e) { Log.logErrorRB("FILTERMASTER_ERROR_SAVING_FILTERS_CONFIG"); Log.log(e); @@ -713,7 +701,7 @@ public class FilterMaster { /** * Clone one filter's config for editing. * - * @param f + * @param filter * one filter's config * @return new config instance */ @@ -736,8 +724,8 @@ public class FilterMaster { /** * Clone one filter's instance config for editing. * - * @param f - * new filter's instance config + * @param files + * new filter's instance config file * @return new config instance */ private static Files cloneFiles(Files files) { diff --git a/src/org/omegat/util/ProjectFileStorage.java b/src/org/omegat/util/ProjectFileStorage.java index 08a72754a..a19634210 100644 --- a/src/org/omegat/util/ProjectFileStorage.java +++ b/src/org/omegat/util/ProjectFileStorage.java @@ -31,17 +31,16 @@ package org.omegat.util; -import java.io.ByteArrayInputStream; import java.io.File; import java.nio.file.Path; import java.nio.file.Paths; import java.util.List; -import javax.xml.bind.JAXBContext; -import javax.xml.bind.Marshaller; - +import com.fasterxml.jackson.dataformat.xml.XmlMapper; +import com.fasterxml.jackson.module.jaxb.JaxbAnnotationModule; import org.apache.commons.io.FileUtils; import org.apache.commons.lang.StringUtils; + import org.omegat.core.data.ProjectProperties; import org.omegat.filters2.TranslationException; import org.omegat.filters2.master.PluginUtils; @@ -71,21 +70,14 @@ public final class ProjectFileStorage { */ public static final String DEFAULT_FOLDER_MARKER = "__DEFAULT__"; - private static final JAXBContext CONTEXT; - static { - try { - CONTEXT = JAXBContext.newInstance(Omegat.class); - } catch (Exception ex) { - throw new ExceptionInInitializerError(ex); - } - } - public static Omegat parseProjectFile(File file) throws Exception { return parseProjectFile(FileUtils.readFileToByteArray(file)); } public static Omegat parseProjectFile(byte[] projectFile) throws Exception { - return (Omegat) CONTEXT.createUnmarshaller().unmarshal(new ByteArrayInputStream(projectFile)); + XmlMapper mapper = new XmlMapper(); + mapper.registerModule(new JaxbAnnotationModule()); + return mapper.readValue(projectFile, Omegat.class); } /** @@ -238,9 +230,9 @@ public final class ProjectFileStorage { om.getProject().getRepositories().getRepository().addAll(props.getRepositories()); } - Marshaller m = CONTEXT.createMarshaller(); - m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); - m.marshal(om, outFile); + XmlMapper mapper = new XmlMapper(); + mapper.registerModule(new JaxbAnnotationModule()); + mapper.writeValue(outFile, om); } private static String normalizeLoadedPath(String path, String defaultValue) { diff --git a/src/org/omegat/util/TMXReader2.java b/src/org/omegat/util/TMXReader2.java index 28865b168..51e8130cf 100644 --- a/src/org/omegat/util/TMXReader2.java +++ b/src/org/omegat/util/TMXReader2.java @@ -62,7 +62,6 @@ import javax.xml.stream.events.XMLEvent; import org.apache.commons.io.input.XmlStreamReader; import org.xml.sax.EntityResolver; import org.xml.sax.InputSource; -import org.xml.sax.SAXException; /** * Helper for read TMX files, using StAX. @@ -276,7 +275,7 @@ public class TMXReader2 { // find 'lang' or 'xml:lang' attribute for (Iterator<?> it = element.getAttributes(); it.hasNext();) { Attribute a = (Attribute) it.next(); - if ("lang".equals(a.getName().getLocalPart())) { + if ("lang".equals(a.getName().getLocalPart()) || "xml:lang".equals(a.getName().getLocalPart())) { tuv.lang = a.getValue(); break; } @@ -681,7 +680,7 @@ public class TMXReader2 { } public static final EntityResolver TMX_DTD_RESOLVER = new EntityResolver() { - public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException { + public InputSource resolveEntity(String publicId, String systemId) { if (systemId.endsWith("tmx11.dtd")) { return new InputSource(TMXReader2.class.getResourceAsStream("/schemas/tmx11.dtd")); } else if (systemId.endsWith("tmx14.dtd")) { diff --git a/src/org/omegat/util/TMXWriter2.java b/src/org/omegat/util/TMXWriter2.java index 1d4cc7bf9..c7fb42697 100644 --- a/src/org/omegat/util/TMXWriter2.java +++ b/src/org/omegat/util/TMXWriter2.java @@ -30,10 +30,10 @@ package org.omegat.util; import java.io.BufferedOutputStream; import java.io.File; -import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.nio.charset.StandardCharsets; +import java.nio.file.Files; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; @@ -66,7 +66,7 @@ public class TMXWriter2 implements AutoCloseable { public static final String PROP_ID = "id"; - private static final XMLOutputFactory FACTORY; + private final XMLOutputFactory factory; private final OutputStream out; private final XMLStreamWriter xml; @@ -82,10 +82,6 @@ public class TMXWriter2 implements AutoCloseable { */ private final SimpleDateFormat tmxDateFormat; - static { - FACTORY = XMLOutputFactory.newInstance(); - } - /** * * @param file to write TMX entries. @@ -100,9 +96,10 @@ public class TMXWriter2 implements AutoCloseable { boolean sentenceSegmentingEnabled, boolean levelTwo, boolean forceValidTMX) throws Exception { this.levelTwo = levelTwo; this.forceValidTMX = forceValidTMX; + factory = XMLOutputFactory.newInstance(); - out = new BufferedOutputStream(new FileOutputStream(file)); - xml = FACTORY.createXMLStreamWriter(out, StandardCharsets.UTF_8.name()); + out = new BufferedOutputStream(Files.newOutputStream(file.toPath())); + xml = factory.createXMLStreamWriter(out, StandardCharsets.UTF_8.name()); xml.writeStartDocument(StandardCharsets.UTF_8.name(), "1.0"); xml.writeCharacters(lineSeparator); diff --git a/test/src/org/omegat/util/TMXWriterTest.java b/test/src/org/omegat/util/TMXWriterTest.java index d05fa218b..7471eca5b 100644 --- a/test/src/org/omegat/util/TMXWriterTest.java +++ b/test/src/org/omegat/util/TMXWriterTest.java @@ -28,9 +28,10 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import java.io.File; -import java.io.FileInputStream; import java.io.InputStreamReader; import java.io.Reader; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; import java.util.ArrayList; import java.util.List; @@ -50,11 +51,12 @@ import org.custommonkey.xmlunit.XMLUnit; import org.junit.After; import org.junit.Before; import org.junit.Test; +import org.w3c.dom.Document; +import org.w3c.dom.Node; + import org.omegat.core.data.ProjectProperties; import org.omegat.core.data.RealProjectTest; import org.omegat.filters.TestFilterBase; -import org.w3c.dom.Document; -import org.w3c.dom.Node; /** * @author Alex Buloichik @@ -158,35 +160,25 @@ public class TMXWriterTest extends TestFilterBase { @test public void testEOLwrite() throws Exception { String eol = TMXWriter2.lineSeparator; - try { - TMXWriter2.lineSeparator = "\r\n"; - - TMXWriter2 wr = new TMXWriter2(outFile, new Language("en-US"), new Language("be-BY"), false, - true, false); - wr.writeEntry("source", "tar\nget", RealProjectTest.createEmptyTMXEntry(), null); - wr.close(); - - StringBuilder text = new StringBuilder(); - try (Reader rd = new InputStreamReader(new FileInputStream(outFile), "UTF-8")) { - char[] buffer = new char[512]; - while (true) { - int len = rd.read(buffer); - if (len < 0) { - break; - } - text.append(buffer, 0, len); + TMXWriter2 wr = new TMXWriter2(outFile, new Language("en-US"), new Language("be-BY"), false, + true, false); + wr.writeEntry("source", "tar\nget", RealProjectTest.createEmptyTMXEntry(), null); + wr.close(); + + StringBuilder text = new StringBuilder(); + try (Reader rd = new InputStreamReader(Files.newInputStream(outFile.toPath()), StandardCharsets.UTF_8)) { + char[] buffer = new char[512]; + while (true) { + int len = rd.read(buffer); + if (len < 0) { + break; } + text.append(buffer, 0, len); } - assertTrue(text.toString().contains("tar\r\nget")); - - final List<String> trs = new ArrayList<String>(); - load(null, trs, true, false); - assertTrue(trs.get(0).contains("tar\nget")); - } finally { - TMXWriter2.lineSeparator = eol; } + assertTrue(text.toString().contains("tar" + eol + "get")); - final List<String> trs = new ArrayList<String>(); + final List<String> trs = new ArrayList<>(); load(null, trs, true, false); assertTrue(trs.get(0).contains("tar\nget")); }
- Loading branch information