I have a lot of classes UNO,HAV,MAS,KOS
I want to create a factory pattern.
validator.load("UNO").validate();
I need dynamically load classes into validator class and return an instance.
(dynamically set name of the class and return an instance)
My problem is: how can I return the instance of a class, if I have incompatible types?
I don't know what to write in return type of method.
The main problem in the Validator CLASS.
public SegmentAbstract load(String str) {
AND
return SegmentAbsClass.forName(identify);
Main class
try{
validator.load("UNO").validate();
}catch(Exception e){
System.out.print("No class ");
}
Abstract Class (SegmentAbstract)
public abstract class SegmentAbstract {
public abstract Boolean validate();
}
Class UNO
public class UNA extends SegmentAbstract{
public Boolean validate() {
System.out.print("UNO!!");
return true;
}
}
Class Validator
public class Validator {
public SegmentAbstract load(String str) {
String identify = str.substring(0, 3);
try {
return SegmentAbsClass.forName(identify);
}
catch(Exception e) {
return this;
}
}
}
Try this :
public interface Validator {
boolean validate(Object obj);
}
public final class ValidatorFactory {
private ValidatorFactory(){}
public static Validator load(String type){
try {
Class<?> clazz = Class.forName(type);
if (Arrays.asList(clazz.getInterfaces()).contains(Validator.class)){
return (Validator) clazz.newInstance();
}
throw new IllegalArgumentException("Provided class doesn't implement Validator interface");
} catch (Exception e) {
throw new IllegalArgumentException("Wrong class provided", e);
}
}
}
Maybe this will help???
I will do something like that:
// ISegment.java
public interface ISegment {
Boolean validate();
}
// Uno.java
public class Uno implements ISegment {
public Boolean validate() {
System.out.print("UNO!!");
return true;
}
}
// SegmentFactory.java
public final class SegmentFactory {
public static enum Supported {
UNO("uno", Uno.class), /* ... */, HAV("hav", Hav.class);
private final Class<?> clazz;
private final String name;
private Supported(final String name, final Class<?> clazz) {
this.name = name;
this.clazz = clazz;
}
public Class<?> getClazz() {
return clazz;
}
public static Supported for(final String name) {
for (final Supported s : values()) {
if (s.name.equals(name) {
return s;
}
}
return null; // a default one
}
}
public static ISegment create(final Supported supp) {
if (supp == null) {
return null;
}
return supp.getClazz.newInstance();
}
private SegmentFactory() {
// avoid instantiation
}
}
usage:
final ISegment sa = SegmentFactory.create(SegmentFactory.Supported.for("uno"));
sa.validate();
Not tested!!
Take a look here. Briefly, the idea is to create a map in your factory class (Map<String,String>, key is identifier, value is fully qualified class name), and add supported classes during initialization. Then you use reflection to instantiate an object in your factory method. Also, you can avoid reflection by using Map<String, SegmentAbstract> instead of Map<String,String> and adding public abstract getNewSegment() to your SegmentAbstract class.
Related
I'm implementing a strategy pattern for exceptions handling
public class GlobalExceptionHandler {
private interface Strategy<T extends Exception> {
ErrorResponse extract(T e);
}
private static class ResponseStatusStrategy implements Strategy<ResponseStatusException> {
#Override
public ErrorResponse extract(ResponseStatusException e) {
return ErrorResponse.builder()
.status(e.getStatus())
.message(e.getReason())
.description(e.getReason())
.build();
}
}
private static class IllegalStateStrategy implements Strategy<IllegalStateException> {
#Override
public ErrorResponse extract(IllegalStateException e) {
return ErrorResponse.builder()
.status(HttpStatus.INTERNAL_SERVER_ERROR)
.message(e.getMessage())
.description("")
.build();
}
}
....
I call this API like this:
Exception ex = ....; // function param
if (ex instanceof ResponseStatusException) {
errorResponse = new ResponseStatusStrategy().extract((ResponseStatusException) ex);
} else if (ex instanceof IllegalStateException) {
errorResponse = new IllegalStateStrategy().extract((IllegalStateException) ex);
} else {
errorResponse = new EmptyStrategy().extract(ex);
}
Is there a more efficient and beautiful way to implement this? Idea gets me hint that I even didn't use interface method: "method extract(T e) is never used".
It would be great to have API like this:
Strategy<???> strategy;
if (ex instanceof ResponseStatusException) {
strategy = new ResponseStatusStrategy();
} else if (ex instanceof IllegalStateException) {
strategy = new IllegalStateStrategy();
} else {
strategy = new EmptyStrategy();
}
errorResponse = strategy.extract(ex);
You are trying to solve an object creational problem. You want a particular Strategy class object based on the StatusException class. Create a new class with a factory pattern to return you the correct object. Here is some dummy code inspired from your code.
private interface Factory {
Strategy buildStrategy(Exception e);
}
private static class FactoryImpl implements Factory {
public Strategy buildStrategy(Exception e) {
if (e instanceof IOException) {
return new Strategy1();
} else {
return new EmptyStrategy();
}
}
}
private interface Strategy<T extends Exception> {
String extract();
}
private static class Strategy1 implements Strategy<IOException> {
#Override public String extract() {
return "Strategy1";
}
}
private static class EmptyStrategy implements Strategy<NamingException> {
#Override public String extract() {
return "EmptyStrategy";
}
}
public static void main(String[] args) {
var f = new FactoryImpl();
System.out.println(f.buildStrategy(new IOException()).extract());
System.out.println(f.buildStrategy(new NamingException()).extract());
}
I'm trying to create annotations from inner string which contains other annotations.
This is SimpleAnnotation that should be processed:
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.SOURCE)
public #interface SimpleAnnotation {
String[] value() default {};
}
This is annotated class
#SimpleAnnotation({
"#com.demo.annotations.Entity(name = \"simple_name\")",
"#com.demo.annotations.CustomAnnotation"
})
public class Simple {
}
The compilation result of annotated class should be
#com.demo.annotations.Entity(name = "simple_name")
#com.demo.annotations.CustomAnnotation
public class Simple {
}
I've tried to use custom annotation processor
that processes class declaration. It gets class modifiers with annotations and analyzes derived annotation as tree
public class SimpleAnnotationProcessor extends AbstractProcessor {
private Messager messager;
private Trees trees;
private ChangeTranslator visitor;
#Override
public Set<String> getSupportedAnnotationTypes() {
return Collections.singleton(SimpleAnnotation.class.getCanonicalName());
}
#Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.RELEASE_8;
}
#Override
public synchronized void init(ProcessingEnvironment processingEnv) {
............
}
#Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
Set<? extends Element> elementsAnnotatedWith = roundEnv.getElementsAnnotatedWith(SimpleAnnotation.class);
for (Element element : elementsAnnotatedWith) {
Name simpleName = element.getSimpleName();
System.out.println(simpleName);
messager.printMessage(Diagnostic.Kind.NOTE, "found with annotation " + simpleName);
JCTree tree = (JCTree) trees.getTree(element);
visitor.setElement(element);
tree.accept(visitor);
}
return true;
}
public class ChangeTranslator extends TreeTranslator {
private JavacProcessingEnvironment javacProcessingEnvironment;
private TreeMaker treeMaker;
private Messager messager;
public ChangeTranslator(JavacProcessingEnvironment javacProcessingEnvironment, TreeMaker treeMaker, Messager messager) {
this.javacProcessingEnvironment = javacProcessingEnvironment;
this.treeMaker = treeMaker;
this.messager = messager;
}
#Override
public void visitClassDef(JCTree.JCClassDecl jcClassDecl) {
super.visitClassDef(jcClassDecl);
if (isNeedProcessing(jcClassDecl)) {
JCTree.JCModifiers modifiers = jcClassDecl.getModifiers();
List<JCTree.JCAnnotation> annotations = modifiers.getAnnotations();
List<JCTree.JCAnnotation> jcAnnotations = List.nil();
for (JCTree.JCAnnotation a : annotations) {
if (a.getAnnotationType().toString().contains(SimpleAnnotation.class.getSimpleName())) {
List<JCTree.JCExpression> arguments = a.getArguments();
for (JCTree.JCExpression arg : arguments) {
JCTree.JCNewArray expressions = (JCTree.JCNewArray) ((JCTree.JCAssign) arg).getExpression();
List<JCTree.JCExpression> elems = expressions.elems;
for (JCTree.JCExpression expression : elems) {
// parse annotation from string
String value = (String) ((JCTree.JCLiteral) expression).getValue();
// e.g com.demo.annotations.Entity
String substringName = value.trim().substring(1, 28);
Class<? extends Class> aClass = null;
try {
aClass = Class.forName(substringName);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
// 1 - attribute to create annotation from
Attribute attribute = new Attribute.Compound(aClass, null);
// 2 - place where annotation should be created
treeMaker.Annotation(attribute);
}
}
}
}
modifiers.annotations = jcAnnotations;
System.out.println(result);
}
}
private boolean isNeedProcessing(JCTree.JCClassDecl jcClassDecl) {
return jcClassDecl.getModifiers().toString().contains("#SimpleAnnotation");
}
}
}
The issue is to get information from Class type to create com.sun.tools.javac.code.Type.ClassType which is used to create JCAnnotation.
Any help is appreciated.
public class SimpleAnnotationProcessor extends AbstractProcessor {
...
#Override
public void visitClassDef(JCTree.JCClassDecl jcClassDecl) {
...
ListBuffer<JCTree.JCExpression> params = new ListBuffer<JCTree.JCExpression>();
params.append(treeMaker.Assign(treeMaker.Ident(names.fromString("name")), treeMaker.Literal("simple_name")));
JCTree.JCAnnotation entity = treeMaker.Annotation(select("com.demo.annotations.Entity"), params.toList());
JCTree.JCAnnotation customAnnotation = treeMaker.Annotation(select("com.demo.annotations.CustomAnnotation"), List.nil());
// then append annotation to modifiers of you want
// NOTE: List<A>.append() method will return a new List in javac
...
}
JCTree.JCExpression select(String path) {
JCTree.JCExpression expression = null;
int i = 0;
for (String split : path.split("\\.")) {
if (i == 0)
expression = treeMaker.Ident(names.fromString(split));
else {
expression = treeMaker.Select(expression, names.fromString(split));
}
i++;
}
return expression;
}
}
Hope it helps those who have the same problem
So I have a class that contains a String-field:
public class A {
private String type = ...
public String getType(){
return this.type;
}
public void setType(String type){
this.type = type;
}
}
I also have a list of all possible types, there are twelve and possibly more in the future.
Now I want to write a method that gets an object of class A and calls a specific method depending on which "type" is in the class.
Is there a smarter solution than writing 12 (or more) if-statements?
Normally I would use the Visitor-pattern but I don't want to create twelve new classes.
edit:
I ended up creating a
Map<String,Function<A,String>> map = new HashMap<String,Function<A,String>>
and then call
A a;
...
map.get(a.getType).apply(a);
Instead of storing type as a "free-form" text value, you should be using an enum, since you have a well-defined list of values.
You can even have the different enums implement the same method differently, by using an abstract method. This will allow you to totally eliminate the error-prone switch statements.
Below is an example showing both instance values and abstract methods. The pattern shown will keep the implementation out of the enum, while having the compiler catch all uses when a new enum is added.
public enum Type {
INTEGER("Integer") {
#Override
public void apply(Action action, A a) {
action.applyInteger(a);
}
},
STRING ("Text") {
#Override
public void apply(Action action, A a) {
action.applyString(a);
}
};
private String displayName;
private Type(String displayName) {
this.displayName = displayName;
}
public String getDisplayName() {
return this.displayName;
}
public abstract void apply(Action action, A a);
}
public interface Action {
public void applyInteger(A a);
public void applyString(A a);
}
public class A {
private Type type;
public Type getType(){
return this.type;
}
public void setType(Type type){
this.type = type;
}
public void apply(Action action) {
this.type.apply(action, this);
}
}
When you add a new type to the TYPE enum, you also add a new method to the Action interface, which will force you to implement that method in all implementations of the interface. With switch statements, you'd get no such safety.
If you are using JDK 7 or greater go for a switch which accepts String as a parameter and write cases for each.
switch (type) {
case "SomeX":
yourInstance.invokeMethod();
break;
case "SomeY":
...
I guess the other answers are correct but, by reading the question I think the more direct answer will be using introspection and convention:
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Test {
public static class A {
private String type;
public String getType(){
return this.type;
}
public void setType(String type){
this.type = type;
}
}
public static class Actions {
public void runForType1(A a) {
System.out.println("It's type 1");
}
public void runForType2(A a) {
System.out.println("It's type 2");
}
public void runForType3(A a) {
System.out.println("It's type 3");
}
}
public static class Runner {
Actions actions;
public Runner(Actions a) {
this.actions = a;
}
public void run(A a) {
try {
Method m = actions.getClass().getMethod("runFor" + a.getType(), A.class);
m.invoke(actions, a);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
Runner r = new Runner(new Actions());
A type1 = new A();
type1.setType("Type1");
A type2 = new A();
type2.setType("Type2");
A type3 = new A();
type3.setType("Type3");
r.run(type1);
r.run(type2);
r.run(type3);
}
}
expected output for the example will be:
It's type 1
It's type 2
It's type 3
If convention is not possible you can always create a HashMap with a type to method name mapping.
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);
}
}
}
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);
}
}