I'm creating a library and in this library, It will contain Shapes more precisely Regular and Irregular Polygons, this library must allow the users to not only use my shapes but also in runtime be able to create his own.

At the moment I have a few shapes provided like so:

Polygon
|- PolygonRegular
   |- Square
   |- Circle
   |- EquilateralTriangle implements Triangle
|- PolygonIrregular
   |- Trapeze
   |- IsoscelesTriangle implements Triangle

Now in this given scenario, let's say I as a user want to create my custom Polygon in this case "ScaleneTriangle" in which will further also implement the Triangle interface, my library must easily provide the tools necessary to create this "factory" to create shapes.

  //Though I don't know the code, what I wanted to achieve, would be something very close to:

    Point2D[] points = new Point2D[]{
            new Point2D.Float(0f, 0f),
            new Point2D.Float(0.25f, 0f),
            new Point2D.Float(1f, 1f),
    };

    ContentFactory.create(PolygonIrregular.class, "ScaleneTriangle", points);

However, I have no idea How can I make a ContentFactory just like this, that create classes in runtime just like it was magic... I will also magically gonna have to create instances of these classes too.

To give about more understanding in case the problem wasn't very clarified: Imagine I'm a user, a canvas pop, draw a new shape. Confirms. A buttonRepresentation is created whit this new shape. Every time the user clicks in buttonRepresentation an element is created whit the shape.

1 Answers

1
Dean On Best Solutions

There are a few ways to do this.

In this article, it is done using jOOQ, but you can re implement their method if you don't want an extra dependency. (archive for posterity)

The way that I have done it in the past (just as a test), was to use a compiler from janino to compile a string to a class which implements an interface which is known at compile time. It's in kotlin, but it would be easy to convert to Java.

package com.dmercer

import org.codehaus.janino.SimpleCompiler;
import org.codehaus.janino.util.Benchmark

fun main(args: Array<String>) {
    val sourceString = """
package com.dmercer;

public class B implements BasicInterface {
    @Override
    public void runMethod() {
        System.out.println("Hello from compiled method");
    }
}
    """.trimIndent()

    val compiler = SimpleCompiler()
    compiler.cook(sourceString)
    val classLoader = compiler.classLoader
    val compiledClass = classLoader.loadClass("com.dmercer.B")// as IDBMethod
    val classInstance = compiledClass.newInstance() as BasicInterface 
    classInstance.runMethod()

}