Saturday, April 16, 2016

How EventBus finds subscriber methods

private void findUsingReflectionInSingleClass(FindState findState) {
    Method[] methods;    try {
        // This is faster than getMethods, especially when subscribers are fat classes like Activities        methods = findState.clazz.getDeclaredMethods();    } catch (Throwable th) {
        // Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149        methods = findState.clazz.getMethods();        findState.skipSuperClasses = true;    }
    for (Method method : methods) {
        int modifiers = method.getModifiers();        if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
            Class<?>[] parameterTypes = method.getParameterTypes();            if (parameterTypes.length == 1) {
                Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);                if (subscribeAnnotation != null) {
                    Class<?> eventType = parameterTypes[0];                    if (findState.checkAdd(method, eventType)) {
                        ThreadMode threadMode = subscribeAnnotation.threadMode();                        findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,                                subscribeAnnotation.priority(), subscribeAnnotation.sticky()));                    }
                }
            } else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
                String methodName = method.getDeclaringClass().getName() + "." + method.getName();                throw new EventBusException("@Subscribe method " + methodName +
                        "must have exactly 1 parameter but has " + parameterTypes.length);            }
        } else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
            String methodName = method.getDeclaringClass().getName() + "." + method.getName();            throw new EventBusException(methodName +
                    " is a illegal @Subscribe method: must be public, non-static, and non-abstract");        }
    }
}

Saturday, March 12, 2016

Using Gradle to disassembles classes into bytecode format in a java project

apply plugin: 'java'import groovy.io.FileType

repositories {
    mavenCentral()
}



dependencies {
    testCompile 'junit:junit:4.12'    testCompile 'org.mockito:mockito-core:1.10.8'
}



task generateBytecode {
    dependsOn compileJava    doLast {
        readClassFiles()
    }
}


private void readClassFiles() {
    def list = []
    File srcDir = sourceSets.main.output.classesDir

    if (srcDir != null) {
        // iterate through all files in the build/classes directory        srcDir.eachFileRecurse(FileType.FILES) { file ->
            boolean b = checkIfIsClassFile(file)
            if (b) {
                // add the file to the list if it is an class file                list << file
            }
        }

        println 'starts generating bytecode files ... '        list.each {
            generateByteCodeFiles(it)
        }
    }
}

private boolean checkIfIsClassFile(File file) {
    String regex = ".*\\.class"    String filename = file.getName()
    boolean b = filename.matches(regex);
    b
}

def generateByteCodeFiles(File file) {

    //execute command and get the command line output as a String    def stdout = new ByteArrayOutputStream()
    exec {
        // javap -v -p -s -sysinfo -constants Subclass\$InnerClass.class        commandLine "javap", "-private", "-v", "-s", file;
        standardOutput = stdout
    }
    String resultString = stdout.toString();
    createFile(resultString, file);
}


def createFile(String result, File classFile) {
    String fname = classFile.name;

    // remove file name extension    int pos = fname.lastIndexOf(".");
    if (pos > 0) {
        fname = fname.substring(0, pos);
    }

    // create txt files to save the result    fname = fname + ".txt"    File textFile = new File(project.getBuildDir().toString() + "/bytecode/" + fname);
    textFile.getParentFile().mkdirs();
    textFile.createNewFile();
    println textFile

    // write the output String into the file    FileWriter fileWriter = new FileWriter(textFile);
    fileWriter.write(result);
    fileWriter.flush();
    fileWriter.close();

}

ClassLoaders in Android SDK




~/Library/Android$ find . -name *ClassLoader*

./sdk/docs/reference/android/os/Parcelable.ClassLoaderCreator.html
./sdk/docs/reference/dalvik/system/BaseDexClassLoader.html
./sdk/docs/reference/dalvik/system/DexClassLoader.html
./sdk/docs/reference/dalvik/system/PathClassLoader.html
./sdk/docs/reference/java/lang/ClassLoader.html
./sdk/docs/reference/java/net/URLClassLoader.html
./sdk/docs/reference/java/security/SecureClassLoader.html
./sdk/sources/android-15/android/core/ClassLoaderTest.java
./sdk/sources/android-15/java/lang/ClassLoader.java
./sdk/sources/android-15/java/lang/VMClassLoader.java
./sdk/sources/android-15/java/net/URLClassLoader.java
./sdk/sources/android-15/java/security/SecureClassLoader.java
./sdk/sources/android-15/junit/runner/TestCaseClassLoader.java
./sdk/sources/android-17/java/lang/ClassLoader.java
./sdk/sources/android-17/java/lang/VMClassLoader.java
./sdk/sources/android-17/java/net/URLClassLoader.java
./sdk/sources/android-17/java/security/SecureClassLoader.java
./sdk/sources/android-17/junit/runner/TestCaseClassLoader.java
./sdk/sources/android-19/java/lang/ClassLoader.java
./sdk/sources/android-19/java/lang/VMClassLoader.java
./sdk/sources/android-19/java/net/URLClassLoader.java
./sdk/sources/android-19/java/security/SecureClassLoader.java
./sdk/sources/android-19/junit/runner/TestCaseClassLoader.java
./sdk/sources/android-20/java/lang/ClassLoader.java
./sdk/sources/android-20/java/lang/VMClassLoader.java
./sdk/sources/android-20/java/net/URLClassLoader.java
./sdk/sources/android-20/java/security/SecureClassLoader.java
./sdk/sources/android-20/junit/runner/TestCaseClassLoader.java
./sdk/sources/android-20/org/apache/harmony/tests/java/lang/ClassLoaderTest.java
./sdk/sources/android-22/java/lang/ClassLoader.java
./sdk/sources/android-22/java/lang/VMClassLoader.java
./sdk/sources/android-22/java/net/URLClassLoader.java
./sdk/sources/android-22/java/security/SecureClassLoader.java
./sdk/sources/android-22/junit/runner/TestCaseClassLoader.java
./sdk/sources/android-22/org/apache/harmony/tests/java/lang/ClassLoaderTest.java
./sdk/sources/android-23/com/android/layoutlib/bridge/intensive/setup/ModuleClassLoader.java
./sdk/sources/android-23/java/lang/ClassLoader.java
./sdk/sources/android-23/java/lang/VMClassLoader.java
./sdk/sources/android-23/java/net/URLClassLoader.java
./sdk/sources/android-23/java/security/SecureClassLoader.java
./sdk/sources/android-23/junit/runner/TestCaseClassLoader.java

./sdk/sources/android-23/org/apache/harmony/tests/java/lang/ClassLoaderTest.java

Saturday, December 5, 2015

Use Gradle to remove 2-digits prefix in filenames recursively


What we have:




We want to remove all the number prefixes in the songs' names. Something like this




import groovy.io.FileType

FileCollection collection
File srcDir = new File('Taylor Swift')

task rename {


    println 'pwd'.execute().text

    def list = []


    srcDir.eachFileRecurse(FileType.FILES) { file ->
        list << file
    }
    list.each {
        changeName(it)
    }
}


def changeName(File file) {

    String regex = "^[0-9][0-9].*"    String originalName = file.getName()



    boolean b = originalName.matches(regex);

    if (b) {
        String newname = originalName.replaceFirst("[0-9][0-9]\\s", "")
        File newNameFile = new File(file.getParent(), newname)
        file.renameTo(newNameFile)

        println newNameFile

    }


}

Script to change all name prefix in a directory


The unix script to remove all file name prefix of 2 digits. example :
03 What is this about.txt



for name in [0-9][0-9]*
do 
    newname="$(echo "$name" | cut -c4-)"
    mv "$name" "$newname"
    echo ${newname}
    
done



This uses bash command substitution to remove the first 3 characters from the input filename via cut, and stores that in $newname. Then it renames the old name to the new name. This is performed on every file.
cut -c4- specifies that only characters after index 4 should be returned from the input. 4- is a range starting at index 7 with no end; that is, until the end of the line.

Reference:

http://unix.stackexchange.com/questions/47367/bulk-rename-change-prefix