Path: blob/master/test/jdk/java/io/Serializable/failureAtomicity/FailureAtomicity.java
41153 views
/*1* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/*24* @test25* @bug 807147426* @summary Better failure atomicity for default read object.27* @modules jdk.compiler28* @library /test/lib29* @build jdk.test.lib.Platform30* jdk.test.lib.util.FileUtils31* @compile FailureAtomicity.java SerialRef.java32* @run main failureAtomicity.FailureAtomicity33*/3435package failureAtomicity;3637import java.io.ByteArrayInputStream;38import java.io.ByteArrayOutputStream;39import java.io.File;40import java.io.IOException;41import java.io.InputStream;42import java.io.ObjectInputStream;43import java.io.ObjectOutputStream;44import java.io.ObjectStreamClass;45import java.io.UncheckedIOException;46import java.lang.reflect.Constructor;47import java.net.URL;48import java.net.URLClassLoader;49import java.nio.file.Files;50import java.nio.file.Path;51import java.nio.file.Paths;52import java.util.ArrayList;53import java.util.Arrays;54import java.util.List;55import java.util.function.BiConsumer;56import java.util.stream.Collectors;57import javax.tools.JavaCompiler;58import javax.tools.JavaFileObject;59import javax.tools.StandardJavaFileManager;60import javax.tools.StandardLocation;61import javax.tools.ToolProvider;62import jdk.test.lib.util.FileUtils;6364@SuppressWarnings("unchecked")65public class FailureAtomicity {66static final Path TEST_SRC = Paths.get(System.getProperty("test.src", "."));67static final Path TEST_CLASSES = Paths.get(System.getProperty("test.classes", "."));68static final Path fooTemplate = TEST_SRC.resolve("Foo.template");69static final Path barTemplate = TEST_SRC.resolve("Bar.template");7071static final String[] PKGS = { "a.b.c", "x.y.z" };7273public static void main(String[] args) throws Exception {74test_Foo();75test_BadFoo(); // 'Bad' => incompatible type; cannot be "fully" deserialized76test_FooWithReadObject();77test_BadFooWithReadObject();7879test_Foo_Bar();80test_Foo_BadBar();81test_BadFoo_Bar();82test_BadFoo_BadBar();83test_Foo_BarWithReadObject();84test_Foo_BadBarWithReadObject();85test_BadFoo_BarWithReadObject();86test_BadFoo_BadBarWithReadObject();87test_FooWithReadObject_Bar();88test_FooWithReadObject_BadBar();89test_BadFooWithReadObject_Bar();90test_BadFooWithReadObject_BadBar();91}9293static final BiConsumer<Object,Object> FOO_FIELDS_EQUAL = (a,b) -> {94try {95int aPrim = a.getClass().getField("fooPrim").getInt(a);96int bPrim = b.getClass().getField("fooPrim").getInt(b);97if (aPrim != bPrim)98throw new AssertionError("Not equal: (" + aPrim + "!=" + bPrim99+ "), in [" + a + "] [" + b + "]");100Object aRef = a.getClass().getField("fooRef").get(a);101Object bRef = b.getClass().getField("fooRef").get(b);102if (!aRef.equals(bRef))103throw new RuntimeException("Not equal: (" + aRef + "!=" + bRef104+ "), in [" + a + "] [" + b + "]");105} catch (NoSuchFieldException | IllegalAccessException x) {106throw new InternalError(x);107}108};109static final BiConsumer<Object,Object> FOO_FIELDS_DEFAULT = (ignore,b) -> {110try {111int aPrim = b.getClass().getField("fooPrim").getInt(b);112if (aPrim != 0)113throw new AssertionError("Expected 0, got:" + aPrim114+ ", in [" + b + "]");115Object aRef = b.getClass().getField("fooRef").get(b);116if (aRef != null)117throw new RuntimeException("Expected null, got:" + aRef118+ ", in [" + b + "]");119} catch (NoSuchFieldException | IllegalAccessException x) {120throw new InternalError(x);121}122};123static final BiConsumer<Object,Object> BAR_FIELDS_EQUAL = (a,b) -> {124try {125long aPrim = a.getClass().getField("barPrim").getLong(a);126long bPrim = b.getClass().getField("barPrim").getLong(b);127if (aPrim != bPrim)128throw new AssertionError("Not equal: (" + aPrim + "!=" + bPrim129+ "), in [" + a + "] [" + b + "]");130Object aRef = a.getClass().getField("barRef").get(a);131Object bRef = b.getClass().getField("barRef").get(b);132if (!aRef.equals(bRef))133throw new RuntimeException("Not equal: (" + aRef + "!=" + bRef134+ "), in [" + a + "] [" + b + "]");135} catch (NoSuchFieldException | IllegalAccessException x) {136throw new InternalError(x);137}138};139static final BiConsumer<Object,Object> BAR_FIELDS_DEFAULT = (ignore,b) -> {140try {141long aPrim = b.getClass().getField("barPrim").getLong(b);142if (aPrim != 0L)143throw new AssertionError("Expected 0, got:" + aPrim144+ ", in [" + b + "]");145Object aRef = b.getClass().getField("barRef").get(b);146if (aRef != null)147throw new RuntimeException("Expected null, got:" + aRef148+ ", in [" + b + "]");149} catch (NoSuchFieldException | IllegalAccessException x) {150throw new InternalError(x);151}152};153154static void test_Foo() {155testFoo("Foo", "String", false, false, FOO_FIELDS_EQUAL); }156static void test_BadFoo() {157testFoo("BadFoo", "byte[]", true, false, FOO_FIELDS_DEFAULT); }158static void test_FooWithReadObject() {159testFoo("FooWithReadObject", "String", false, true, FOO_FIELDS_EQUAL); }160static void test_BadFooWithReadObject() {161testFoo("BadFooWithReadObject", "byte[]", true, true, FOO_FIELDS_DEFAULT); }162163static void testFoo(String testName, String xyzZebraType,164boolean expectCCE, boolean withReadObject,165BiConsumer<Object,Object>... resultCheckers) {166System.out.println("\nTesting " + testName);167try {168Path testRoot = testDir(testName);169Path srcRoot = Files.createDirectory(testRoot.resolve("src"));170List<Path> srcFiles = new ArrayList<>();171srcFiles.add(createSrc(PKGS[0], fooTemplate, srcRoot, "String", withReadObject));172srcFiles.add(createSrc(PKGS[1], fooTemplate, srcRoot, xyzZebraType, withReadObject));173174Path build = Files.createDirectory(testRoot.resolve("build"));175javac(build, srcFiles);176177URLClassLoader loader = new URLClassLoader(new URL[]{ build.toUri().toURL() },178FailureAtomicity.class.getClassLoader());179Class<?> fooClass = Class.forName(PKGS[0] + ".Foo", true, loader);180Constructor<?> ctr = fooClass.getConstructor(181new Class<?>[]{int.class, String.class, String.class});182Object abcFoo = ctr.newInstance(5, "chegar", "zebra");183184try {185toOtherPkgInstance(abcFoo, loader);186if (expectCCE)187throw new AssertionError("Expected CCE not thrown");188} catch (ClassCastException e) {189if (!expectCCE)190throw new AssertionError("UnExpected CCE: " + e);191}192193Object deserialInstance = failureAtomicity.SerialRef.obj;194195System.out.println("abcFoo: " + abcFoo);196System.out.println("deserialInstance: " + deserialInstance);197198for (BiConsumer<Object, Object> rc : resultCheckers)199rc.accept(abcFoo, deserialInstance);200} catch (IOException x) {201throw new UncheckedIOException(x);202} catch (ReflectiveOperationException x) {203throw new InternalError(x);204}205}206207static void test_Foo_Bar() {208testFooBar("Foo_Bar", "String", "String", false, false, false,209FOO_FIELDS_EQUAL, BAR_FIELDS_EQUAL);210}211static void test_Foo_BadBar() {212testFooBar("Foo_BadBar", "String", "byte[]", true, false, false,213FOO_FIELDS_DEFAULT, BAR_FIELDS_DEFAULT);214}215static void test_BadFoo_Bar() {216testFooBar("BadFoo_Bar", "byte[]", "String", true, false, false,217FOO_FIELDS_DEFAULT, BAR_FIELDS_DEFAULT);218}219static void test_BadFoo_BadBar() {220testFooBar("BadFoo_BadBar", "byte[]", "byte[]", true, false, false,221FOO_FIELDS_DEFAULT, BAR_FIELDS_DEFAULT);222}223static void test_Foo_BarWithReadObject() {224testFooBar("Foo_BarWithReadObject", "String", "String", false, false, true,225FOO_FIELDS_EQUAL, BAR_FIELDS_EQUAL);226}227static void test_Foo_BadBarWithReadObject() {228testFooBar("Foo_BadBarWithReadObject", "String", "byte[]", true, false, true,229FOO_FIELDS_EQUAL, BAR_FIELDS_DEFAULT);230}231static void test_BadFoo_BarWithReadObject() {232testFooBar("BadFoo_BarWithReadObject", "byte[]", "String", true, false, true,233FOO_FIELDS_DEFAULT, BAR_FIELDS_DEFAULT);234}235static void test_BadFoo_BadBarWithReadObject() {236testFooBar("BadFoo_BadBarWithReadObject", "byte[]", "byte[]", true, false, true,237FOO_FIELDS_DEFAULT, BAR_FIELDS_DEFAULT);238}239240static void test_FooWithReadObject_Bar() {241testFooBar("FooWithReadObject_Bar", "String", "String", false, true, false,242FOO_FIELDS_EQUAL, BAR_FIELDS_EQUAL);243}244static void test_FooWithReadObject_BadBar() {245testFooBar("FooWithReadObject_BadBar", "String", "byte[]", true, true, false,246FOO_FIELDS_EQUAL, BAR_FIELDS_DEFAULT);247}248static void test_BadFooWithReadObject_Bar() {249testFooBar("BadFooWithReadObject_Bar", "byte[]", "String", true, true, false,250FOO_FIELDS_DEFAULT, BAR_FIELDS_DEFAULT);251}252static void test_BadFooWithReadObject_BadBar() {253testFooBar("BadFooWithReadObject_BadBar", "byte[]", "byte[]", true, true, false,254FOO_FIELDS_DEFAULT, BAR_FIELDS_DEFAULT);255}256257static void testFooBar(String testName, String xyzFooZebraType,258String xyzBarZebraType, boolean expectCCE,259boolean fooWithReadObject, boolean barWithReadObject,260BiConsumer<Object,Object>... resultCheckers) {261System.out.println("\nTesting " + testName);262try {263Path testRoot = testDir(testName);264Path srcRoot = Files.createDirectory(testRoot.resolve("src"));265List<Path> srcFiles = new ArrayList<>();266srcFiles.add(createSrc(PKGS[0], fooTemplate, srcRoot, "String",267fooWithReadObject, "String"));268srcFiles.add(createSrc(PKGS[1], fooTemplate, srcRoot, xyzFooZebraType,269fooWithReadObject, xyzFooZebraType));270srcFiles.add(createSrc(PKGS[0], barTemplate, srcRoot, "String",271barWithReadObject, "String"));272srcFiles.add(createSrc(PKGS[1], barTemplate, srcRoot, xyzBarZebraType,273barWithReadObject, xyzFooZebraType));274275Path build = Files.createDirectory(testRoot.resolve("build"));276javac(build, srcFiles);277278URLClassLoader loader = new URLClassLoader(new URL[]{ build.toUri().toURL() },279FailureAtomicity.class.getClassLoader());280Class<?> fooClass = Class.forName(PKGS[0] + ".Bar", true, loader);281Constructor<?> ctr = fooClass.getConstructor(282new Class<?>[]{int.class, String.class, String.class,283long.class, String.class, String.class});284Object abcBar = ctr.newInstance( 5, "chegar", "zebraFoo", 111L, "aBar", "zebraBar");285286try {287toOtherPkgInstance(abcBar, loader);288if (expectCCE)289throw new AssertionError("Expected CCE not thrown");290} catch (ClassCastException e) {291if (!expectCCE)292throw new AssertionError("UnExpected CCE: " + e);293}294295Object deserialInstance = failureAtomicity.SerialRef.obj;296297System.out.println("abcBar: " + abcBar);298System.out.println("deserialInstance: " + deserialInstance);299300for (BiConsumer<Object, Object> rc : resultCheckers)301rc.accept(abcBar, deserialInstance);302} catch (IOException x) {303throw new UncheckedIOException(x);304} catch (ReflectiveOperationException x) {305throw new InternalError(x);306}307}308309static Path testDir(String name) throws IOException {310Path testRoot = Paths.get("FailureAtomicity-" + name);311if (Files.exists(testRoot))312FileUtils.deleteFileTreeWithRetry(testRoot);313Files.createDirectory(testRoot);314return testRoot;315}316317static String platformPath(String p) { return p.replace("/", File.separator); }318static String binaryName(String name) { return name.replace(".", "/"); }319static String condRemove(String line, String pattern, boolean hasReadObject) {320if (hasReadObject) { return line.replaceAll(pattern, ""); }321else { return line; }322}323static String condReplace(String line, String... zebraFooType) {324if (zebraFooType.length == 1) {325return line.replaceAll("\\$foo_zebra_type", zebraFooType[0]);326} else { return line; }327}328static String nameFromTemplate(Path template) {329return template.getFileName().toString().replaceAll(".template", "");330}331332static Path createSrc(String pkg, Path srcTemplate, Path srcRoot,333String zebraType, boolean hasReadObject,334String... zebraFooType)335throws IOException336{337Path srcDst = srcRoot.resolve(platformPath(binaryName(pkg)));338Files.createDirectories(srcDst);339Path srcFile = srcDst.resolve(nameFromTemplate(srcTemplate) + ".java");340341List<String> lines = Files.lines(srcTemplate)342.map(s -> s.replaceAll("\\$package", pkg))343.map(s -> s.replaceAll("\\$zebra_type", zebraType))344.map(s -> condReplace(s, zebraFooType))345.map(s -> condRemove(s, "//\\$has_readObject", hasReadObject))346.collect(Collectors.toList());347Files.write(srcFile, lines);348return srcFile;349}350351static void javac(Path dest, List<Path> sourceFiles) throws IOException {352JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();353try (StandardJavaFileManager fileManager =354compiler.getStandardFileManager(null, null, null)) {355List<File> files = sourceFiles.stream()356.map(p -> p.toFile())357.collect(Collectors.toList());358Iterable<? extends JavaFileObject> compilationUnits =359fileManager.getJavaFileObjectsFromFiles(files);360fileManager.setLocation(StandardLocation.CLASS_OUTPUT,361Arrays.asList(dest.toFile()));362fileManager.setLocation(StandardLocation.CLASS_PATH,363Arrays.asList(TEST_CLASSES.toFile()));364JavaCompiler.CompilationTask task = compiler365.getTask(null, fileManager, null, null, null, compilationUnits);366boolean passed = task.call();367if (!passed)368throw new RuntimeException("Error compiling " + files);369}370}371372static Object toOtherPkgInstance(Object obj, ClassLoader loader)373throws IOException, ClassNotFoundException374{375byte[] bytes = serialize(obj);376bytes = replacePkg(bytes);377return deserialize(bytes, loader);378}379380@SuppressWarnings("deprecation")381static byte[] replacePkg(byte[] bytes) {382String str = new String(bytes, 0);383str = str.replaceAll(PKGS[0], PKGS[1]);384str.getBytes(0, bytes.length, bytes, 0);385return bytes;386}387388static byte[] serialize(Object obj) throws IOException {389try (ByteArrayOutputStream baos = new ByteArrayOutputStream();390ObjectOutputStream out = new ObjectOutputStream(baos);) {391out.writeObject(obj);392return baos.toByteArray();393}394}395396static Object deserialize(byte[] data, ClassLoader l)397throws IOException, ClassNotFoundException398{399return new WithLoaderObjectInputStream(new ByteArrayInputStream(data), l)400.readObject();401}402403static class WithLoaderObjectInputStream extends ObjectInputStream {404final ClassLoader loader;405WithLoaderObjectInputStream(InputStream is, ClassLoader loader)406throws IOException407{408super(is);409this.loader = loader;410}411@Override412protected Class<?> resolveClass(ObjectStreamClass desc)413throws IOException, ClassNotFoundException {414try {415return super.resolveClass(desc);416} catch (ClassNotFoundException x) {417String name = desc.getName();418return Class.forName(name, false, loader);419}420}421}422}423424425