DZone Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world

Snippets has posted 5883 posts at DZone. View Full User Profile

Demo Ruby Style Mixin In Java

04.09.2005
| 2574 views |
  • submit to reddit
        This needs more work to be complete.  Will it ever be useful?

public class MixinTest
{
  /*
   * The Demo
   */
  interface Chimera extends Lion, Goat, Serpent, Animal {}

  public static void main(String[] args)
  {
    Chimera chimera = (Chimera) MixinFactory.create(Chimera.class, new AnimalImpl());
    System.out.println("The Chimera: ");
    chimera.roar();
    chimera.stomp();
    chimera.slither();
    chimera.action("Sing a song");
  }

  /*
   * The Interfaces
   */
  public interface Lion
  {
    void roar();
  }

  public interface Goat
  {
    void stomp();
  }

  public interface Serpent
  {
    void slither();
  }

  public interface Animal
  {
    void action(String description);
  }

  /*
   * The Implementations
   */
  public static class LionImpl implements Lion
  {
    private Animal animal;

    public LionImpl(Animal animal)
    {
      this.animal = animal;
    }

    public void roar()
    {
      animal.action("Roars with lion head");
    }
  }

  public static class GoatImpl implements Goat
  {
    private Animal animal;

    public GoatImpl(Animal animal)
    {
      this.animal = animal;
    }

    public void stomp()
    {
      animal.action("Stomps with goat foot");
    }
  }

  public static class SerpentImpl implements Serpent
  {
    private Animal animal;

    public SerpentImpl(Animal animal)
    {
      this.animal = animal;
    }

    public void slither()
    {
      animal.action("Slithers with serpent tail");
    }
  }

  public static class AnimalImpl implements Animal
  {
    public void action(String description)
    {
      System.out.println(description);
    }
  }

  /*
   * The Guts
   */
  public static class MixinFactory
  {
    private static class MixinInvocationHandler implements InvocationHandler
    {
      private Map implMap = new HashMap();
      public MixinInvocationHandler(Class clazz, Object core)
      {
        for (int i = 0; i < clazz.getInterfaces().length; i++)
        {
          Class anInterface = clazz.getInterfaces()[i];
          try
          {
            Class delegateClass = Class.forName(anInterface.getName()+"Impl");
            Constructor delegateConstructor = findBestMatchConstrustor(delegateClass, core.getClass());
            if(delegateConstructor != null)
            {
              implMap.put(anInterface, delegateConstructor.newInstance(new Object[] {core}));
            }
            else
            {
              implMap.put(anInterface, core);
            }
          }
          catch(Exception e)
          {
            throw new RuntimeException(e);
          }
        }
      }
      public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
      {
        Object delegate = implMap.get(method.getDeclaringClass());
        return delegate.getClass().getDeclaredMethod(method.getName(), method.getParameterTypes()).invoke(delegate, args);
      }
      private static Constructor findBestMatchConstrustor(Class delegateClass, Class coreClass)
      {
        if(coreClass == null)
        {
          return null;
        }
        try
        {
          return delegateClass.getConstructor(new Class[] {coreClass});
        }
        catch (NoSuchMethodException e)
        {
          Class[] interfaces = coreClass.getInterfaces();
          for (int i = 0; interfaces != null && i < interfaces.length; i++)
          {
            Class interfaceClass = interfaces[i];
            Constructor delegateConstructor = findBestMatchConstrustor(delegateClass, interfaceClass);
            if(delegateConstructor != null)
            {
              return delegateConstructor;
            }
          }
          Constructor delegateConstructor = findBestMatchConstrustor(delegateClass, coreClass.getSuperclass());
          if(delegateConstructor != null)
          {
            return delegateConstructor;
          }
        }
        return null;
      }
    }
    public static Object create(Class clazz, Object core)
    {
      return Proxy.newProxyInstance(clazz.getClassLoader(), new Class [] {clazz}, new MixinInvocationHandler(clazz, core));
    }
  }
}