All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.osjava.jardiff.Tools Maven / Gradle / Ivy

/**
 * Copyright 2012-2014 Julien Eluard and contributors
 * This project includes software developed by Julien Eluard: https://github.com/jeluard/
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.osjava.jardiff;

import org.objectweb.asm.Opcodes;

/**
 * A set of Tools which do not belong anywhere else in the API at this time.
 * This is nasty, but for now, useful.
 *
 * @author Antony Riley
 */
public final class Tools
{
    /**
     * Private constructor so this class can't be instantiated.
     */
    private Tools() {
        /* empty */
    }

    /**
     * Get the java class name given an internal class name.
     * This method currently replaces all instances of $ and / with . this
     * may not be according to the java language spec, and will almost
     * certainly fail for some inner classes.
     *
     * @param internalName The internal name of the class.
     * @return The java class name.
     */
    public static final String getClassName(String internalName) {
        final StringBuffer ret = new StringBuffer(internalName.length());
        for (int i = 0; i < internalName.length(); i++) {
            final char ch = internalName.charAt(i);
            switch (ch) {
            case '$':
            case '/':
                ret.append('.');
                break;
            default:
                ret.append(ch);
            }
        }
        return ret.toString();
    }

    private static boolean has(final int value, final int mask) {
        return (value & mask) != 0;
    }
    private static boolean not(final int value, final int mask) {
        return (value & mask) == 0;
    }

    /**
     * @deprecated Use {@link #isClassAccessChange(int, int)}.
     */
    public static boolean isAccessChange(int oldAccess, int newAccess) {
        return isClassAccessChange(oldAccess, newAccess);
    }

    /**
     * Returns whether a class's newAccess is incompatible with oldAccess
     * following Java Language Specification, Java SE 7 Edition:
     * 
    *
  • 13.4.1 abstract Classes
      *
    • If a class that was not declared abstract is changed to be declared abstract, * then pre-existing binaries that attempt to create new instances of that class * will throw either an InstantiationError at link time, * or (if a reflective method is used) an InstantiationException at run time. * Such changes break backward compatibility!
    • *
    • Changing a class that is declared abstract to no longer be declared abstract * does not break compatibility with pre-existing binaries.
    • *
  • *
  • 13.4.2 final Classes
      *
    • If a class that was not declared final is changed to be declared final, * then a VerifyError is thrown if a binary of a pre-existing subclass of this class is loaded, * because final classes can have no subclasses. * Such changes break functional backward compatibility!
    • *
    • Changing a class that is declared final to no longer be declared final * does not break compatibility with pre-existing binaries.
    • *
  • *
* * @param oldAccess * @param newAccess * @return */ public static boolean isClassAccessChange(final int oldAccess, final int newAccess) { if ( not(oldAccess, Opcodes.ACC_ABSTRACT) && has(newAccess, Opcodes.ACC_ABSTRACT) ) { return true; // 13.4.1 #1 } else if ( not(oldAccess, Opcodes.ACC_FINAL) && has(newAccess, Opcodes.ACC_FINAL) ) { return true; // 13.4.2 #1 } else { final int compatibleChanges = Opcodes.ACC_ABSTRACT | // 13.4.1 #2 Opcodes.ACC_FINAL ; // 13.4.2 #2 // FIXME Opcodes.ACC_VOLATILE ? final int oldAccess2 = oldAccess & ~compatibleChanges; final int newAccess2 = newAccess & ~compatibleChanges; return oldAccess2 != newAccess2; } } /** * Returns whether a field's newAccess is incompatible with oldAccess * following Java Language Specification, Java SE 7 Edition: *
    *
  • 13.4.9 final Fields and Constants
      *
    • If a field that was not declared final is changed to be declared final, * then it can break compatibility with pre-existing binaries that attempt to assign new values to the field.
    • *
    • Deleting the keyword final or changing the value to which a non-final field is initialized * does not break compatibility with existing binaries.
    • *
    • If a field is a constant variable (§4.12.4), * then deleting the keyword final or changing its value * will not break compatibility with pre-existing binaries by causing them not to run, * but they will not see any new value for the usage of the field unless they are recompiled. * This is true even if the usage itself is not a compile-time constant expression (§15.28). * Such changes break functional backward compatibility!
    • *
  • *
  • 13.4.10 static Fields
      *
    • If a field that is not declared private was not declared static * and is changed to be declared static, or vice versa, * then a linkage error, specifically an IncompatibleClassChangeError, * will result if the field is used by a pre-existing binary which expected a field of the other kind. * Such changes break backward compatibility!
    • *
  • *
  • 13.4.11. transient Fields
      *
    • Adding or deleting a transient modifier of a field * does not break compatibility with pre-existing binaries.
    • *
  • *
  • 13.4.11 volatile Fields (JLS 1.0)
      *
    • If a field that is not declared private was not declared volatile * and is changed to be declared volatile, or vice versa, then a linkage time error, * specifically an IncompatibleClassChangeError, may result if the field is used * by a preexisting binary that expected a field of the opposite volatility. * Such changes break backward compatibility!
    • *
  • *
* * @param oldAccess * @param newAccess * @return */ public static boolean isFieldAccessChange(final int oldAccess, final int newAccess) { if ( not(oldAccess, Opcodes.ACC_FINAL) && has(newAccess, Opcodes.ACC_FINAL) ) { return true; // 13.4.9 #1 } else { final int compatibleChanges = Opcodes.ACC_FINAL | // 13.4.9 #2 Opcodes.ACC_TRANSIENT; // 13.4.11 #1 final int oldAccess2 = oldAccess & ~compatibleChanges; final int newAccess2 = newAccess & ~compatibleChanges; return oldAccess2 != newAccess2; } } /** * Returns whether a method's newAccess is incompatible with oldAccess * following Java Language Specification, Java SE 7 Edition: *
    *
  • 13.4.16 abstract Methods
      *
    • Changing a method that is declared abstract to no longer be declared abstract * does not break compatibility with pre-existing binaries.
    • *
    • Changing a method that is not declared abstract to be declared abstract * will break compatibility with pre-existing binaries that previously invoked the method, causing an AbstractMethodError.
    • *
  • *
  • 13.4.17 final
      *
    • Changing a method that is declared final to no longer be declared final * does not break compatibility with pre-existing binaries.
    • *
    • Changing an instance method that is not declared final to be declared final * may break compatibility with existing binaries that depend on the ability to override the method.
    • *
    • Changing a class (static) method that is not declared final to be declared final * does not break compatibility with existing binaries, because the method could not have been overridden.
    • *
  • *
  • 13.4.18 native Methods
      *
    • Adding or deleting a native modifier of a method * does not break compatibility with pre-existing binaries.
    • *
  • *
  • 13.4.19 static Methods
      *
    • If a method that is not declared private is also declared static (that is, a class method) * and is changed to not be declared static (that is, to an instance method), or vice versa, * then compatibility with pre-existing binaries may be broken, resulting in a linkage time error, * namely an IncompatibleClassChangeError, if these methods are used by the pre-existing binaries. * Such changes break functional backward compatibility!
    • *
  • *
  • 13.4.20 synchronized Methods
      *
    • Adding or deleting a synchronized modifier of a method * does not break compatibility with pre-existing binaries.
    • *
  • *
  • 13.4.21 Method and Constructor Throws
      *
    • Changes to the throws clause of methods or constructors * do not break compatibility with pre-existing binaries; these clauses are checked only at compile time.
    • *
  • *
* * @param oldAccess * @param newAccess * @return */ public static boolean isMethodAccessChange(final int oldAccess, final int newAccess) { if ( not(oldAccess, Opcodes.ACC_ABSTRACT) && has(newAccess, Opcodes.ACC_ABSTRACT) ) { return true; // 13.4.16 #2 } else if ( not(oldAccess, Opcodes.ACC_FINAL) && not(oldAccess, Opcodes.ACC_STATIC) && has(newAccess, Opcodes.ACC_FINAL) ) { return true; // 13.4.17 #2 excluding and #3 } else { final int compatibleChanges = Opcodes.ACC_ABSTRACT | // 13.4.16 #1 Opcodes.ACC_FINAL | // 13.4.17 #1 Opcodes.ACC_NATIVE | // 13.4.18 #1 Opcodes.ACC_SYNCHRONIZED; // 13.4.20 #1 final int oldAccess2 = oldAccess & ~compatibleChanges; final int newAccess2 = newAccess & ~compatibleChanges; return oldAccess2 != newAccess2; } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy