jmultimethod

multimethods for Java using annotations
git clone https://logand.com/git/jmultimethod.git/
Log | Files | Refs | LICENSE

commit f1507b1ff6bb1b5655ded6a42253ff5981ec7b5f
parent b0c76f4d1af96ba63c18417310a3d01f1f313d41
Author: Tomas Hlavaty <tom@logand.com>
Date:   Sat, 26 Dec 2015 22:56:22 +0100

remove tabs

Diffstat:
Msrc/jmultimethod/AsteroidTest.java | 154++++++++++++++++++++++++++++++++++++++++----------------------------------------
Msrc/jmultimethod/CarTest.java | 186++++++++++++++++++++++++++++++++++++++++----------------------------------------
Msrc/jmultimethod/Multi.java | 3+--
Msrc/jmultimethod/Multimethod.java | 192++++++++++++++++++++++++++++++++++++++++----------------------------------------
Msrc/jmultimethod/V.java | 3+--
5 files changed, 268 insertions(+), 270 deletions(-)

diff --git a/src/jmultimethod/AsteroidTest.java b/src/jmultimethod/AsteroidTest.java @@ -4,81 +4,81 @@ package jmultimethod; public class AsteroidTest { - class Asteroid {} - - class Spaceship {} - - @Multi("collide") - public void collideOO(Object X, Object Y) { - log("?? Bang, what happened? ", X, Y); - } - - @Multi("collide") - public void collideAA(Asteroid X, Asteroid Y) { - log("AA Look at the beautiful fireworks! ", X, Y); - } - - @Multi("collide") - public void collideAS(Asteroid X, Spaceship Y) { - log("AS Is it fatal? ", X, Y); - } - - @Multi("collide") - public void collideSA(Spaceship X, Asteroid Y) { - log("SA Is it fatal? ", X, Y); - } - - @Multi("collide") - public void collideSS(Spaceship X, Spaceship Y) { - log("SS Who's fault was it? ", X, Y); - } - - @Multi("collide") - public void collide1S(String X, Spaceship Y) { - log("1S any string? ", X, Y); - } - - @Multi("collide") - public void collide2S(@V("hi") String X, Spaceship Y) { - log("2S 'hi' value? ", X, Y); - } - - protected Multimethod mm = new Multimethod("collide", getClass()); - - public void collide(Object X, Object Y) { - mm.invoke(this, X, Y); - } - - public void run() { - Object A = new Asteroid(); - Object S = new Spaceship(); - collide(A, A); - collide(A, S); - collide(S, A); - collide(S, S); - collide(A, 1); - collide(2, A); - collide(S, 3); - collide(4, S); - collide(5, null); - collide(null, null); - collide("hi", S); - collide("hello", S); - } - - public void log(Object... args) { - for(Object o: args) { - if(o instanceof String) { - System.out.print(" " + (String) o); - } else { - System.out.print(" " + o); - } - } - System.out.println(); - } - - public static void main(String[] args) throws Exception { - AsteroidTest t = new AsteroidTest(); - t.run(); - } + class Asteroid {} + + class Spaceship {} + + @Multi("collide") + public void collideOO(Object X, Object Y) { + log("?? Bang, what happened? ", X, Y); + } + + @Multi("collide") + public void collideAA(Asteroid X, Asteroid Y) { + log("AA Look at the beautiful fireworks! ", X, Y); + } + + @Multi("collide") + public void collideAS(Asteroid X, Spaceship Y) { + log("AS Is it fatal? ", X, Y); + } + + @Multi("collide") + public void collideSA(Spaceship X, Asteroid Y) { + log("SA Is it fatal? ", X, Y); + } + + @Multi("collide") + public void collideSS(Spaceship X, Spaceship Y) { + log("SS Who's fault was it? ", X, Y); + } + + @Multi("collide") + public void collide1S(String X, Spaceship Y) { + log("1S any string? ", X, Y); + } + + @Multi("collide") + public void collide2S(@V("hi") String X, Spaceship Y) { + log("2S 'hi' value? ", X, Y); + } + + protected Multimethod mm = new Multimethod("collide", getClass()); + + public void collide(Object X, Object Y) { + mm.invoke(this, X, Y); + } + + public void run() { + Object A = new Asteroid(); + Object S = new Spaceship(); + collide(A, A); + collide(A, S); + collide(S, A); + collide(S, S); + collide(A, 1); + collide(2, A); + collide(S, 3); + collide(4, S); + collide(5, null); + collide(null, null); + collide("hi", S); + collide("hello", S); + } + + public void log(Object... args) { + for(Object o: args) { + if(o instanceof String) { + System.out.print(" " + (String) o); + } else { + System.out.print(" " + o); + } + } + System.out.println(); + } + + public static void main(String[] args) throws Exception { + AsteroidTest t = new AsteroidTest(); + t.run(); + } } diff --git a/src/jmultimethod/CarTest.java b/src/jmultimethod/CarTest.java @@ -4,97 +4,97 @@ package jmultimethod; public class CarTest { - interface CarElement {} - - class Wheel implements CarElement { - private String name; - Wheel(String name) { - this.name = name; - } - String getName() { - return this.name; - } - } - - class Engine implements CarElement {} - - class Body implements CarElement {} - - class Car { - CarElement[] elements; - public CarElement [] getElements() { - return elements.clone(); - } - public Car() { - this.elements = new CarElement[] - { new Wheel("front left"), new Wheel("front right"), - new Wheel("back left") , new Wheel("back right"), - new Body(), new Engine()}; - } - } - - @Multi("visit") - public void visitP(Wheel wheel, @V("print") String mode) { - System.out.println("Visiting "+ wheel.getName() + " wheel"); - } - - @Multi("visit") - public void visitP(Engine engine, @V("print") String mode) { - System.out.println("Visiting engine"); - } - - @Multi("visit") - public void visitP(Body body, @V("print") String mode) { - System.out.println("Visiting body"); - } - - @Multi("visit") - public void visitP(Car car, @V("print") String mode) { - System.out.println("\nVisiting car"); - for(CarElement element : car.getElements()) { - visit(element, mode); - } - System.out.println("Visited car"); - } - - @Multi("visit") - public void visitD(Wheel wheel, @V("do") String mode) { - System.out.println("Kicking my "+ wheel.getName()); - } - - @Multi("visit") - public void visitD(Engine engine, @V("do") String mode) { - System.out.println("Starting my engine"); - } - - @Multi("visit") - public void visitD(Body body, @V("do") String mode) { - System.out.println("Moving my body"); - } - - @Multi("visit") - public void visitD(Car car, @V("do") String mode) { - System.out.println("\nStarting my car"); - for(CarElement element : car.getElements()) { - visit(element, mode); - } - System.out.println("Started car"); - } - - protected Multimethod mm = new Multimethod("visit", getClass()); - - public void visit(Object any, String mode) { - mm.invoke(this, any, mode); - } - - public void run() { - Car car = new Car(); - visit(car, "print"); - visit(car, "do"); - } - - static public void main(String[] args){ - CarTest t = new CarTest(); - t.run(); - } + interface CarElement {} + + class Wheel implements CarElement { + private String name; + Wheel(String name) { + this.name = name; + } + String getName() { + return this.name; + } + } + + class Engine implements CarElement {} + + class Body implements CarElement {} + + class Car { + CarElement[] elements; + public CarElement [] getElements() { + return elements.clone(); + } + public Car() { + this.elements = new CarElement[] + { new Wheel("front left"), new Wheel("front right"), + new Wheel("back left") , new Wheel("back right"), + new Body(), new Engine()}; + } + } + + @Multi("visit") + public void visitP(Wheel wheel, @V("print") String mode) { + System.out.println("Visiting "+ wheel.getName() + " wheel"); + } + + @Multi("visit") + public void visitP(Engine engine, @V("print") String mode) { + System.out.println("Visiting engine"); + } + + @Multi("visit") + public void visitP(Body body, @V("print") String mode) { + System.out.println("Visiting body"); + } + + @Multi("visit") + public void visitP(Car car, @V("print") String mode) { + System.out.println("\nVisiting car"); + for(CarElement element : car.getElements()) { + visit(element, mode); + } + System.out.println("Visited car"); + } + + @Multi("visit") + public void visitD(Wheel wheel, @V("do") String mode) { + System.out.println("Kicking my "+ wheel.getName()); + } + + @Multi("visit") + public void visitD(Engine engine, @V("do") String mode) { + System.out.println("Starting my engine"); + } + + @Multi("visit") + public void visitD(Body body, @V("do") String mode) { + System.out.println("Moving my body"); + } + + @Multi("visit") + public void visitD(Car car, @V("do") String mode) { + System.out.println("\nStarting my car"); + for(CarElement element : car.getElements()) { + visit(element, mode); + } + System.out.println("Started car"); + } + + protected Multimethod mm = new Multimethod("visit", getClass()); + + public void visit(Object any, String mode) { + mm.invoke(this, any, mode); + } + + public void run() { + Car car = new Car(); + visit(car, "print"); + visit(car, "do"); + } + + static public void main(String[] args){ + CarTest t = new CarTest(); + t.run(); + } } diff --git a/src/jmultimethod/Multi.java b/src/jmultimethod/Multi.java @@ -8,6 +8,5 @@ import java.lang.annotation.Target; @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface Multi { - - public String value(); + public String value(); } diff --git a/src/jmultimethod/Multimethod.java b/src/jmultimethod/Multimethod.java @@ -8,107 +8,107 @@ import java.util.Comparator; public class Multimethod { - protected String name; - protected final ArrayList<Method> methods = new ArrayList<Method>(); - protected final MethodComparator methodComparator = new MethodComparator(); + protected String name; + protected final ArrayList<Method> methods = new ArrayList<Method>(); + protected final MethodComparator methodComparator = new MethodComparator(); - public Multimethod(String name, Class... classes) { - this.name = name; - for(Class c: classes) { - add(c); - } - } + public Multimethod(String name, Class... classes) { + this.name = name; + for(Class c: classes) { + add(c); + } + } - public void add(Class c) { - for(Method m: c.getMethods()) { - for(Annotation ma: m.getAnnotations()) { - if(ma instanceof Multi) { - Multi g = (Multi) ma; - if(this.name.equals(g.value())) { - methods.add(m); - } - } - } - } - sort(); - } + public void add(Class c) { + for(Method m: c.getMethods()) { + for(Annotation ma: m.getAnnotations()) { + if(ma instanceof Multi) { + Multi g = (Multi) ma; + if(this.name.equals(g.value())) { + methods.add(m); + } + } + } + } + sort(); + } - protected void sort() { - Method[] a = new Method[methods.size()]; - methods.toArray(a); - Arrays.sort(a, methodComparator); - methods.clear(); - for(Method m: a) { - methods.add(m); - } - } + protected void sort() { + Method[] a = new Method[methods.size()]; + methods.toArray(a); + Arrays.sort(a, methodComparator); + methods.clear(); + for(Method m: a) { + methods.add(m); + } + } - protected class MethodComparator implements Comparator<Method> { - @Override - public int compare(Method l, Method r) { - // most specific methods first - Class[] lc = l.getParameterTypes(); - Class[] rc = r.getParameterTypes(); - for(int i = 0; i < lc.length; i++) { - String lv = value(l, i); - String rv = value(r, i); - if(lv == null) { - if(rv != null) { - return 1; - } - } - if(lc[i].isAssignableFrom(rc[i])) { - return 1; - } - } - return -1; - } - } + protected class MethodComparator implements Comparator<Method> { + @Override + public int compare(Method l, Method r) { + // most specific methods first + Class[] lc = l.getParameterTypes(); + Class[] rc = r.getParameterTypes(); + for(int i = 0; i < lc.length; i++) { + String lv = value(l, i); + String rv = value(r, i); + if(lv == null) { + if(rv != null) { + return 1; + } + } + if(lc[i].isAssignableFrom(rc[i])) { + return 1; + } + } + return -1; + } + } - protected String value(Method method, int arg) { - Annotation[] a = method.getParameterAnnotations()[arg]; - for(Annotation p: a) { - if(p instanceof V) { - V v = (V) p; - return v.value(); - } - } - return null; - } + protected String value(Method method, int arg) { + Annotation[] a = method.getParameterAnnotations()[arg]; + for(Annotation p: a) { + if(p instanceof V) { + V v = (V) p; + return v.value(); + } + } + return null; + } - protected boolean isApplicable(Method method, Object... args) { - Class[] c = method.getParameterTypes(); - for(int i = 0; i < c.length; i++) { - // must be instanceof and equal to annotated value if present - if(c[i].isInstance(args[i])) { - String v = value(method, i); - if(v != null && !v.equals(args[i])) { - return false; - } - } else { - if(args[i] != null || !Object.class.equals(c[i])) { - return false; - } - } - } - return true; - } + protected boolean isApplicable(Method method, Object... args) { + Class[] c = method.getParameterTypes(); + for(int i = 0; i < c.length; i++) { + // must be instanceof and equal to annotated value if present + if(c[i].isInstance(args[i])) { + String v = value(method, i); + if(v != null && !v.equals(args[i])) { + return false; + } + } else { + if(args[i] != null || !Object.class.equals(c[i])) { + return false; + } + } + } + return true; + } - public Object invoke(Object self, Object... args) { - Method m = null; // first applicable method (most specific) - for(Method method: methods) { - if(isApplicable(method, args)) { - m = method; - break; - } - } - if(m == null) { - throw new RuntimeException("No applicable method '" + name + "'."); - } - try { - return m.invoke(self, args); - } catch (Exception e) { - throw new RuntimeException("Method invocation failed '" + name + "'."); - } - } + public Object invoke(Object self, Object... args) { + Method m = null; // first applicable method (most specific) + for(Method method: methods) { + if(isApplicable(method, args)) { + m = method; + break; + } + } + if(m == null) { + throw new RuntimeException("No applicable method '" + name + "'."); + } + try { + return m.invoke(self, args); + } catch (Exception e) { + throw new RuntimeException("Method invocation failed '" + name + "'."); + } + } } diff --git a/src/jmultimethod/V.java b/src/jmultimethod/V.java @@ -8,6 +8,5 @@ import java.lang.annotation.Target; @Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) public @interface V { - - public String value(); + public String value(); }