I have a android application, but it is not relevant.
I have a class called "Front controller" which will receive some message
through it's constructor. The message, for brievity, could be an integer.
I want somewhere else to create a new controller which will execute
a method based on the integer defined above
public class OtherController {
#MessageId("100")
public void doSomething(){
//execute this code
}
#MessageId("101")
public void doSomethingElse(){
//code
}
}
The front controller could be something like this:
public class FrontController {
private int id;
public FrontController(int id){
this.id=id;
executeProperControllerMethodBasedOnId();
}
public void executeProperControllerMethodBasedOnId(){
//code here
}
public int getId(){
return id;
}
}
So, if the Front Controller will receive the integer 100, it
will execute the method annotated with #MessageId(100). The
front controller don't know exactly the class where this method
is.
The problem which I found is that I need to register somehow
each controller class. I Spring I had #Component or #Controller
for autoloading. After each controllers are register, I need to
call the properly annotated method.
How to achieve this task? In Spring MVC, I had this system
implemented, used to match the HTTP routes. How could I implement
this in a plain java project?
Any suggestions?
Thanks to Google Reflections (hope you can integrate this in your android project.)
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections-maven</artifactId>
<version>0.9.8</version>
</dependency>
For optimisation I've added the requirement to also annotate the class with MessageType annotation and the classes should be in the same package (org.conffusion in my example):
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.TYPE)
public #interface MessageType {
}
The OtherController looks like:
#MessageType
public class OtherController {
#MessageId(id=101)
public void method1()
{
System.out.println("executing method1");
}
#MessageId(id=102)
public void method2()
{
System.out.println("executing method2");
}
}
The implementation will look like:
public void executeProperControllerMethodBasedOnId() {
Set<Class<?>> classes = new org.reflections.Reflections("org.conffusion")
.getTypesAnnotatedWith(MessageType.class);
System.out.println("found classes " + classes.size());
for (Class<?> c : classes) {
for (Method m : c.getMethods()) {
try {
if (m.isAnnotationPresent(MessageId.class)) {
MessageId mid = m.getAnnotation(MessageId.class);
Object o = c.newInstance();
if (mid.id() == id)
m.invoke(o);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
Maybe you can optimise and build a static hashmap containing already scanned message ids.
You need to implement some of the work by yourself using reflection, I would recommend to prepare message handlers on initial phase in regards to performance. Also you possibly want to think about Singleton/Per Request controllers. Some of the ways to implement the solution:
interface MessageProcessor {
void execute() throws Exception;
}
/* Holds single instance and method to invoke */
class SingletonProcessor implements MessageProcessor {
private final Object instance;
private final Method method;
SingletonProcessor(Object instance, Method method) {
this.instance = instance;
this.method = method;
}
public void execute() throws Exception {
method.invoke(instance);
}
}
/* Create instance and invoke the method on execute */
class PerRequestProcessor implements MessageProcessor {
private final Class clazz;
private final Method method;
PerRequestProcessor(Class clazz, Method method) {
this.clazz = clazz;
this.method = method;
}
public void execute() throws Exception {
Object instance = clazz.newInstance();
method.invoke(instance);
}
}
/* Dummy controllers */
class PerRequestController {
#MessageId(1)
public void handleMessage1(){System.out.println(this + " - Message1");}
}
class SingletonController {
#MessageId(2)
public void handleMessage2(){System.out.println(this + " - Message2");}
}
class FrontController {
private static final Map<Integer, MessageProcessor> processors = new HashMap<Integer, MessageProcessor>();
static {
try {
// register your controllers
// also you can scan for annotated controllers as suggested by Conffusion
registerPerRequestController(PerRequestController.class);
registerSingletonController(SingletonController.class);
} catch (Exception e) {
throw new ExceptionInInitializerError();
}
}
private static void registerPerRequestController(Class aClass) {
for (Method m : aClass.getMethods()) {
if (m.isAnnotationPresent(MessageId.class)) {
MessageId mid = m.getAnnotation(MessageId.class);
processors.put(mid.value(), new PerRequestProcessor(aClass, m));
}
}
}
private static void registerSingletonController(Class aClass) throws Exception {
for (Method m : aClass.getMethods()) {
if (m.isAnnotationPresent(MessageId.class)) {
MessageId mid = m.getAnnotation(MessageId.class);
Object instance = aClass.newInstance();
processors.put(mid.value(), new SingletonProcessor(instance, m));
}
}
}
/* To process the message you just need to look up processor and execute */
public void processMessage(int id) throws Exception {
if (processors.containsKey(id)) {
processors.get(id).execute();
} else {
System.err.print("Processor not found for message " + id);
}
}
}
Related
I have method that is called by another service and it just change one of the field for some rows in database. Method looks like this:
void errorOrders() {
List<Orders> orders = OrderDAO.getErrorOrders(); //select only fields with status 'error'
orders.forEach(order -> order.setStatus(OrderStatus.NEW);
//some logging etc.
}
Is there any way to unit test this method? Can I inject myself inside this method and check if orders status was changed?
Cheers!
I would recommend you refactor your class to make your code testable. Ideally you would inject the dependency that represents the OrderDAO:
class ErrorChecker {
private final OrderDAO orderDAO;
public ErrorChecker(OrderDAO orderDAO) {
this.orderDAO = orderDAO;
}
public void errorOrders() {
List<Orders> orders = orderDAO.getErrorOrders();
orders.forEach(order -> order.setStatus(OrderStatus.NEW);
}
}
Then your test code would look like:
#Test
void testErrorOrders() {
Order order1 = mock(Order.class);
Order order2 = mock(Order.class);
OrderDAO orderDAO = mock(OrderDAO.class);
when(orderDAO.getErrorOrders()).thenReturn(List.of(order1, order2));
ErrorChecker errorChecker = new ErrorChecker(orderDAO);
errorChecker.errorOrders();
verify(order1).setState(OrderStatus.NEW);
verify(order2).setState(OrderStatus.NEW);
}
There are ways to mock static methods but I would recommend refactoring to inject the dependencies as it has many other benefits beside testability.
If you need to leave the method as static then you can still mock it (in v3.4+ of Mockito):
#Test
void testErrorOrders() {
try (MockedStatic mocked = mockStatic(OrderDAO.class)) {
mocked.when(OrderDAO.getErrorOrders()).thenReturn(List.of(order1, order2));
ErrorChecker errorChecker = new ErrorChecker(orderDAO);
errorChecker.errorOrders();
mocked.verify(order1).setState(OrderStatus.NEW);
}
}
#ismail and #khelwood already provided good answers.
If you mock the Object, you can control/see what happens to it
If you change an Object, where you can access the state via public methods, use those
If you change an Object whose state you cannot access with normal code, use Java Reflections to look at member variables.
If you set up Objects, that pass their data to streams and other output, you can put some additional streams etc in between. Use inheritance and reflection if necessary
Simple example of using Reflection on a shielded class:
package stackoverflow.simplefieldaccess;
public class ShieldedClass {
private int mStatus;
public ShieldedClass() {
mStatus = 666;
}
public void setStatus(final int pStatus) {
mStatus = pStatus; // usually with ints be careful and do checks here, but for the sake of simplicity we leave that out
}
#Override public String toString() {
return getClass().getSimpleName() + "[status:" + mStatus + "]";
}
}
Code to access it via reflection in a few ways:
package stackoverflow.simplefieldaccess;
import java.lang.reflect.Field;
import jc.lib.lang.reflect.JcFieldAccess;
public class SimpleFieldAccess {
public static void main(final String[] args) throws NoSuchFieldException, SecurityException {
final ShieldedClass so = new ShieldedClass();
System.out.println("Object.status before change: " + so);
so.setStatus(667);
System.out.println("Object.status after change: " + so);
System.out.println();
System.out.println("Accessing Object.status via Reflection...");
final Class<? extends ShieldedClass> cls = so.getClass();
final Field fieldToChance = cls.getDeclaredField("mStatus");
{
System.out.println("\nBad read access");
try { // will result in java.lang.IllegalAccessException
System.out.println("\tReading Object.status fiels via Reflection: " + fieldToChance.getInt(so));
throw new IllegalStateException("UNEXOECTED ERROR!");
} catch (final java.lang.IllegalAccessException e) {
System.out.println("\tAs expected: IllegalAccessException");
}
}
{
System.out.println("\nBad write access");
try { // will result in java.lang.IllegalAccessException
fieldToChance.set(so, Integer.valueOf(1337));
System.out.println("\tObject.status after change: " + so);
} catch (final java.lang.IllegalAccessException e) {
System.out.println("\tAs expected: IllegalAccessException");
}
}
{
System.out.println("\nGood manual read and write access");
final boolean isFieldOriginallyAccessible = fieldToChance.isAccessible();
try { // will result in java.lang.IllegalAccessException
if (!isFieldOriginallyAccessible) fieldToChance.setAccessible(true);
System.out.println("\tReading Object.status field via Reflection: " + fieldToChance.getInt(so));
fieldToChance.set(so, Integer.valueOf(4321));
System.out.println("\tObject.status after change: " + so);
} catch (final java.lang.IllegalAccessException e) {
e.printStackTrace();
} finally {
if (!isFieldOriginallyAccessible) fieldToChance.setAccessible(false);
}
}
{
System.out.println("\nGood automated read and write access");
try (JcFieldAccess fa = new JcFieldAccess(fieldToChance)) { // will result in java.lang.IllegalAccessException
System.out.println("\tReading Object.status field via Reflection: " + fieldToChance.getInt(so));
fieldToChance.set(so, Integer.valueOf(123));
System.out.println("\tObject.status after change: " + so);
} catch (final java.lang.IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
For reflections, when I want to access fields, I use my homebrew class that makes it easier to get access to the field and afterwards restore it to normal (last example above uses this):
package jc.lib.lang.reflect;
import java.io.Closeable;
import java.lang.reflect.AccessibleObject;
public class JcFieldAccess implements Closeable {
private final AccessibleObject mField;
private final boolean mIsAccessible;
public JcFieldAccess(final AccessibleObject pField) {
mField = pField;
mIsAccessible = mField.isAccessible();
if (!mIsAccessible) mField.setAccessible(true);
}
#Override public void close() {
if (mIsAccessible) return;
if (mField != null) mField.setAccessible(false);
}
}
The trick with this util class is that when used in a try-resource block, its close() method will get called automatically, whether the block fails or not. It's the same as having the close() or in this case setAccessible(false) call in the finally block, with some extra checks.
Let the class be:
class HandleErrorOrders {
private OrderDAO orderDAO;
HandleErrorOrders(final OrderDAO orderDAO) {
this.orderDAO = orderDAO;
}
public void errorOrders() {
List<Orders> orders = OrderDAO.getErrorOrders(); //select only fields with status 'error'
orders.forEach(order -> order.setStatus(OrderStatus.NEW);
//some logging etc.
}
}
You need to use assert methods to check end state.
To test, write something like:
class HandleErrorOrdersTest {
#Mock
private OrderDAO orderDAO;
#InjectMocks
private HandleErrorOrders handleErrorOrders;
#Test
void testErrorOrders() {
Order order1 = mock(Order.class);
Order order2 = mock(Order.class);
when(orderDAO.getErrorOrders()).thenReturn(List.of(order1, order2));
ErrorChecker errorChecker = new ErrorChecker(orderDAO);
errorChecker.errorOrders();
//asset checks
Assert.assertEquals(OrderStatus.NEW, order1.getStatus());
Assert.assertEquals(OrderStatus.NEW, order2.getStatus());
//verification checks
Mockito.verify(orderDAO).getErrorOrders();
}
}
First I'm not sure if it's a good idea to do all this.
Goal is to create some interfaces with annotations to hide legacy position based string access out of a configuration database, without implementing each interface.
Declarative configured Interface:
public interface LegacyConfigItem extends ConfigDbAccess{
#Subfield(length=3)
String BWHG();
#Subfield(start = 3, length=1)
int BNKST();
#Subfield(start = 4, length=1)
int BEINH();
:
}
Base interface for runtime identification
public interface ConfigDbAccess{
}
Dummy implementation without functionality, may change.
public class EmptyImpl {
}
Beanfactory and MethodInvocation interceptor, to handle the unimplemented methods.
#Component
public class InterfaceBeanFactory extends DefaultListableBeanFactory {
protected static final int TEXT_MAX = 400;
#Autowired
private EntityRepo entityRepo;
public <T> T getInstance(Class<T> legacyInterface, String key) {
ProxyFactory factory = new ProxyFactory(new EmptyImpl());
factory.setInterfaces(legacyInterface);
factory.setExposeProxy(true);
factory.addAdvice(new MethodInterceptor() {
#Override
public Object invoke(MethodInvocation invocation) throws Throwable {
KEY keyAnnotation = invocation.getThis().getClass().getAnnotation(Key.class);
String key= keyAnnotation.key().toUpperCase();
String ptart = invocation.getMethod().getDeclaringClass().getSimpleName();
Vpt result = entityRepo.getOne(new EntityId(ptart.toUpperCase(), schl.toUpperCase()));
Subfield sub = invocation.getMethod().getAnnotation(Subfield.class);
//TODO: Raise missing Subfield annotation
int start = sub.start();
int length = sub.length();
if (start + length > TEXT_MAX) {
//TODO: Raise invalid Subfield config
}
String value = result.getTextField().substring(start,start+length);
return value;
}
});
return (T) factory.getProxy();
}
#Override
protected Map<String, Object> findAutowireCandidates(String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {
Map<String, Object> map = super.findAutowireCandidates(beanName, requiredType, descriptor);
if (ConfigDbAccess.class.isAssignableFrom(requiredType )) {
:
#SpringBootApplication
public class JpaDemoApplication {
#Autowired
private ApplicationContext context;
public static void main(String[] args) {
SpringApplication app = new SpringApplication(JpaDemoApplication.class);
// app.setApplicationContextClass(InterfaceInjectionContext .class);
app.run(args);
}
public class InterfaceInjectionContext extends AnnotationConfigApplicationContext {
public VptInjectionContext () {
super (new InterfaceBeanFactory ());
}
}
So far I got all this stuff working, except when I try to set the applications Context class to my DefaultListableBeanFactory, I'm killing the Spring boot starter web. The application starts, injects the the Autowired fields with my intercepted pseudo implementaition --- and ends.
I think I'm doing something wrong with registering the DefaultListableBeanFactory, but I've no idea how to do it right.
To get this answered:
M. Deinum pointed me to a much simpler solution:
Instead of creating a BeanFactory I installed a BeanPostProcessor with this functioniality.
#RestController
public class DemoRestController {
#Autowired
VptService vptService;
#ConfigItem(key="KS001")
private PrgmParm prgmKs001;
#ConfigItem(key="KS002")
private PrgmParm prgmKs002;
public DemoRestController() {
super();
}
Where the ConfigItem annotation defines the injection point.
Next I created a CustomBeanPostProcessor which scans all incoming beans for
fields having a ConfigItem annotation
#Component
public class CustomBeanPostProcessor implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
for (Field field : bean.getClass().getDeclaredFields()) {
SHL cfgDef = field.getAnnotation(ConfigItem.class);
if (cfgDef != null) {
Object instance = getlInstance(field.getType(), cfgDef.key());
boolean accessible = field.isAccessible();
field.setAccessible(true);
try {
field.set(bean, instance);
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
field.setAccessible(accessible);
}
}
return bean;
}
The getInstnce(field.getType(),cfgDef.key()) creates a proxy with the MethodInterceptor, which does the work.
There are a lot of things to finalize, but all in all it looks good to me.
this question was asked many times but I couldn't find elegant workaround for it.
This example works as desired:
public class RequestWrapper<T> {
private final T request;
private final Class<T> type;
public RequestWrapper(T request, Class<T> type) {
this.request = request;
this.type = type;
}
public T getRequest() {
return request;
}
public Class<T> getType() {
return type;
}
}
public class Service {
private void invoke(String request) {
System.out.println("String:" + request);
}
private void invoke(Object request) {
System.out.println("Object:" + request + "," + request.getClass().getSimpleName());
}
public static void main(String[] args) {
RequestWrapper<String> sw = new RequestWrapper<String>("A", String.class);
RequestWrapper<Integer> iw = new RequestWrapper<Integer>(Integer.valueOf(0), Integer.class);
new Service().invoke(sw.getRequest());
new Service().invoke(iw.getRequest());
}
}
But I would need to add one more method to Service class which do something before/after call of invoke method:
public void invoke(RequestWrapper<?> wrapper) {
try {
// ...
invoke(wrapper.getType().cast(wrapper.getRequest()));
invoke(wrapper.getRequest());
} catch(Exception e ) {
// ...
}
}
then the main method would contain:
new Service().invoke(sw);
I understand the reason why the invoke(Object request) is used instead of invoke(String request).
What would be an elegant solution to call proper invoke method and be able to do some common actions before/after it?
To have an interface e.g. Invoker, implement it e.g. StringInvoker, Invoker> and call map.get(wrapper.getType()).invoke(wrapper.getRequest()) is possible solution but I expect something better.
You can check the type and explicitly cast it, for example (I also added Integer so you can see branching on more types):
Class<?> c = wrapper.getType();
if (c == String.class)
invoke((String) wrapper.getRequest()); // Invokes invoke(String)
else if (c == Integer.class)
invoke((Integer) wrapper.getRequest()); // Invokes invoke(Integer)
else
invoke(wrapper.getRequest()); // Invokes invoke(Object)
Note:
If you go on this path, you don't even need to store the request type in the RequestWrapper class because you can just as easily use the instanceof operator on the request itself to check its type. And if you "get rid" of the request type, your current RequestWrapper class will only contain the request so the RequestWrapper is not even needed in this case.
Visitor patter can serves to solve it. Only drawback is that there isn't possible to write:
new Service().invoke(new RequestWrapper<String>("A"));
My implementation:
public class Service {
public void invoke(RequestWrapper<?> wrapper) {
try {
// ...
wrapper.invoke(this);
} catch(Exception e ) {
// ...
}
}
public void invoke(String request) {
System.out.println("String:" + request);
}
public void invoke(Boolean request) {
System.out.println("Boolean:" + request);
}
public static void main(String[] args) {
RequestWrapper<Boolean> rw = new BooleanRequestWrapper(Boolean.TRUE);
new Service().invoke(rw);
}
}
abstract class RequestWrapper<T> {
protected final T request;
public RequestWrapper(T request) {
this.request = request;
}
public abstract void invoke(Service v);
}
class BooleanRequestWrapper extends RequestWrapper<Boolean> {
public BooleanRequestWrapper(Boolean request) {
super(request);
}
public void invoke(Service service) {
service.invoke(request);
}
}
So I am testing a simple Google Guice interceptor -
My Annotation -
#Retention(RetentionPolicy.RUNTIME) #Target(ElementType.METHOD)
public #interface AppOpsOperation {
}
My Interceptor
public class AppOpsOperationDecorator implements MethodInterceptor {
private ServiceCallStack callStack = null ;
#Inject
public void setServiceCallStack(ServiceCallStack stack ){
callStack = stack ;
}
#Override
public Object invoke(MethodInvocation arg0) throws Throwable {
// Retrieve the call stack
// exclude service population if caller service is the same service
// else push the current service onto top of stack
System.out.println("Intercepting method -- :: " + arg0.getMethod().getName());
System.out.println("On object - :: " + arg0.getThis().getClass().getName());
System.out.println("On accessible object - :: " + arg0.getStaticPart().getClass().getName());
return invocation.proceed();
}
}
And now my Service interface and method
public interface MockCalledService extends AppOpsService {
#AppOpsOperation
public String methodOneCalled(String some);
#AppOpsOperation
public String methodTwoCalled(String some);
}
public class MockCalledServiceImpl extends BaseAppOpsService implements MockCalledService {
#Override
#AppOpsOperation
public String methodOneCalled(String some) {
System.out.println("MockCalledServiceImpl.methodOneCalled()");
return this.getClass().getCanonicalName() + "methodOneCalled";
}
#Override
public String methodTwoCalled(String some) {
System.out.println("MockCalledServiceImpl.methodTwoCalled()");
return this.getClass().getCanonicalName() + "methodTwoCalled";
}
}
And my Guice test module
public class MockTestGuiceModule extends AbstractModule {
#Override
protected void configure() {
bind(ServiceCallStack.class).toInstance(new ServiceCallStack());
AppOpsOperationDecorator decorator = new AppOpsOperationDecorator() ;
requestInjection(decorator);
bindInterceptor(Matchers.any(), Matchers.annotatedWith(AppOpsOperation.class),
decorator);
bind(MockCalledService.class).toInstance(new MockCalledServiceImpl());
}
}
This interceptor doesn't execute when I run the test below -
public class AppOpsOperationDecoratorTest {
private Injector injector = null ;
#Before
public void init(){
injector = Guice.createInjector(new MockTestGuiceModule());
}
#Test
public void testDecoratorInvocation() {
MockCalledService called = injector.getInstance(MockCalledService.class);
called.methodOneCalled("Test String");
}
}
Can you please highlight what I am doing wrong ?
I am answering after finding the real reason. Its so simple that its really tricky.
Method interception only works if you bind the interface with the class and not an instance of this implementation.
so instead of bind(MockCalledService.class).toInstance(new MockCalledServiceImpl());
we should write bind(MockCalledService.class).to(MockCalledServiceImpl.class);
Seems instances are not proxied :(
I keep getting the error: java.lang.NoSuchMethodException: com.production.workflow.MyWorkflow.<init>(com.production.model.entity.WorkflowEntity)
I have a constructor that is expecting WorkflowEntity so I'm not able to figure out why it's saying NoSuchMethod. Is there something about constructor inheritance that is preventing this from instantiating?
My instantiation factory:
public static Workflow factory(WorkflowEntity workflowEntity) {
try {
Class<?> clazz = Class.forName(workflowEntity.getClassName()).asSubclass(Workflow.class);
Constructor c = clazz.getConstructor(WorkflowEntity.class);
Object workflowClass = c.newInstance(clazz);
return (Workflow) workflowClass;
} catch (Exception e) {
e.printStackTrace();
logger.severe("Unable to instantiate "+workflowEntity.getClassName()+" class: " + e.getLocalizedMessage());
}
return null;
}
Workflow class:
public class MyWorkflow extends Workflow {
//no constructors
Extended class:
abstract public class Workflow {
protected static final Logger logger = Logger.getLogger(Workflow.class.getName());
private WorkflowEntity entity;
protected WorkflowProcess workflowProcess;
#Autowired
private WorkflowProcessService workflowProcessService;
/* Don't use this one */
public Workflow() { }
/* Default constructor */
public Workflow (WorkflowEntity entity) {
this.entity = entity;
//get first workflow process
//#todo this should factor in rule, for multiple starting points
for (WorkflowProcessEntity workflowProcessEntity : entity.getWorkflowProcesses()) {
workflowProcess = WorkflowProcess.factory(workflowProcessEntity);
break;
}
}
There are two problems in your code:
Constructors are not automatically inherited by subclasses. You need to add the MyWorkflow(WorkflowEntity) constructor to the MyWorkflow class.
Your new instance call needs to be made with the workflowEntity instance (and not the class instance you are giving it now)
Here:
class MyWorkflow extends Workflow {
public MyWorkflow() {
super();
}
public MyWorkflow(WorkflowEntity entity) {
super(entity);
}
}
public static Workflow factory(WorkflowEntity workflowEntity) {
try {
Class<?> clazz = Class.forName(workflowEntity.getClassName())
.asSubclass(Workflow.class);
Constructor<?> c = clazz.getConstructor(WorkflowEntity.class);
Object workflowClass = c.newInstance(workflowEntity);
return (Workflow) workflowClass;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
Consider the builder pattern instead of the factory pattern. Here is an example that builds a WorkFlow that takes a WorkflowEntity constructor parameter and builds a workFlow that does not take a WorkFlowEntity pattern (just showing multiple options available via a builder).
public class WorkFlowBuilder
{
private WorkflowEntity constructorParameter;
private Class workflowClass;
public WorkFlowBuilder(Class desiredWorkflowClass)
{
if (desiredWorkflowClass != null)
{
workflowClass = desiredWorkflowClass;
}
else
{
throw new IllegalArgumentException("blah blah blah");
}
}
public void setConstructorParameter(final WorkflowEntity newValue)
{
constructorParameter = newValue;
}
public WorkFlow build()
{
Object workflowObject;
if (constructorParameter != null)
{
Constructor constructor = workflowClass.getConstructor(WorkflowEntity.class);
Object workflowObject;
workflowObject = constructor.newInstance(workflowEntity);
}
else
{
workflowObject = workflowClass.newInstance();
}
return (WorkFlow)workflowObject;
}
}
Use this as follows:
WorkFlowBuilder builder = new WorkFlowBuilder(MyWorkFlow.class);
WorkflowEntity entity = new WorkFlowEntity();
WorkFlow item;
entity... set stuff.
builder.setConstructerParameter(entity)
item = builder.build();
I think you just want to pass in the workflowEntity into the constructor on the newInstance call, instead of the typed Class.
Constructors lost their outside visibility during inheritance.
You need to redefine it in MyWorkflow.
This is done so because sub classes may not support the super class creation process. So super object constructors does not make sense to sub classes and it's even unsafe if they were visible outside.
You should also remove the default constructor if your class can be used if instantiated without WorkflowEntity. Just remove it from Workflow and do not add to MyWorkflow.
UPD
You should also consider using generics to avoid class casting.
public Workflow create(WorkflowEntity workflowEntity) throws
ClassNotFoundException, NoSuchMethodException, SecurityException
, InstantiationException, IllegalAccessException
, IllegalArgumentException, InvocationTargetException {
Class<? extends Workflow> clazz = Class.forName(workflowEntity.getClassName()).asSubclass(Workflow.class);
Constructor<? extends Workflow> c = clazz.getConstructor(WorkflowEntity.class);
Workflow workflowClass = c.newInstance(clazz);
return workflowClass;
}
class WorkflowEntity {
public String getClassName() {
return "className";
};
}
class Workflow {
Workflow(WorkflowEntity entity) {
};
}
class MyWorkflow extends Workflow {
MyWorkflow(WorkflowEntity entity) {
super(entity);
}
}