diff --git a/src/main/java/org/apache/xmlbeans/Filer.java b/src/main/java/org/apache/xmlbeans/Filer.java index 5c0076366..a511e5b77 100755 --- a/src/main/java/org/apache/xmlbeans/Filer.java +++ b/src/main/java/org/apache/xmlbeans/Filer.java @@ -43,6 +43,18 @@ public interface Filer * * @throws IOException when the file can't be created */ - public Writer createSourceFile(String typename) throws IOException; + default Writer createSourceFile(String typename) throws IOException { + return createSourceFile(typename, null); + } + /** + * Creates a new binding source file (.java) and returns a writer for it. + * + * @param typename fully qualified type name + * @param sourceCodeEncoding an optional encoding used when compiling source code (can be null) + * @return a stream to write the type to + * + * @throws IOException when the file can't be created + */ + public Writer createSourceFile(String typename, String sourceCodeEncoding) throws IOException; } diff --git a/src/main/java/org/apache/xmlbeans/FilterXmlObject.java b/src/main/java/org/apache/xmlbeans/FilterXmlObject.java index b0c2cf8c9..95039f2c8 100644 --- a/src/main/java/org/apache/xmlbeans/FilterXmlObject.java +++ b/src/main/java/org/apache/xmlbeans/FilterXmlObject.java @@ -28,6 +28,7 @@ import java.util.Calendar; import java.util.Date; import java.util.List; +import java.util.zip.ZipOutputStream; /** * A FilterXmlObject delegates to some other XmlObject, which it can use as @@ -199,6 +200,10 @@ public void save(OutputStream os, XmlOptions options) throws IOException { underlyingXmlObject().save(os, options); } + public void save(ZipOutputStream zos, XmlOptions options) throws IOException { + underlyingXmlObject().save(zos, options); + } + public void save(Writer w, XmlOptions options) throws IOException { underlyingXmlObject().save(w, options); } diff --git a/src/main/java/org/apache/xmlbeans/XmlOptions.java b/src/main/java/org/apache/xmlbeans/XmlOptions.java index 5ca03f9cf..c60803037 100644 --- a/src/main/java/org/apache/xmlbeans/XmlOptions.java +++ b/src/main/java/org/apache/xmlbeans/XmlOptions.java @@ -107,6 +107,7 @@ public enum XmlOptionsKeys { SAVE_CDATA_LENGTH_THRESHOLD, SAVE_CDATA_ENTITY_COUNT_THRESHOLD, SAVE_SAX_NO_NSDECLS_IN_ATTRIBUTES, + SAVE_EXTRA_NAMESPACES, LOAD_REPLACE_DOCUMENT_ELEMENT, LOAD_STRIP_WHITESPACE, LOAD_STRIP_COMMENTS, @@ -157,7 +158,7 @@ public enum XmlOptionsKeys { XPATH_USE_SAXON, XPATH_USE_XMLBEANS, ATTRIBUTE_VALIDATION_COMPAT_MODE, - + USE_JAVA_SHORT_NAME } @@ -213,7 +214,6 @@ public boolean isSaveNamespacesFirst() { return hasOption(XmlOptionsKeys.SAVE_NAMESPACES_FIRST); } - /** * This option will cause the saver to reformat white space for easier reading. * @@ -448,6 +448,23 @@ public Map getSaveSuggestedPrefixes() { return (Map) get(XmlOptionsKeys.SAVE_SUGGESTED_PREFIXES); } + /** + * A map of hints to pass to the saver for which prefixes to use + * for which namespace URI. + * + * @param extraNamespaces a map from URIs to prefixes + * @see XmlTokenSource#save(java.io.File, XmlOptions) + * @see XmlTokenSource#xmlText(XmlOptions) + */ + public XmlOptions setSaveExtraNamespaces(Map extraNamespaces) { + return set(XmlOptionsKeys.SAVE_EXTRA_NAMESPACES, extraNamespaces); + } + + @SuppressWarnings("unchecked") + public Map getSaveExtraNamespaces() { + return (Map) get(XmlOptionsKeys.SAVE_EXTRA_NAMESPACES); + } + /** * This option causes the saver to filter a Processing Instruction * with the given target @@ -1070,6 +1087,21 @@ public boolean isCompileDownloadUrls() { return hasOption(XmlOptionsKeys.COMPILE_DOWNLOAD_URLS); } + /** + * If this option is set, then the schema compiler will use the java_short_name to generate file name + * + */ + public XmlOptions setCompileUseShortJavaName() { + return setCompileUseShortJavaName(true); + } + + public XmlOptions setCompileUseShortJavaName(boolean b) { + return set(XmlOptionsKeys.USE_JAVA_SHORT_NAME, b); + } + + public boolean isCompileUseShortJavaName() { + return hasOption(XmlOptionsKeys.USE_JAVA_SHORT_NAME); + } /** * If this option is set, then the schema compiler will permit and * ignore multiple definitions of the same component (element, attribute, diff --git a/src/main/java/org/apache/xmlbeans/XmlTokenSource.java b/src/main/java/org/apache/xmlbeans/XmlTokenSource.java index 58aef645b..374288b4a 100644 --- a/src/main/java/org/apache/xmlbeans/XmlTokenSource.java +++ b/src/main/java/org/apache/xmlbeans/XmlTokenSource.java @@ -22,6 +22,7 @@ import javax.xml.stream.XMLStreamReader; import java.io.*; +import java.util.zip.ZipOutputStream; /** * Represents a holder of XML that can return an {@link XmlCursor} @@ -170,6 +171,14 @@ public interface XmlTokenSource { */ void save(OutputStream os) throws IOException; + /** + * Writes the XML represented by this source to the given zip output stream. + * This method will save the XML declaration, including encoding information, + * with the XML. + */ + void save(ZipOutputStream os) throws IOException; + + /** * Writes the XML represented by this source to the given output. * Note that this method does not save the XML declaration, including the encoding information. @@ -336,6 +345,13 @@ public interface XmlTokenSource { */ void save(OutputStream os, XmlOptions options) throws IOException; + /** + * Writes the XML represented by this source to the given zip output stream. + * This method will save the XML declaration, including encoding information, + * with the XML. + */ + void save(ZipOutputStream os, XmlOptions options) throws IOException; + /** * Writes the XML represented by this source to the given output. * Note that this method does not save the XML declaration, including the encoding information. diff --git a/src/main/java/org/apache/xmlbeans/impl/schema/SchemaTypePool.java b/src/main/java/org/apache/xmlbeans/impl/schema/SchemaTypePool.java index 0f58fdbc4..8bbc52214 100644 --- a/src/main/java/org/apache/xmlbeans/impl/schema/SchemaTypePool.java +++ b/src/main/java/org/apache/xmlbeans/impl/schema/SchemaTypePool.java @@ -89,7 +89,17 @@ String handleForElement(SchemaGlobalElement element) { } String handle = _componentsToHandles.get(element); if (handle == null) { - handle = addUniqueHandle(element, NameUtil.upperCamelCase(element.getName().getLocalPart()) + "Element"); + if(typeSystem.isUseJavaShortName()) { + SchemaType type = element.getType(); + String javaName = type.getShortJavaName(); + if (javaName != null && !javaName.isEmpty()) { + handle = addUniqueHandle(element, NameUtil.upperCamelCase(javaName) + "Element"); + } else { + handle = addUniqueHandle(element, NameUtil.upperCamelCase(element.getName().getLocalPart()) + "Element"); + } + } else { + handle = addUniqueHandle(element, NameUtil.upperCamelCase(element.getName().getLocalPart()) + "Element"); + } } return handle; } @@ -179,7 +189,15 @@ String handleForType(SchemaType type) { if (name == null) { baseName = "Anon" + uniq + "Type"; } else { - baseName = NameUtil.upperCamelCase(name.getLocalPart()) + uniq + suffix + "Type"; + if(typeSystem.isUseJavaShortName()) { + String javaName = type.getShortJavaName(); + if (javaName == null || javaName.isEmpty()) + javaName = name.getLocalPart(); + baseName = NameUtil.upperCamelCase(javaName) + uniq + suffix + "Type"; + } + else { + baseName = NameUtil.upperCamelCase(name.getLocalPart()) + uniq + suffix + "Type"; + } } handle = addUniqueHandle(type, baseName); diff --git a/src/main/java/org/apache/xmlbeans/impl/schema/SchemaTypeSystemCompiler.java b/src/main/java/org/apache/xmlbeans/impl/schema/SchemaTypeSystemCompiler.java index 528a51a5a..1566e1049 100644 --- a/src/main/java/org/apache/xmlbeans/impl/schema/SchemaTypeSystemCompiler.java +++ b/src/main/java/org/apache/xmlbeans/impl/schema/SchemaTypeSystemCompiler.java @@ -373,14 +373,14 @@ public static boolean generateTypes(SchemaTypeSystem system, Filer filer, XmlOpt types.addAll(Arrays.asList(system.attributeTypes())); - SchemaCodePrinter printer = (options == null) ? null : options.getSchemaCodePrinter(); + SchemaCodePrinter printer = options == null ? null : options.getSchemaCodePrinter(); if (printer == null) { printer = new SchemaTypeCodePrinter(); } String indexClassName = SchemaTypeCodePrinter.indexClassForSystem(system); - try (Writer out = filer.createSourceFile(indexClassName)) { + try (Writer out = filer.createSourceFile(indexClassName, options == null ? null : options.getCharacterEncoding())) { Repackager repackager = (filer instanceof FilerImpl) ? ((FilerImpl) filer).getRepackager() : null; printer.printHolder(out, system, options, repackager); } catch (IOException e) { @@ -398,7 +398,7 @@ public static boolean generateTypes(SchemaTypeSystem system, Filer filer, XmlOpt String fjn = type.getFullJavaName(); - try (Writer writer = filer.createSourceFile(fjn)) { + try (Writer writer = filer.createSourceFile(fjn, options == null ? null : options.getCharacterEncoding())) { // Generate interface class printer.printType(writer, type, options); } catch (IOException e) { @@ -408,7 +408,7 @@ public static boolean generateTypes(SchemaTypeSystem system, Filer filer, XmlOpt fjn = type.getFullJavaImplName(); - try (Writer writer = filer.createSourceFile(fjn)) { + try (Writer writer = filer.createSourceFile(fjn, options == null ? null : options.getCharacterEncoding())) { // Generate Implementation class printer.printTypeImpl(writer, type, options); } catch (IOException e) { diff --git a/src/main/java/org/apache/xmlbeans/impl/schema/SchemaTypeSystemImpl.java b/src/main/java/org/apache/xmlbeans/impl/schema/SchemaTypeSystemImpl.java index 8d95d44f7..b104c07a4 100644 --- a/src/main/java/org/apache/xmlbeans/impl/schema/SchemaTypeSystemImpl.java +++ b/src/main/java/org/apache/xmlbeans/impl/schema/SchemaTypeSystemImpl.java @@ -162,7 +162,9 @@ public class SchemaTypeSystemImpl extends SchemaTypeLoaderBase implements Schema private Map _typeRefsByClassname = new HashMap<>(); private Set _namespaces; - + // the additional config option + private String _sourceCodeEncoding ; + private boolean _useJavaShortName; static String nameToPathString(String nameForSystem) { nameForSystem = nameForSystem.replace('.', '/'); @@ -312,7 +314,25 @@ void savePointers() { void savePointersForComponents(SchemaComponent[] components, String dir) { for (SchemaComponent component : components) { - savePointerFile(dir + QNameHelper.hexsafedir(component.getName()), _name); + if(_useJavaShortName) { + String javaName = _localHandles.handleForComponent(component); + if (javaName != null && !javaName.isEmpty()) + { + QName nameTemp = component.getName(); + String resultName; + if (nameTemp.getNamespaceURI() == null || nameTemp.getNamespaceURI().length() == 0) { + resultName = "_nons/" + QNameHelper.hexsafe(javaName); + } else { + resultName = QNameHelper.hexsafe(nameTemp.getNamespaceURI()) + "/" + + QNameHelper.hexsafe(javaName); + } + savePointerFile(dir + resultName, _name); + } else { + savePointerFile(dir + QNameHelper.hexsafedir(component.getName()), _name); + } + } else { + savePointerFile(dir + QNameHelper.hexsafedir(component.getName()), _name); + } } } @@ -411,6 +431,14 @@ SchemaContainer getContainerNonNull(String namespace) { return result; } + String getSourceCodeEncoding() { + return _sourceCodeEncoding ; + } + + Boolean isUseJavaShortName() { + return _useJavaShortName; + } + @SuppressWarnings("unchecked") private void buildContainersHelper(Map elements, BiConsumer adder) { elements.forEach((k, v) -> adder.accept(getContainerNonNull(k.getNamespaceURI()), (T) v)); @@ -615,6 +643,8 @@ public void loadFromStscState(StscState state) { _annotations = state.annotations(); _namespaces = new HashSet<>(Arrays.asList(state.getNamespaces())); _containers = state.getContainerMap(); + _useJavaShortName = state.useShortName(); + _sourceCodeEncoding = state.sourceCodeEncoding(); fixupContainers(); // Checks that data in the containers matches the lookup maps assertContainersSynchronized(); diff --git a/src/main/java/org/apache/xmlbeans/impl/schema/StscState.java b/src/main/java/org/apache/xmlbeans/impl/schema/StscState.java index 036791727..c2993be0d 100644 --- a/src/main/java/org/apache/xmlbeans/impl/schema/StscState.java +++ b/src/main/java/org/apache/xmlbeans/impl/schema/StscState.java @@ -103,6 +103,8 @@ public class StscState { private boolean _noPvr; private boolean _noAnn; private boolean _mdefAll; + private boolean _useJavaShortName; + private String _sourceCodeEncoding ; private final Set _mdefNamespaces = buildDefaultMdefNamespaces(); private EntityResolver _entityResolver; private File _schemasDir; @@ -459,6 +461,12 @@ public void setOptions(XmlOptions options) { !"true".equals(SystemProperties.getProperty("xmlbean.schemaannotations", "true")); _doingDownloads = options.isCompileDownloadUrls() || "true".equals(SystemProperties.getProperty("xmlbean.downloadurls", "false")); + _sourceCodeEncoding = options.getCharacterEncoding(); + if (_sourceCodeEncoding == null || _sourceCodeEncoding.isEmpty()) { + _sourceCodeEncoding = SystemProperties.getProperty("xmlbean.sourcecodeencoding"); + } + _useJavaShortName = options.isCompileUseShortJavaName() || + "true".equals(SystemProperties.getProperty("xmlbean.useshortjavaname", "false")); _entityResolver = options.getEntityResolver(); if (_entityResolver == null) { @@ -523,6 +531,22 @@ public boolean allowPartial() { return _allowPartial; } + /** + * An optional encoding to use when compiling generated java source file (can be null) + */ + // EXPERIMENTAL + public String sourceCodeEncoding () { + return _sourceCodeEncoding ; + } + + /** + * True if use the java_short_name to generate file name + */ + // EXPERIMENTAL + public boolean useShortName() { + return _useJavaShortName; + } + /** * Get count of recovered errors. Not for public. */ diff --git a/src/main/java/org/apache/xmlbeans/impl/store/Cursor.java b/src/main/java/org/apache/xmlbeans/impl/store/Cursor.java index 2e9956242..c32349da4 100755 --- a/src/main/java/org/apache/xmlbeans/impl/store/Cursor.java +++ b/src/main/java/org/apache/xmlbeans/impl/store/Cursor.java @@ -36,6 +36,7 @@ import java.util.Collection; import java.util.Map; import java.util.function.Supplier; +import java.util.zip.ZipOutputStream; public final class Cursor implements XmlCursor, ChangeListener { static final int ROOT = Cur.ROOT; @@ -509,6 +510,10 @@ public void _save(OutputStream os) throws IOException { _save(os, null); } + public void _save(ZipOutputStream zos) throws IOException { + _save(zos, null); + } + public void _save(Writer w) throws IOException { _save(w, null); } @@ -578,6 +583,26 @@ public void _save(OutputStream os, XmlOptions options) throws IOException { } } + public void _save(ZipOutputStream zos, XmlOptions options) throws IOException { + if (zos == null) { + throw new IllegalArgumentException("Null ZipOutputStream specified"); + } + + try (InputStream is = _newInputStream(options)) { + byte[] bytes = new byte[8192]; + + for (; ; ) { + int n = is.read(bytes); + + if (n < 0) { + break; + } + + zos.write(bytes, 0, n); + } + } + } + public void _save(Writer w, XmlOptions options) throws IOException { if (w == null) { throw new IllegalArgumentException("Null Writer specified"); @@ -1974,6 +1999,10 @@ public void save(OutputStream os) throws IOException { syncWrapIOEx(() -> _save(os)); } + public void save(ZipOutputStream zos) throws IOException { + syncWrapIOEx(() -> _save(zos)); + } + public void save(Writer w) throws IOException { syncWrapIOEx(() -> _save(w)); } @@ -2006,6 +2035,10 @@ public void save(OutputStream os, XmlOptions options) throws IOException { syncWrapIOEx(() -> _save(os, options)); } + public void save(ZipOutputStream zos, XmlOptions options) throws IOException { + syncWrapIOEx(() -> _save(zos, options)); + } + public void save(Writer w, XmlOptions options) throws IOException { syncWrapIOEx(() -> _save(w, options)); } diff --git a/src/main/java/org/apache/xmlbeans/impl/store/Saver.java b/src/main/java/org/apache/xmlbeans/impl/store/Saver.java index fac6a4400..ceb6dc99d 100755 --- a/src/main/java/org/apache/xmlbeans/impl/store/Saver.java +++ b/src/main/java/org/apache/xmlbeans/impl/store/Saver.java @@ -43,6 +43,9 @@ abstract class Saver { private final long _version; private SaveCur _cur; + + protected boolean _isTopLevelElement = true; + protected final Map _extraNamespaces; private List _ancestorNamespaces; private final Map _suggestedPrefixes; @@ -133,6 +136,8 @@ protected void syntheticNamespace(String prefix, String uri, boolean considerDef _suggestedPrefixes = options.getSaveSuggestedPrefixes(); _ancestorNamespaces = _cur.getAncestorNamespaces(); + + _extraNamespaces = options.getSaveExtraNamespaces(); } private static SaveCur createSaveCur(Cur c, XmlOptions options) { @@ -285,10 +290,12 @@ protected final boolean process() { switch (_cur.kind()) { case ROOT: { processRoot(); + _isTopLevelElement = true; break; } case ELEM: { processElement(); + _isTopLevelElement = false; break; } case -ELEM: { @@ -897,6 +904,8 @@ protected boolean emitElement(SaveCur c, List attrNames, List att emitNamespacesHelper(); } + emitExtraNamespacesHelper(); + for (int i = 0; i < attrNames.size(); i++) { emitAttrHelper(attrNames.get(i), attrValues.get(i)); } @@ -941,6 +950,17 @@ protected void emitXmlns(String prefix, String uri) { emit('"'); } + private void emitExtraNamespacesHelper() { + if (!_isTopLevelElement || null == _extraNamespaces) + return; + + for (Map.Entry nsEntry : _extraNamespaces.entrySet()) { + emit(' '); + emitXmlns(nsEntry.getKey(), nsEntry.getValue()); + } + + } + private void emitNamespacesHelper() { LinkedHashMap nsMap = new LinkedHashMap<>(); for (iterateMappings(); hasMapping(); nextMapping()) { @@ -1848,6 +1868,8 @@ protected boolean emitElement(SaveCur c, List attrNames, List att emit('<'); emitName(c.getName(), false); + emitExtraNamespacesHelper(); + for (int i = 0; i < attrNames.size(); i++) { emitAttrHelper(attrNames.get(i), attrValues.get(i)); } @@ -1897,6 +1919,15 @@ private void emitNamespacesHelper() { } } + private void emitExtraNamespacesHelper() { + if (!_isTopLevelElement || null == _extraNamespaces) + return; + for (Map.Entry nsEntry : _extraNamespaces.entrySet()) { + emit(' '); + emitXmlns(nsEntry.getKey(), nsEntry.getValue()); + } + } + private void emitAttrHelper(QName attrName, String attrValue) { emit(' '); emitName(attrName, true); @@ -2570,6 +2601,15 @@ private String getPrefixedName(QName name) { return prefix + ":" + local; } + private void emitExtraNamespacesHelper() { + if (!_isTopLevelElement || null == _extraNamespaces|| !_nsAsAttrs) + return; + for (Map.Entry nsEntry : _extraNamespaces.entrySet()) { + String prefix = nsEntry.getKey(); + _attributes.addAttribute("http://www.w3.org/2000/xmlns/", prefix, "xmlns:" + prefix , "CDATA", nsEntry.getValue()); + } + } + private void emitNamespacesHelper() { for (iterateMappings(); hasMapping(); nextMapping()) { String prefix = mappingPrefix(); @@ -2599,6 +2639,8 @@ protected boolean emitElement(SaveCur c, List attrNames, List att emitNamespacesHelper(); } + emitExtraNamespacesHelper(); + for (int i = 0; i < attrNames.size(); i++) { QName name = attrNames.get(i); diff --git a/src/main/java/org/apache/xmlbeans/impl/tool/CodeGenUtil.java b/src/main/java/org/apache/xmlbeans/impl/tool/CodeGenUtil.java index 0c30d90c3..88da95642 100644 --- a/src/main/java/org/apache/xmlbeans/impl/tool/CodeGenUtil.java +++ b/src/main/java/org/apache/xmlbeans/impl/tool/CodeGenUtil.java @@ -21,6 +21,7 @@ import java.io.*; import java.net.URI; import java.net.URISyntaxException; +import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.security.CodeSource; @@ -87,12 +88,34 @@ static private String quoteAndEscapeFilename(String filename) { * @deprecated */ public static boolean externalCompile(List srcFiles, File outdir, File[] cp, boolean debug) { - return externalCompile(srcFiles, outdir, cp, debug, DEFAULT_COMPILER, null, DEFAULT_MEM_START, DEFAULT_MEM_MAX, false, false); + return externalCompile(srcFiles, outdir, cp, debug, DEFAULT_COMPILER, null, DEFAULT_MEM_START, DEFAULT_MEM_MAX, + false, false, null); } - // KHK: temporary to avoid build break - public static boolean externalCompile(List srcFiles, File outdir, File[] cp, boolean debug, String javacPath, String memStart, String memMax, boolean quiet, boolean verbose) { - return externalCompile(srcFiles, outdir, cp, debug, javacPath, null, memStart, memMax, quiet, verbose); + /** + * Invokes javac on the generated source files in order to turn them + * into binary files in the output directory. This will return a list of + * {@code GenFile}s for all of the classes produced or null if an + * error occurred. + * + * @deprecated + */ + public static boolean externalCompile(List srcFiles, File outdir, File[] cp, boolean debug, String javacPath, String memStart, String memMax, + boolean quiet, boolean verbose) { + return externalCompile(srcFiles, outdir, cp, debug, javacPath, null, memStart, memMax, quiet, verbose, null); + } + + /** + * Invokes javac on the generated source files in order to turn them + * into binary files in the output directory. This will return a list of + * {@code GenFile}s for all of the classes produced or null if an + * error occurred. + * + * @deprecated + */ + public static boolean externalCompile(List srcFiles, File outdir, File[] cp, boolean debug, String javacPath, String memStart, String memMax, + boolean quiet, boolean verbose, String sourceCodeEncoding) { + return externalCompile(srcFiles, outdir, cp, debug, javacPath, null, memStart, memMax, quiet, verbose, sourceCodeEncoding); } /** @@ -100,8 +123,22 @@ public static boolean externalCompile(List srcFiles, File outdir, File[] c * into binary files in the output directory. This will return a list of * {@code GenFile}s for all of the classes produced or null if an * error occurred. + * + * @deprecated */ - public static boolean externalCompile(List srcFiles, File outdir, File[] cp, boolean debug, String javacPath, String genver, String memStart, String memMax, boolean quiet, boolean verbose) { + public static boolean externalCompile(List srcFiles, File outdir, File[] cp, boolean debug, String javacPath, String genver, String memStart, String memMax, + boolean quiet, boolean verbose) { + return externalCompile(srcFiles, outdir, cp, debug, javacPath, genver, memStart, memMax, quiet, verbose, null); + } + + /** + * Invokes javac on the generated source files in order to turn them + * into binary files in the output directory. This will return a list of + * {@code GenFile}s for all of the classes produced or null if an + * error occurred. + */ + public static boolean externalCompile(List srcFiles, File outdir, File[] cp, boolean debug, String javacPath, String genver, String memStart, String memMax, + boolean quiet, boolean verbose, String sourceCodeEncoding) { List args = new ArrayList<>(); File javac = findJavaTool(javacPath == null ? DEFAULT_COMPILER : javacPath); @@ -119,6 +156,11 @@ public static boolean externalCompile(List srcFiles, File outdir, File[] c cp = systemClasspath(); } + if(sourceCodeEncoding != null && !sourceCodeEncoding.isEmpty()) { + args.add("-encoding"); + args.add(sourceCodeEncoding); + } + if (cp.length > 0) { StringBuilder classPath = new StringBuilder(); // Add the output directory to the classpath. We do this so that @@ -156,10 +198,12 @@ public static boolean externalCompile(List srcFiles, File outdir, File[] c addAllJavaFiles(srcFiles, args); + final Charset charset = sourceCodeEncoding == null || sourceCodeEncoding.isEmpty() ? + StandardCharsets.ISO_8859_1 : Charset.forName(sourceCodeEncoding); File clFile = null; try { clFile = Files.createTempFile(IOUtil.getTempDir(), "javac", ".tmp").toFile(); - try (Writer fw = Files.newBufferedWriter(clFile.toPath(), StandardCharsets.ISO_8859_1)) { + try (Writer fw = Files.newBufferedWriter(clFile.toPath(), charset)) { Iterator i = args.iterator(); for (i.next(); i.hasNext(); ) { String arg = i.next(); diff --git a/src/main/java/org/apache/xmlbeans/impl/tool/Parameters.java b/src/main/java/org/apache/xmlbeans/impl/tool/Parameters.java index 9f496a0c5..8ee32c462 100644 --- a/src/main/java/org/apache/xmlbeans/impl/tool/Parameters.java +++ b/src/main/java/org/apache/xmlbeans/impl/tool/Parameters.java @@ -54,6 +54,8 @@ public class Parameters { private boolean noExt; private boolean debug; private boolean copyAnn; + private boolean useShortName; + private String sourceCodeEncoding; private boolean incrementalSrcGen; private String repackage; private List extensions = Collections.emptyList(); @@ -203,6 +205,14 @@ public boolean isNoAnn() { return noAnn; } + public boolean isUseShortName() { + return useShortName; + } + + public String getSourceCodeEncoding() { + return sourceCodeEncoding; + } + public void setNoAnn(boolean noAnn) { this.noAnn = noAnn; } @@ -239,6 +249,14 @@ public void setDebug(boolean debug) { this.debug = debug; } + public void setUseShortName(boolean useShortName) { + this.useShortName = useShortName; + } + + public void setSourceCodeEncoding(String sourceCodeEncoding) { + this.sourceCodeEncoding = sourceCodeEncoding; + } + public String getMemoryInitialSize() { return memoryInitialSize; } diff --git a/src/main/java/org/apache/xmlbeans/impl/tool/SchemaCompiler.java b/src/main/java/org/apache/xmlbeans/impl/tool/SchemaCompiler.java index 21792712c..7aefbf825 100644 --- a/src/main/java/org/apache/xmlbeans/impl/tool/SchemaCompiler.java +++ b/src/main/java/org/apache/xmlbeans/impl/tool/SchemaCompiler.java @@ -67,6 +67,8 @@ public static void printUsage() { System.out.println(" processed left-to-right, e.g. \"ALL,-GET_LIST\" exclude java.util.List getters - see XmlOptions.BeanMethod" ); System.out.println(" -repackage - repackage specification, e.g. \"org.apache.xmlbeans.metadata:mypackage.metadata\" to change the metadata directory"); System.out.println(" -copyann - copy schema annotations to javadoc (default false) - don't activate on untrusted schema sources!"); + System.out.println(" -sourcecodeencoding [encodingName] - Generate Java source code and jar package by the encoding specified by encodingName"); + System.out.println(" -usejavashortname - Generate file name using JavaShortName"); /* Undocumented feature - pass in one schema compiler extension and related parameters System.out.println(" -extension - registers a schema compiler extension"); System.out.println(" -extensionParms - specify parameters for the compiler extension"); @@ -98,11 +100,13 @@ public static void main(String[] args) { flags.add("noext"); flags.add("srconly"); flags.add("debug"); + flags.add("usejavashortname"); Set opts = new HashSet<>(); opts.add("out"); opts.add("name"); opts.add("src"); + opts.add("sourcecodeencoding"); opts.add("d"); opts.add("cp"); opts.add("compiler"); @@ -186,6 +190,8 @@ public static void main(String[] args) { boolean nojavac = (cl.getOpt("srconly") != null); boolean debug = (cl.getOpt("debug") != null); boolean copyAnn = (cl.getOpt("copyann") != null); + String sourceCodeEncoding = cl.getOpt("sourcecodeencoding"); + boolean useJavaShortName = (cl.getOpt("usejavashortname") != null); String allowmdef = cl.getOpt("allowmdef"); Set mdefNamespaces = (allowmdef == null ? Collections.emptySet() : @@ -333,6 +339,8 @@ public static void main(String[] args) { params.setNoVDoc(noVDoc); params.setNoExt(noExt); params.setDebug(debug); + params.setSourceCodeEncoding(sourceCodeEncoding); + params.setUseShortName(useJavaShortName); params.setErrorListener(err); params.setRepackage(repackage); params.setExtensions(extensions); @@ -356,7 +364,7 @@ public static void main(String[] args) { private static SchemaTypeSystem loadTypeSystem(String name, File[] xsdFiles, File[] wsdlFiles, URL[] urlFiles, File[] configFiles, File[] javaFiles, ResourceLoader cpResourceLoader, - boolean download, boolean noUpa, boolean noPvr, boolean noAnn, boolean noVDoc, boolean noExt, + boolean download, boolean noUpa, boolean noPvr, boolean noAnn, boolean noVDoc, boolean noExt, String sourceCodeEncoding, boolean useShortName, Set mdefNamespaces, File baseDir, Map sourcesToCopyMap, Collection outerErrorListener, File schemasDir, EntityResolver entResolver, File[] classpath) { XmlErrorWatcher errorListener = new XmlErrorWatcher(outerErrorListener); @@ -521,6 +529,12 @@ private static SchemaTypeSystem loadTypeSystem(String name, File[] xsdFiles, Fil if (noAnn) { opts.setCompileNoAnnotations(); } + if (sourceCodeEncoding != null ) { + opts.setCharacterEncoding(sourceCodeEncoding); + } + if (useShortName) { + opts.setCompileUseShortJavaName(); + } if (mdefNamespaces != null) { opts.setCompileMdefNamespaces(mdefNamespaces); } @@ -614,6 +628,8 @@ public static boolean compile(Parameters params) { boolean noExt = params.isNoExt(); boolean incrSrcGen = params.isIncrementalSrcGen(); boolean copyAnn = params.isCopyAnn(); + String sourceCodeEncoding = params.getSourceCodeEncoding(); + boolean useShortName = params.isUseShortName(); Collection outerErrorListener = params.getErrorListener(); Set partialMethods = params.getPartialMethods(); @@ -666,7 +682,7 @@ public static boolean compile(Parameters params) { // build the in-memory type system XmlErrorWatcher errorListener = new XmlErrorWatcher(outerErrorListener); SchemaTypeSystem system = loadTypeSystem(name, xsdFiles, wsdlFiles, urlFiles, configFiles, - javaFiles, cpResourceLoader, download, noUpa, noPvr, noAnn, noVDoc, noExt, mdefNamespaces, + javaFiles, cpResourceLoader, download, noUpa, noPvr, noAnn, noVDoc, noExt, sourceCodeEncoding, useShortName, mdefNamespaces, baseDir, sourcesToCopyMap, errorListener, schemasDir, cmdLineEntRes, classpath); if (errorListener.hasError()) { result = false; @@ -693,6 +709,8 @@ public static boolean compile(Parameters params) { options.setCompilePartialMethod(partialMethods); options.setCompileNoAnnotations(noAnn); options.setCompileAnnotationAsJavadoc(copyAnn); + options.setCharacterEncoding(sourceCodeEncoding); + options.setCompileUseShortJavaName(useShortName); // save .xsb files system.save(filer); @@ -722,7 +740,8 @@ public static boolean compile(Parameters params) { if (javaFiles != null) { sourcefiles.addAll(java.util.Arrays.asList(javaFiles)); } - if (!CodeGenUtil.externalCompile(sourcefiles, classesDir, classpath, debug, compiler, memoryInitialSize, memoryMaximumSize, quiet, verbose)) { + if (!CodeGenUtil.externalCompile(sourcefiles, classesDir, classpath, debug, compiler, null, + memoryInitialSize, memoryMaximumSize, quiet, verbose, sourceCodeEncoding)) { result = false; } diff --git a/src/main/java/org/apache/xmlbeans/impl/util/FilerImpl.java b/src/main/java/org/apache/xmlbeans/impl/util/FilerImpl.java index de5862f06..fdd8f9476 100755 --- a/src/main/java/org/apache/xmlbeans/impl/util/FilerImpl.java +++ b/src/main/java/org/apache/xmlbeans/impl/util/FilerImpl.java @@ -85,9 +85,10 @@ public OutputStream createBinaryFile(String typename) throws IOException { * Creates a new binding source file (.java) and returns a writer for it. * * @param typename fully qualified type name + * @param sourceCodeEncoding an optional encoding used when compiling source code (can be null) * @return a stream to write the type to */ - public Writer createSourceFile(String typename) throws IOException { + public Writer createSourceFile(String typename, String sourceCodeEncoding) throws IOException { if (incrSrcGen) { seenTypes.add(typename); } @@ -114,7 +115,7 @@ public Writer createSourceFile(String typename) throws IOException { return new IncrFileWriter(sourcefile, repackager); } else { return repackager == null ? - writerForFile(sourcefile) : + writerForFile(sourcefile, sourceCodeEncoding) : new RepackagingWriter(sourcefile, repackager); } } @@ -127,8 +128,10 @@ public Repackager getRepackager() { return repackager; } - private static Writer writerForFile(File f) throws IOException { - if (CHARSET == null) { + private static Writer writerForFile(File f, String sourceCodeEncoding) throws IOException { + if (sourceCodeEncoding != null) { + return Files.newBufferedWriter(f.toPath(), Charset.forName(sourceCodeEncoding)); + } else if (CHARSET == null) { return Files.newBufferedWriter(f.toPath(), StandardCharsets.ISO_8859_1); } @@ -164,7 +167,7 @@ public void close() throws IOException { if (diffs.size() > 0) { // Diffs encountered, replace the file on disk with text from the buffer - try (Writer fw = writerForFile(_file)) { + try (Writer fw = writerForFile(_file, null)) { fw.write(str); } } @@ -180,7 +183,7 @@ public RepackagingWriter(File file, Repackager repackager) { public void close() throws IOException { super.close(); - try (Writer fw = writerForFile(_file)) { + try (Writer fw = writerForFile(_file, null)) { fw.write(_repackager.repackage(getBuffer()).toString()); } } diff --git a/src/main/java/org/apache/xmlbeans/impl/values/XmlObjectBase.java b/src/main/java/org/apache/xmlbeans/impl/values/XmlObjectBase.java index e1d9de362..6e08c0d83 100644 --- a/src/main/java/org/apache/xmlbeans/impl/values/XmlObjectBase.java +++ b/src/main/java/org/apache/xmlbeans/impl/values/XmlObjectBase.java @@ -35,6 +35,7 @@ import java.util.*; import java.util.function.Function; import java.util.function.IntFunction; +import java.util.zip.ZipOutputStream; public abstract class XmlObjectBase implements TypeStoreUser, Serializable, XmlObject, SimpleValue { public static final short MAJOR_VERSION_NUMBER = (short) 1; // for serialization @@ -191,6 +192,12 @@ public void save(OutputStream os, XmlOptions options) throws IOException { } } + public void save(ZipOutputStream zos, XmlOptions options) throws IOException { + try (XmlCursor cur = newCursorForce()) { + cur.save(zos, makeInnerOptions(options)); + } + } + public void save(Writer w, XmlOptions options) throws IOException { try (XmlCursor cur = newCursorForce()) { cur.save(w, makeInnerOptions(options)); @@ -209,6 +216,10 @@ public void save(OutputStream os) throws IOException { save(os, null); } + public void save(ZipOutputStream zos) throws IOException { + save(zos, null); + } + public void save(Writer w) throws IOException { save(w, null); } diff --git a/src/test/java/compile/scomp/checkin/XmlBeansCompCheckinTests.java b/src/test/java/compile/scomp/checkin/XmlBeansCompCheckinTests.java index ce1925b84..a95af5c67 100644 --- a/src/test/java/compile/scomp/checkin/XmlBeansCompCheckinTests.java +++ b/src/test/java/compile/scomp/checkin/XmlBeansCompCheckinTests.java @@ -36,6 +36,7 @@ public class XmlBeansCompCheckinTests { private final List xm_errors = new ArrayList<>(); private final XmlOptions xm_opts = new XmlOptions(); private final List expBinType; + private final List expBinShortnameType; private final List expSrcType; public XmlBeansCompCheckinTests() { @@ -51,6 +52,18 @@ public XmlBeansCompCheckinTests() { "org/apache/xmlbeans/metadata/javaname/baz/AType.xsb" ); + expBinShortnameType = Arrays.asList( + "org/apache/xmlbeans/metadata/system/apiCompile/atypedb57type.xsb", + "org/apache/xmlbeans/metadata/system/apiCompile/elnamedocument429edoctype.xsb", + "org/apache/xmlbeans/metadata/system/apiCompile/atypeelement.xsb", + "org/apache/xmlbeans/metadata/system/apiCompile/index.xsb", + "org/apache/xmlbeans/metadata/element/http_3A_2F_2Fbaz/atypeelement.xsb", + "org/apache/xmlbeans/metadata/type/http_3A_2F_2Fbaz/atypedb57type.xsb", + "org/apache/xmlbeans/metadata/namespace/http_3A_2F_2Fbaz/xmlns.xsb", + "org/apache/xmlbeans/metadata/javaname/baz/ElNameDocument.xsb", + "org/apache/xmlbeans/metadata/javaname/baz/AType.xsb" + ); + expSrcType = Arrays.asList( "org.apache.xmlbeans.metadata.system.apiCompile.TypeSystemHolder", "baz.AType", @@ -88,6 +101,25 @@ void test_Filer_compilation() throws Exception { MatcherAssert.assertThat(f.getSrcFileVec(), is(expSrcType)); } + @Test + void test_Filer_shortname_compilation() throws Exception { + XmlObject obj1 = XmlObject.Factory.parse(FOR_XSD); + XmlObject[] schemas = new XmlObject[]{obj1}; + + TestFiler f = new TestFiler(); + xm_opts.setCompileUseShortJavaName(); + XmlBeans.compileXmlBeans("apiCompile", null, schemas, null, XmlBeans.getBuiltinTypeSystem(), f, xm_opts); + + assertTrue(f.isCreateBinaryFile(), "Binary File method not invoked"); + assertTrue(f.isCreateSourceFile(), "Source File method not invoked"); + + assertNotNull(f.getBinFileVec()); + MatcherAssert.assertThat(f.getBinFileVec(), is(expBinShortnameType)); + + assertNotNull(f.getSrcFileVec()); + MatcherAssert.assertThat(f.getSrcFileVec(), is(expSrcType)); + } + /** * Verify Partial SOM cannot be saved to file system */ diff --git a/src/test/java/compile/scomp/common/mockobj/TestFiler.java b/src/test/java/compile/scomp/common/mockobj/TestFiler.java index 1382333eb..8f6c60655 100644 --- a/src/test/java/compile/scomp/common/mockobj/TestFiler.java +++ b/src/test/java/compile/scomp/common/mockobj/TestFiler.java @@ -48,10 +48,10 @@ public OutputStream createBinaryFile(String typename) throws IOException { return impl.createBinaryFile(typename); } - public Writer createSourceFile(String typename) throws IOException { + public Writer createSourceFile(String typename, String sourceCodeEncoding) throws IOException { srcFileVec.add(typename); isCreateSourceFile = true; - return impl.createSourceFile(typename); + return impl.createSourceFile(typename, sourceCodeEncoding); } public boolean isCreateBinaryFile() { diff --git a/src/test/java/xmlobject/detailed/XmlObjectAbstractClassTest.java b/src/test/java/xmlobject/detailed/XmlObjectAbstractClassTest.java index bd0e93943..c7c370d1e 100755 --- a/src/test/java/xmlobject/detailed/XmlObjectAbstractClassTest.java +++ b/src/test/java/xmlobject/detailed/XmlObjectAbstractClassTest.java @@ -57,7 +57,7 @@ private boolean compileFile(File source) { return CodeGenUtil.externalCompile(srcFiles, dir, classpath, false, CodeGenUtil.DEFAULT_COMPILER, null, CodeGenUtil.DEFAULT_MEM_START, - CodeGenUtil.DEFAULT_MEM_MAX, false, false); + CodeGenUtil.DEFAULT_MEM_MAX, false, false, null); } /**