i know kung fu - juggling java bytecode

Download I Know Kung Fu - Juggling Java Bytecode

If you can't read please download the document

Upload: alexander-shopov

Post on 16-Apr-2017

1.295 views

Category:

Technology


4 download

TRANSCRIPT

I Know Kung Fu Writing Java Bytecode

Alexander Shopov

[ash@edge ~]$ whoami

By day: Software Engineer at CiscoBy night: OSS contributorCoordinator of Bulgarian Gnome TP

Contacts:E-mail: [email protected]:[email protected]: http://www.linkedin.com/in/alshopovWeb:Just search al_shopov

Please Learn And Share

License: CC-BY v3.0Creative Commons Attribution v3.0

Disclaimer

My opinions, knowledge and experience!Not my employer's.

Plan

What is bytecode and how to juggle it

Why do it, why not do it

How to do itClass file structure

Manipulation with ASM

How to consume your own dog foodClassloaders

Proxies

Agents

What it is

Bytecodes are the assembler of JVM. By writing new bytecode sequences or changing existing ones we can program the JVM directly outside of the domain of the Java Programming Language;

Lower level than writing Java - JVM assembler;

Much easier than writing a whole (optimizing) compiler;

Harder than using a compiler;

Similar to the Jedi Dark Side pathway to many abilities some consider to be unnatural.

Why do it?

Makes impossible things possible &

Makes hard things attainable &

Makes long tasks shorter &

Makes slow things faster &

Makes repetition go away &

Makes your head blow away!!!

Common use cases

Program analysis find bugs, unused code paths, reverse engineering, metrics, etc.

Program generation compilers, stub/skeleton compilers, fast layers without reflection.

Transformation optimize, deoptimize/obfuscate, aspect weaving, performance monitoring.

Why not do it?

Source stops being close to executable &

Executable stops being close to any source &

There can be better or easier ways of doing things &

Fewer people knowing what happens means no one can help you &

Problems will be your fault! Unit test ! &

You take the red pill and find out the rabbit hole goes deep, deep, deep EOT

Common misuse cases

I write it, you maintain it.

Do it because it is cool or others are doing it.

Over engineering / over generalization.

Solution in a search of a problem.

Preferring NIH to a popular solution.

Bytecode crash course in 1-2-3

Thread AF0F1F2F3F4Thread BF0F1F2Thread CF0F1Thread DF0F1F2F3

Bytecode crash course in 1-2-3

JVM (heap)F0

Class

Pool of constants0123456

Local variables

Stack

Method codePCClass

Bytecode crash course in 1-2-3

Bytecodes retrieve things from class bytestream, constant pool, local variables array

Perform computations only on stack

Store temporary results in local variables array

Enter frame by method call

Return from frame with a possible result (top thing on stack), throw top of stack

JVM can also throw and unroll frames

If you need more information

Check my other presentation:

Lifting the Veil Reading Java Bytecode

How to do it

Many ways with different pluses and minuses

Easiest way to write byte code use the Java compiler.javac you all know that

java compiler api since 1.6

But more of that wait for the end

Until then

Serp

BCELCGlibJCF EditorAspectJJavaAssistRooSootRetroweaverJiapiTea Trove

jclasslibjReloaderjDeccojen

gnu.bytecode

Serp

BCELCGlibJCF EditorAspectJJavaAssistRooSootRetroweaverJiapiTea Trove

jclasslibjReloaderjDeccojen

gnu.bytecodeOne of the older frameworks,

Bytecode manipulation

Not constrained by Java

Not constrained by compiler

Not constrained by source availability

Still constrained by JVM

Generate or change bytecode to the limits of JVM

Classfile Structure, 0xcafebabe

Modifiers, name, super class, interfaces

Constant pool: numeric, string and type constants

Source file name (optional)

Enclosing class reference

Annotation*

Attribute*

Inner class*Name

Field*Modifiers, name, type

Annotation*

Attribute*

Method*

Modifiers, name, return and parameter types

Annotation*

Attribute*

Compiled code

What is ASM

Extremely well designed bytecode manipulation library

Modular, small and fast pick all

Events based visitor (+SAX), additionally has tree API (DOM like)

Provides a small bytecode generation variant

Minimal just transformation, can stack transformations, no classloading

Timeline

1.5 30 Aug 2004 up to JDK 1.6 incl.

2.0 17 May 2005

3.0 01 Nov 2006

4.0 29 Oct 2011 framework for compatibility

Who uses ASM?

Languages and AOP tools: AspectJ, BeanShell, CGLIB, Clojure, Groovy, Jruby, Jython, Coroutines

Tools and frameworks: Fractal, Terracotta, Javeleon, JRebel

Persistence: OpenEJB, Oracle BerkleyDB, EclipseLink

Monitoring: WebLogic, JiP

Testing and code analysis: Cobertura, Eclipse

Most JDKs Use It!

OracleSun HotSpot JDK, OpenJDK

BEA/Appeal VM JRockit

IBM J9

Azul Zing$JAVA_HOME/jre/lib/rt.jar

com.sun.xml.internal.ws.org.objectweb.asm

com.sun.xml.internal.ws.model.WrapperBeanGenerator RuntimeModeler Web Services implementation

Read and explore

ClassReaderClassVisitor

ClassReaderClassVisitorClassVisitorClassWriterRead, transform, write

ClassReaderClassVisitorClassVisitorClassVisitorClassVisitorClassVisitorClassVisitorClassWriterI know what I am doing

ClassReaderClassVisitorClassVisitorClassVisitorClassWriterClassVisitorClassVisitorClassVisitorClassWriterClassReaderClassVisitorClassVisitorClassVisitorClassVisitorI believe I can fly, I believe I can touch the sky

ClassReaderClassVisitorClassVisitorClassVisitorClassVisitorClassWriterClassVisitorClassVisitorClassVisitorClassWriter

ClassVisitor

ClassVisitor

Basic Pattern Of Transformation

Read bytestream of a class

Generate events from that

Make changes to the events

Receive the events and serialize to bytestream

Lather, rinse, repeat

**visitvisitSourcevisitOuterClassvisitAnnotationvisitAttributevisitInnerClassvisitFiledvistiMethodvisitEndBasic diagram of class visiting

UserClassVisitor

Order is important

Bold return other visitors

* marks repeat

*visitvisitEnumvisitAnnotationBasic diagram of annotation visiting

UserAnnotationVisitor

Order is important

Bold return other visitors

* marks repeat

visitArrayvisitEnd

*visitAnnotationvisitAttributevisitEndBasic diagram of field visiting

UserFieldVisitor

Order is important

Bold return other visitors

* marks repeat

*

*visitAnnotationDefaultvisitAnnotationvisitParameterAnnotationvisitAttributevisitCodevisitFramevisitXInsnvisitLabelvisitTryCatchBlockvisitLocalVariablevisitLineNumbervisitMaxsvisitEndBasic diagram of method visiting

UserMethodVisitor

Order is important

Bold return other visitors

* marks repeat

package org.kambanaria.writebytecode.asm;
public class Zombunny { //

public Integer getVersion() {
return Integer.valueOf(1);
}

}

Our humble beginning

public class StupidClassLoader extends ClassLoader {

private Map bytes = new HashMap();

public StupidClassLoader() {
super(StupidClassLoader.class.getClassLoader());
}

public void provide(String className, byte[] classBytes) {
bytes.put(className, classBytes);
}

@Override
public Class loadClass(String name) throws ClassNotFoundException {
byte[] classBytes = bytes.get(name);
Class loaded;
if (classBytes != null) {
loaded = defineClass(name, classBytes, 0, classBytes.length);
} else {
ClassLoader parent = getParent();
if (null == parent) {
parent = ClassLoader.getSystemClassLoader();
}
loaded = parent.loadClass(name);
}
return loaded;
}
}Our building blocks

public final class Utilities {
private Utilities() { }
public static final String CLASS_NAME = "org.kambanaria.writebytecode.asm.Zombunny";
public static final String METHOD_NAME = "getVersion";
public static String toClassPathResourceName(String clazz) {
return clazz.replace('.', '/') + ".class";
}
public static byte[] retrieveBytesFromClassPath(String className) throws IOException {
String path = toClassPathResourceName(className);
InputStream is = Utilities.class.getClassLoader().getResourceAsStream(path);
InputStream classBytes = new BufferedInputStream(is);
return is2bytes(classBytes);
}
public static byte[] patch(byte[] bytes, DemoClassAdapter adapter) {
ClassReader cr = new ClassReader(bytes);
cr.accept(adapter, ClassReader.SKIP_FRAMES);
return adapter.getCw().toByteArray();
}
public static byte[] is2bytes(InputStream is) throws IOException {
int max = 1024 * 1024;
byte[] bytes = new byte[max]; // 1MB
int read = is.read(bytes); // Don't do that
byte[] result = new byte[read];
System.arraycopy(bytes, 0, result, 0, result.length);
return result;
}
public static Object call0ArgsMethodOn(Object o, String methodName) //
throws ReflectiveOperationException {
Class c = o.getClass();
Method m = c.getDeclaredMethod(methodName, (Class[]) null);
m.setAccessible(true);
return m.invoke(o, (Object[]) null);
}
}Our building blocks

public class DemoClassAdapter extends ClassVisitor {

public DemoClassAdapter(ClassVisitor cv) {
super(Opcodes.ASM4, cv);
}

public ClassWriter getCw() {
return (ClassWriter) cv;
}
}Our building blocks

public class Rename extends DemoClassAdapter {

private String suffix;

public Rename(ClassVisitor cv, String suffix) {
super(cv);
this.suffix = suffix;
}

@Override
public void visit(int version, int access, String name, //
String signature, String superName, String[] interfaces) {
cv.visit(version, access, name + suffix, signature, superName, interfaces);
}
}Rename class

package org.kambanaria.writebytecode.asm;
public class ZombunnySUFFIX { //

public Integer getVersion() {
return Integer.valueOf(1);
}

}

Result is as if

public class AddField extends DemoClassAdapter {
public AddField(ClassVisitor cv) {
super(cv);
}
@Override
public void visitEnd() {
cv.visitField(ACC_PRIVATE, "_version", //
Type.getDescriptor(Integer.class), null, null);
cv.visitEnd();
}}Add field

public class Zombunny { //

private Integer _version;

public Integer getVersion() {
return Integer.valueOf(1);
}

}Add field

public class ChangeMethod extends DemoClassAdapter {
public ChangeMethod(ClassVisitor cv) {
super(cv);
}
@Override
public MethodVisitor visitMethod(int access, String name, String desc, //
String signature, String[] exceptions) {
MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
if (Utilities.METHOD_NAME.equals(name) && "()Ljava/lang/Integer;".equals(desc)) {
return new DemoMethodVisitor(Opcodes.ASM4, mv);
} else {
return mv;
}
}
class DemoMethodVisitor extends MethodVisitor {

public DemoMethodVisitor(int version, MethodVisitor mv) {
super(version, mv);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, "org/kambanaria/writebytecode/asm/Zombunny", //
"_version", "Ljava/lang/Integer;");
mv.visitInsn(ARETURN);
mv.visitEnd();
}
}
}Change method

public class Zombunny { //

private Integer _version;

public Integer getVersion() {
return _version;
}

}And change method

public class ManipulateConstructors extends DemoClassAdapter {
public ManipulateConstructors(ClassVisitor cv) {
super(cv);
}
@Override
public MethodVisitor visitMethod(int access, String name, String desc, //
String signature, String[] exceptions) {
if ("".equals(name)) {
MethodVisitor mv = cv.visitMethod(ACC_PUBLIC, "", "()V", null, null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V");
mv.visitVarInsn(ALOAD, 0);
mv.visitTypeInsn(NEW, "java/lang/Integer");
mv.visitInsn(DUP);
mv.visitInsn(ICONST_2);
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Integer", "", "(I)V");
mv.visitFieldInsn(PUTFIELD, "org/kambanaria/writebytecode/asm/Zombunny", //
"_version", "Ljava/lang/Integer;");
mv.visitInsn(RETURN);
mv.visitMaxs(4, 1);
mv.visitEnd();
return mv;
} else {
return cv.visitMethod(access, name, desc, signature, exceptions);
}
}
@Override
public void visitEnd() {
MethodVisitor mv = cv.visitMethod(ACC_PUBLIC, "", "(Ljava/lang/Integer;)V", //
null, null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V");
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 1);
mv.visitFieldInsn(PUTFIELD, "org/kambanaria/writebytecode/asm/Zombunny", //
"_version", "Ljava/lang/Integer;");
mv.visitInsn(RETURN);
mv.visitMaxs(2, 2);
mv.visitEnd();
cv.visitEnd();
}
}Fix constructors

public class Zombunny { //

private Integer _version;

public Zombunny() {
_version = new Integer(2);
}

public Zombunny(Integer version) {
_version = version;
}

public Integer getVersion() {
return _version;
}
}And fix constructors

public class AddInterface extends DemoClassAdapter {

private static final String COMPARABLE = "java/lang/Comparable";

public AddInterface(ClassVisitor cv) {
super(cv);
}

@Override
public void visit(int version, int access, String name, String signature,//
String superName, String[] interfaces) {
if (Arrays.asList(interfaces).contains(COMPARABLE)) {
super.visit(version, access, name, signature, superName, interfaces);
} else {
int l = interfaces.length;
String[] newInterfaces = new String[l + 1];
System.arraycopy(interfaces, 0, newInterfaces, 0, l);
newInterfaces[l] = COMPARABLE;
super.visit(version, access, name, signature, superName, newInterfaces);
}
}
}Add interface

public class Zombunny implements Comparable { //

private Integer _version;

public Zombunny() {
_version = new Integer(2);
}

public Zombunny(Integer version) {
_version = version;
}

public Integer getVersion() {
return _version;
}
}And add interface

public class AddMethod extends DemoClassAdapter {
public AddMethod(ClassVisitor cv) {super(cv);}
@Override
public void visitEnd() {
MethodVisitor compareToObject = cv.visitMethod(ACC_PUBLIC, "compareTo", //
"(Ljava/lang/Object;)I", null, null);
compareToObject.visitCode();
compareToObject.visitVarInsn(ALOAD, 1);
compareToObject.visitTypeInsn(INSTANCEOF, "org/kambanaria/writebytecode/asm/Zombunny");
Label lbl0 = new Label();
compareToObject.visitJumpInsn(IFNE, lbl0);
compareToObject.visitTypeInsn(NEW, "java/lang/ClassCastException");
compareToObject.visitInsn(DUP);
compareToObject.visitMethodInsn(INVOKESPECIAL, "java/lang/ClassCastException", //
"", "()V");
compareToObject.visitInsn(ATHROW);
compareToObject.visitLabel(lbl0);
compareToObject.visitVarInsn(ALOAD, 0);
compareToObject.visitVarInsn(ALOAD, 1);
compareToObject.visitTypeInsn(CHECKCAST, "org/kambanaria/writebytecode/asm/Zombunny");
compareToObject.visitMethodInsn(INVOKEVIRTUAL, "org/kambanaria/writebytecode/asm/Zombunny", //
"compareTo", "(Lorg/kambanaria/writebytecode/asm/Zombunny;)I");
compareToObject.visitInsn(IRETURN);
compareToObject.visitMaxs(2, 2);
compareToObject.visitEnd();
MethodVisitor compareToZombunny = cv.visitMethod(ACC_PUBLIC, "compareTo", //
"(Lorg/kambanaria/writebytecode/asm/Zombunny;)I", null, null);
compareToZombunny.visitCode();
compareToZombunny.visitVarInsn(ALOAD, 0);
compareToZombunny.visitFieldInsn(GETFIELD, "org/kambanaria/writebytecode/asm/Zombunny", //
"_version", "Ljava/lang/Integer;");
compareToZombunny.visitVarInsn(ALOAD, 1);
compareToZombunny.visitFieldInsn(GETFIELD, "org/kambanaria/writebytecode/asm/Zombunny", //
"_version", "Ljava/lang/Integer;");
compareToZombunny.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "compareTo", //
"(Ljava/lang/Integer;)I");
compareToZombunny.visitInsn(IRETURN);
compareToZombunny.visitMaxs(2, 2);
compareToZombunny.visitEnd();
cv.visitEnd();
}
}Add interface implementation

public class Zombunny implements Comparable { //

private Integer _version;

public Zombunny() {
_version = new Integer(2);
}

public Zombunny(Integer version) {
_version = version;
}

public Integer getVersion() {
return _version;
}

public int compareTo(Object o) {
if (o instanceof Zombunny) {
return compareTo((Zombunny) o);
} else {
throw new ClassCastException();
}
}

public int compareTo(Zombunny o) {
return _version.compareTo(o._version);
}
}And add interface

package org.kambanaria.writebytecode.asm;

public class Version {

private Integer _version;

public Version(Integer version) {
_version = version;
}

public Integer getVersion() {
return _version;
}

@Override
public String toString() {
return "Version: " + _version;
}
}The class we get method from

public class Chimerize extends DemoClassAdapter {

protected ClassNode twig;
protected MethodNode nm;
private static final String TWIG_NAME = "org.kambanaria.writebytecode.asm.Version";
public Chimerize(ClassVisitor cv) throws IOException {
super(cv);
ClassReader rdr = new ClassReader(TWIG_NAME);
twig = new ClassNode();
rdr.accept(twig, 0);
for (Object o : twig.methods) {
MethodNode method = (MethodNode) o;
if (method.name.equals("toString")) {
// Guess what is missing?
nm = method;
}
}
}
@Override
public void visitEnd() {
MethodVisitor chimeric =cv.visitMethod(nm.access, nm.name, nm.desc,
nm.signature, null);
nm.instructions.resetLabels();
Remapper remapper = new Remapper() {
@Override
public String map(String name) {
return name.replace("Version", "Zombunny");
}
};
nm.accept(new RemappingMethodAdapter(nm.access, nm.desc, chimeric, remapper));
cv.visitEnd();
}
}Chimerization

public class Zombunny implements Comparable { //
private Integer _version;
public Zombunny() {
_version = new Integer(2);
}
public Zombunny(Integer version) {
_version = version;
}
public Integer getVersion() {
return _version;
}
public int compareTo(Object o) {
if (o instanceof Zombunny) {
return compareTo((Zombunny) o);
} else {
throw new ClassCastException();
}
}
public int compareTo(Zombunny o) {
return _version.compareTo(o._version);
}
@Override
public String toString(){
return "Version: " + _version;
}
}Finally

public class ChimerizeTest {
Comparable sut;
@Before
public void setUp() throws IOException, ReflectiveOperationException {
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES + //
ClassWriter.COMPUTE_MAXS);
ClassVisitor cv = new AddField(new ManipulateConstructors( //
new AddMethod(new AddInterface(new Chimerize(cw)))));
ClassReader rdr = new ClassReader(Utilities.CLASS_NAME);
rdr.accept(cv, 0);
byte[] newClassBytes = cw.toByteArray();
StupidClassLoader ldr = new StupidClassLoader();
ldr.provide(Utilities.CLASS_NAME, newClassBytes);
Class newClass = ldr.loadClass(Utilities.CLASS_NAME);
Constructor constructor = newClass.getDeclaredConstructor(Integer.class);
sut = (Comparable) constructor.newInstance(new Integer(42));
}
}Peek at test construction chain

Utilities

Type

Generate the visitors with: Asmfierjava -classpath asm.jar:asm-util.jar:OUR_CP \
org.objectweb.asm.util.ASMifier CLASS

TraceClassVisitor

CheckClassAdapter

Additional APIs

org.objectweb.asm.commons commonly needed adaptors

org.objectweb.asm.xml bridge to SAX 2.0, manipulate via XSLT, XQuery

org.objectweb.asm.tree deserialize to tree

Classloaders

Dynamically load software components for Java platform

Lazy loaded on demand, as late as possible

Type-safe linkage must not violate type safety, no runtime checks

User-defined extensibility normal, user controlled objects

Multiple communicating namespaces types determined by class name and classloader

Classloader Chain

Bootstrap CLprimordial, nativejre/lib/*.jarExtension CLjre/lib/ext/*.jar-Djava.ext.dirsSystem CL$CLASSPATH-Djava.class.path

Applicationclassloader

Programmerclassloader

Classloader Hierarchy

Bootstrap CLprimordial, nativejre/lib/*.jarExtension CLjre/lib/ext/*.jar-Djava.ext.dirsSystem CL$CLASSPATH-Djava.class.path

Applicationclassloader

ApplicationclassloaderApplicationclassloader

ProgrammerclassloaderProgrammerclassloaderProgrammerclassloader

Enterprise Classloader Hierarchy

Bootstrap CLprimordial, nativejre/lib/*.jarExtension CLjre/lib/ext/*.jar-Djava.ext.dirsSystem CL$CLASSPATH-Djava.class.path

Applicationclassloader

ApplicationclassloaderApplicationclassloaderProgrammerclassloader

Programmerclassloader

Programmerclassloader

Programmerclassloader

Programmerclassloader

Programmerclassloader

Class Loader API

public abstract class ClassLoader {
protected ClassLoader(ClassLoader parent);
protected ClassLoader();

protected Class loadClass(String name, boolean resolve);
protected Class findClass(String name);
protected final Class defineClass(String name, byte[] b,
int off, int len);
protected final void resolveClass(Class c);

public URL getResource(String name);
public Enumeration getResources(String name);

public final MyClassLoader getParent();

public void setDefaultAssertionStatus(boolean);
public void setPackageAssertionStatus(String packageName,boolean enabled);
public void setClassAssertionStatus(String className, boolean enabled);
public void clearAssertionStatus();
}

When are class loaded?

Statically:Instance creation: new Integer(42);

Reference to static field or method: System.out;

Dynamically:Class.forName("java.lang.HashMap");

Class.forName("java.lang.HashMap",
boolean initialize,
ClassLoader loader);

Delegating Classloaders Standard

Plugin or Web Classloaders

OSGI & others

OMG!!!

Type Compatibility

A classloader can see and use (with exact type) instances of classes loaded by the ancestral chain and the classloader itself

Instances of classes loaded by sibling or descendant classloaders are invisible, they are just java.lang.Object

Object a; "SomeClass".equals(a.getClass().getName()); a instanceof Object; (SomeClass)a -> ClassCastExceptionUse reflection

Proxies

Dynamic proxy acts as a pass through/router to the real objectruntime implementations of interfaces

public, final and not abstract

extend java.lang.reflect.Proxy

Proxys behaviour is determined by an implementation of java.lang.reflect.InvocationHandler

Square peg in a non square hole

Some objectSome interface

public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}Fit it with an InvocationHandler

Object

Proxy

public class MyInvocationHandler implements InvocationHandler {
private Object delegate;
public MyInvocationHandler(Object... params) {
delegate = makeDelegate();
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
Class[] types = method.getParameterTypes();
Method m = reachMethod(methodName, types);
Object result;
try {
result = m.invoke(delegate, args);
} catch (InvocationTargetException e) {
throw e.getCause();
}
return result;
}

private static Method reachMethod(String name, Class... parTypes) {
Method m = null;
/* Logic to determine method */
return m;
}

private static Object makeDelegate(Object... params) {
/* Produce real object instead */
return new Object();
}
}

Java agents

Package java.lang.instrument - allow Java programming language agents to instrument programs running on the JVM.

java ... -javaagent:jarpath[=options]

Manifest attributes

byte[] -> byte[]

Almost Real Example

Action takes place here

A planet, an icy atmosphere

This country

Outsources to this country

They deliver cheaper than the world, faster than the speed of thought

The entrepreneurial spirit of that country

Makes them sell the software to this country

Where it fails spectacularly while clearly working in the other two ones

Investigation takes place

Finds the culprit

SimpleDateFormat frmt =
new SimpleDateFormat("E MM/dd/yyyy");

publicSimpleDateFormat(String pattern)Constructs a SimpleDateFormat using thegiven pattern and the default date formatsymbols for the default locale.Note: This constructor may not support allLocales. For full coverage, use the factorymethods in the DateFormat class.Parameters:pattern - the pattern describing the date andtime format Throws: NullPointerException -if the given pattern is null IllegalArgumentException - if the given patternis invalid

SimpleDateFormat

Could this have been avoided?

LANG=de_DE.UTF-8 java -jar SimpleDateFormat.jar Freitag 11/16/2012LANG=en_US.UTF-8 java -jar SimpleDateFormat.jar Friday 11/16/2012LANG=hi_IN.UTF-8 java -jar SimpleDateFormat.jar //LANG=bn_IN.UTF-8 java -jar SimpleDateFormat.jar Friday 11/16/2012LANG=bg_BG.UTF-8 java -jar SimpleDateFormat.jar 11/16/2012Hindi(300106, 4th)ShukravrBengali(200106, 7th)Shukrobar

India proposes:

UseEnglishLocale

USA retransmits:

UseEnglish Locale

Germany says:

No!

USA try in German:

VerwendenSieEnglischeLocale

Germany says:

Nein!

USA try manners:

Bitte?

Germany says:

NEIN!

USA checks what they said with Google translate:

mv.visitMethodInsn(INVOKESPECIAL, "java/text/SimpleDateFormat", //
"", "(Ljava/lang/String;)V");mv.visitFieldInsn(GETSTATIC, "java/util/Locale", //
"US", "Ljava/util/Locale;");
mv.visitMethodInsn(INVOKESPECIAL, "java/text/SimpleDateFormat", //
"", "(Ljava/lang/String;Ljava/util/Locale;)V");

Compiler API

import java.util.Random;
public class I {
public boolean singOutOfTune() {
return new Random().nextBoolean();
}
}

import java.util.Random;
public class I {
public boolean singOutOfTune() {
return new Random().nextBoolean();
}
}public class You {
public static String DID = "StandUp&WalkOutOnMe";
public static String DIDNOT = "LendMeAnEar";
public String wouldDo(boolean iF) {
return iF ? "StandUp&WalkOutOnMe" : "LendMeAnEar";
}
}

import java.util.Random;
public class I {
public boolean singOutOfTune() {
return new Random().nextBoolean();
}
}public class You {
public static String DID = "StandUp&WalkOutOnMe";
public static String DIDNOT = "LendMeAnEar";
public String wouldDo(boolean iF) {
return iF ? "StandUp&WalkOutOnMe" : "LendMeAnEar";
}
}public class ExistingClassesTest {
@Test
public void test1000times() {
int times = 1000;
do {
boolean didI;
I i = new I();
You you = new You();
String what = you.wouldDo(didI = i.singOutOfTune());
assertEquals(what, didI ? You.DID : You.DIDNOT);
} while (--times > 0);

}
}

import java.util.Random;
public class I {
public boolean singOutOfTune() {
return new Random().nextBoolean();
}
}public class You {
public static String DID = "StandUp&WalkOutOnMe";
public static String DIDNOT = "LendMeAnEar";
public String wouldDo(boolean iF) {
return iF ? "StandUp&WalkOutOnMe" : "LendMeAnEar";
}
}public class ExistingClassesTest {
@Test
public void test1000times() {
int times = 1000;
do {
boolean didI;
I i = new I();
You you = new You();
String what = you.wouldDo(didI = i.singOutOfTune());
assertEquals(what, didI ? You.DID : You.DIDNOT);
} while (--times > 0);
// What would you do if I sang out of tune ? The Beatles
}
}

public class SourceStrings {
private SourceStrings() }
public final static String I = " "
+ "import java.util.Random; "
+ "public class I { "
+ " public boolean singOutOfTune() { "
+ " return new Random().nextBoolean(); "
+ " } "
+ "} ";
public final static String YOU = " "
+ "public class You { "
+ " public static String DID = \"StandUp&WalkOutOnMe\"; "
+ " public static String DIDNOT = \"LendMeAnEar\"; "
+ " public String wouldDo(boolean iF) { "
+ " return iF ? \"StandUp&WalkOutOnMe\" : \"LendMeAnEar\";"
+ " } "
+ "} ";
}class StringSourceCodeObject extends SimpleJavaFileObject {

final String _source;

public StringSourceCodeObject(String fqName, String source) {
super(URI.create("string:///" + fqName.replaceAll("\\.", "/") //
+ Kind.SOURCE.extension), Kind.SOURCE);
_source = source;
}

@Override
public CharSequence getCharContent(boolean ignoreEncodingErrors) {
return _source;
}

public class CompilerAPI {
public static void main(String args[]) throws Exception {

/* Creating dynamic java source code file object */
JavaFileObject iObject = new StringSourceCodeObject("I", SourceStrings.I);
JavaFileObject youObject = new StringSourceCodeObject("You", SourceStrings.YOU);
JavaFileObject jfObjects[] = new JavaFileObject[]{iObject, youObject};
/* Units to compile */
Iterable units = Arrays.asList(jfObjects);
/* Instantiating the java compiler */
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
/* Get compiler file manager to show what to read. */
// (DEFAULT LISTENER, Locale.getDefault(), Charset.defaultCharset() )
JavaFileManager manager = compiler.getStandardFileManager(null, null, null);
/* Compilation options - here: place in target directory */
String[] compileOptions = new String[]{"-d", "target/classes"};
Iterable options = Arrays.asList(compileOptions);
/* Diagnostic placeholder */
DiagnosticCollector sink = new DiagnosticCollector();
/* 1st null: where to write (default), 2nd null: no annotations processed */
CompilationTask task = compiler.getTask(null, manager, sink, options, null, units);
/* Go, go, go */
boolean status = task.call();
if (!status) {
for (Diagnostic