test/hotspot/jtreg/runtime/cds/appcds/test-classes/Util.java
changeset 57567 b000362a89a0
parent 48403 6d4e1efac80a
child 57765 a89ec7fc99aa
equal deleted inserted replaced
57566:ad84ae073248 57567:b000362a89a0
       
     1 /*
       
     2  * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.
       
     8  *
       
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    12  * version 2 for more details (a copy is included in the LICENSE file that
       
    13  * accompanied this code).
       
    14  *
       
    15  * You should have received a copy of the GNU General Public License version
       
    16  * 2 along with this work; if not, write to the Free Software Foundation,
       
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    18  *
       
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    20  * or visit www.oracle.com if you need additional information or have any
       
    21  * questions.
       
    22  *
       
    23  */
       
    24 
       
    25 import java.io.*;
       
    26 import java.lang.reflect.*;
       
    27 import java.util.jar.*;
       
    28 
       
    29 public class Util {
       
    30     /**
       
    31      * Invoke the loader.defineClass() class method to define the class stored in clsFile,
       
    32      * with the following modification:
       
    33      * <ul>
       
    34      *  <li> All ASCII strings in the class file bytes that matches fromString will be replaced with toString.
       
    35      *       NOTE: the two strings must be the exact same length.
       
    36      * </ul>
       
    37      */
       
    38     public static Class defineModifiedClass(ClassLoader loader, File clsFile, String fromString, String toString)
       
    39         throws FileNotFoundException, IOException, NoSuchMethodException, IllegalAccessException,
       
    40                InvocationTargetException
       
    41     {
       
    42       try (DataInputStream dis = new DataInputStream(new FileInputStream(clsFile))) {
       
    43         byte[] buff = new byte[(int)clsFile.length()];
       
    44         dis.readFully(buff);
       
    45         replace(buff, fromString, toString);
       
    46 
       
    47         System.out.println("Loading from: " + clsFile + " (" + buff.length + " bytes)");
       
    48 
       
    49         Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass",
       
    50                                                                  buff.getClass(), int.class, int.class);
       
    51         defineClass.setAccessible(true);
       
    52 
       
    53         // We directly call into ClassLoader.defineClass() to define the "Super" class. Also,
       
    54         // rewrite its classfile so that it returns ___yyy___ instead of ___xxx___. Changing the
       
    55         // classfile will guarantee that this class will NOT be loaded from the CDS archive.
       
    56         Class cls = (Class)defineClass.invoke(loader, buff, new Integer(0), new Integer(buff.length));
       
    57         System.out.println("Loaded : " + cls);
       
    58 
       
    59         return cls;
       
    60       }
       
    61     }
       
    62 
       
    63     /**
       
    64      * @return the number of occurrences of the <code>from</code> string that
       
    65      * have been replaced.
       
    66      */
       
    67     public static int replace(byte buff[], String from, String to) {
       
    68         if (to.length() != from.length()) {
       
    69             throw new RuntimeException("bad strings");
       
    70         }
       
    71         byte f[] = asciibytes(from);
       
    72         byte t[] = asciibytes(to);
       
    73         byte f0 = f[0];
       
    74 
       
    75         int numReplaced = 0;
       
    76         int max = buff.length - f.length;
       
    77         for (int i=0; i<max; ) {
       
    78             if (buff[i] == f0 && replace(buff, f, t, i)) {
       
    79                 i += f.length;
       
    80                 numReplaced ++;
       
    81             } else {
       
    82                 i++;
       
    83             }
       
    84         }
       
    85         return numReplaced;
       
    86     }
       
    87 
       
    88     public static boolean replace(byte buff[], byte f[], byte t[], int i) {
       
    89         for (int x=0; x<f.length; x++) {
       
    90             if (buff[x+i] != f[x]) {
       
    91                 return false;
       
    92             }
       
    93         }
       
    94         for (int x=0; x<f.length; x++) {
       
    95             buff[x+i] = t[x];
       
    96         }
       
    97         return true;
       
    98     }
       
    99 
       
   100     static byte[] asciibytes(String s) {
       
   101         byte b[] = new byte[s.length()];
       
   102         for (int i=0; i<b.length; i++) {
       
   103             b[i] = (byte)s.charAt(i);
       
   104         }
       
   105         return b;
       
   106     }
       
   107 
       
   108     public static Class defineClassFromJAR(ClassLoader loader, File jarFile, String className)
       
   109         throws FileNotFoundException, IOException, NoSuchMethodException, IllegalAccessException,
       
   110                InvocationTargetException {
       
   111         return defineClassFromJAR(loader, jarFile, className, null, null);
       
   112     }
       
   113 
       
   114     /**
       
   115      * Invoke the loader.defineClass() class method to define the named class stored in a JAR file.
       
   116      *
       
   117      * If a class exists both in the classpath, as well as in the list of URLs of a URLClassLoader,
       
   118      * by default, the URLClassLoader will not define the class, and instead will delegate to the
       
   119      * app loader. This method is an easy way to force the class to be defined by the URLClassLoader.
       
   120      *
       
   121      * Optionally, you can modify the contents of the classfile buffer. See comments in
       
   122      * defineModifiedClass.
       
   123      */
       
   124     public static Class defineClassFromJAR(ClassLoader loader, File jarFile, String className,
       
   125                                            String fromString, String toString)
       
   126         throws FileNotFoundException, IOException, NoSuchMethodException, IllegalAccessException,
       
   127                InvocationTargetException
       
   128     {
       
   129         byte[] buff = getClassFileFromJar(jarFile, className);
       
   130 
       
   131         if (fromString != null) {
       
   132             replace(buff, fromString, toString);
       
   133         }
       
   134 
       
   135         //System.out.println("Loading from: " + ent + " (" + buff.length + " bytes)");
       
   136 
       
   137         Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass",
       
   138                                                                  buff.getClass(), int.class, int.class);
       
   139         defineClass.setAccessible(true);
       
   140         Class cls = (Class)defineClass.invoke(loader, buff, new Integer(0), new Integer(buff.length));
       
   141 
       
   142         //System.out.println("Loaded : " + cls);
       
   143         return cls;
       
   144     }
       
   145 
       
   146     public static byte[] getClassFileFromJar(File jarFile, String className) throws FileNotFoundException, IOException {
       
   147         JarFile jf = new JarFile(jarFile);
       
   148         JarEntry ent = jf.getJarEntry(className.replace('.', '/') + ".class");
       
   149 
       
   150         try (DataInputStream dis = new DataInputStream(jf.getInputStream(ent))) {
       
   151             byte[] buff = new byte[(int)ent.getSize()];
       
   152             dis.readFully(buff);
       
   153             return buff;
       
   154         }
       
   155     }
       
   156 }