I have RecipientTypesFactory that is going to create objects of the type RecipientType. For RecipientTypes object I have the followin hierarchy:
public interface RecipientType{
public abstract Object accept(RecipientTypeVisitor v);
}
public class DynamicGroupType implemetns RecipientType{
private Integer dynamicGroupId;
public Object accept(RecipientTypeVisitor visitor){
return visitor.visit(this);
}
//GET, SET
}
public class StaticGroupType implements RecipientType{
private Integer staticGroupId;
public Object accept(RecipientTypeVisitor visitor){
return visitor.visit(this);
}
//GET, SET
}
RecipientTypesFactory itself looks as follows:
public enum RecipientTypeEnum {
STATIC_GROUP, DYNAMIC_GROUP
}
public class RecipientTypesFactory{
private Map<RecipientTypeEnum, RecipientTypeCreator> creators;
public RecipientType createRecipientType(RecipientTypeEnum t){
return creators.get(t).create();
}
}
I'm not going to provide the actual definition of RecipientTypeCreator and its hierarchy because I don't think it's very important.
Now I have the controller:
public class CreateMailingController{
private RecipientTypesFactory recipientTypesFactory;
private Integer dynamicGroupId;
private Integer staticGroupId;
private RecipientTypeEnum selectedType;
//GET, SET, other staff
public void createMailing(){
Type t = recipientTypesFactory.createRecipientType(selectedType);
//How to initialize t's field with an appropriate value?
}
}
The thing is RecipientTypesFactory and its creators know nothing about CreateMailingController's dynamicGroupId and staticGroupId values. Those values are setting up by some user from web-interface. Therefore the factory cannot initialize the corresponding field of a type to create with these values.
RecipientTypesFactory and its creators are spring beans.
Question: How can I pass the values of dynamicGroupId and staticGroupId to the Factory in a flexible way and avoid wiriting switch-case like code? Is that possible?
Maybe there's another patter for that purposes. In fact the factory is creating the prototype of an object.
You can use map to avoid switch cases,like below:
private static final Map<String, RecipientType> factoryMap = Collections
.unmodifiableMap(new HashMap<String, RecipientType>() {
{
put("dynamicGroupId", new RecipientType() {
public RecipientType accept() {
return new DynamicGroupType();
}
});
put("staticGroupId", new RecipientType() {
public RecipientType accept() {
return new StaticGroupType();
}
});
}
});
public RecipientType createRecipientType(String type) {
RecipientType factory = factoryMap.get(type);
if (factory == null) {
}
return factory.accept();
}
Related
How to choose CDI java bean base on annotation, then the annotation poses table of arguments?
The problem is easier to show using an example than to describe.
Assume that for each object of type Problem we have to choose proper solution.
public class Problem {
private Object data;
private ProblemType type;
public Object getData() { return data; }
public void setData(Object data) { this.data = data; }
public ProblemType getType() { return type; }
public void setType(ProblemType type) { this.type = type;}
}
There are few types of problems:
public enum ProblemType {
A, B, C;
}
There are few solutions:
public interface Solution {
public void resolve(Problem problem);
}
like FirstSolution:
#RequestScoped
#SolutionQualifier(problemTypes = { ProblemType.A, ProblemType.C })
public class FirstSolution implements Solution {
#Override
public void resolve(Problem problem) {
// ...
}
}
and SecondSolution:
#RequestScoped
#SolutionQualifier(problemTypes = { ProblemType.B })
public class SecondSolution implements Solution {
#Override
public void resolve(Problem problem) {
// ...
}
}
The solution should be chosen based on annotation #SolutionQualifier:
#Qualifier
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.TYPE)
public #interface SolutionQualifier {
ProblemType[] problemTypes();
public static class SolutionQualifierLiteral extends AnnotationLiteral<SolutionQualifier> implements SolutionQualifier {
private ProblemType[] problemTypes;
public SolutionQualifierLiteral(ProblemType[] problems) {
this.problemTypes = problems;
}
#Override
public ProblemType[] problemTypes() {
return problemTypes;
}
}
}
By SolutionProvider:
#RequestScoped
public class DefaultSolutionProvider implements SolutionProvider {
#Inject
#Any
private Instance<Solution> solutions;
#Override
public Instance<Solution> getSolution(Problem problem) {
/**
* Here is the problem of choosing proper solution.
* I do not know how method {#link javax.enterprise.inject.Instance#select(Annotation...)}
* works, and how it compares annotations, so I do no know what argument I should put there
* to obtain proper solution.
*/
ProblemType[] problemTypes = { problem.getType() };
return solutions.select(new SolutionQualifier.SolutionQualifierLiteral(problemTypes));
}
}
And in the last one there is a problem:
I do not know how method javax.enterprise.inject.Instance#select(Annotation...) works internally, and how it compares annotations, so I do no know what argument I should put there to obtain proper solution. If there appear a problem of type A table ProblemType[] will consist of one argument, while FirstSolution.class is annotated with #SolutionQualifier having two arguments, so therefore I will not get the proper Instance.
I didn't find a way to resolve it using CDI API, instead:
I created another enum:
public enum SoultionType {
A(ProblemType.A, ProblemType.C),
B(ProblemType.A);
//...
SoultionType(ProblemType problems...) {
// ...
}
public static SoultionType getByProblemType(ProblemType problem) {
// ...
}
}
Changed so SolutionQualifier has only SoultionType field inside, so there is no problem with the comparison.
Given the following abstract class:
public abstract class BaseVersionResponse<T extends BaseVO> {
public abstract void populate(T versionVO);
}
and the following child class:
public class VersionResponseV1 extends BaseVersionResponse<VersionVOV1>
{
protected String testFieldOne;
protected String testFieldTwo;
public String getTestFieldOne() {
return testFieldOne;
}
public void setTestFieldOne(String value) {
this.testFieldOne = value;
}
public String getTestFieldTwo() {
return testFieldTwo;
}
public void setTestFieldTwo(String value) {
this.testFieldTwo = value;
}
#Override
public void populate(VersionVOV1 versionVO) {
this.setTestFieldOne(versionVO.getFieldOne());
this.setTestFieldTwo(versionVO.getFieldTwo());
}
I desire to do something like this from a calling method:
public void getVersionInfo(String version) {
BaseVO versionVO = null;
BaseVersionResponse<? extends BaseVO> baseVersionResponse = null;
baseVersionResponse = createVersionResponse(version);
versionVO = createVersionVO(version);
baseVersionResponse.populate(versionVO);
}
where createVersionResponse(...) and createVersionVO(...) look like this:
public BaseVersionResponse<? extends BaseVO> createVersionResponse(String version) {
BaseVersionResponse<? extends BaseVO> specificVersionResponse = null;
if (version.equalsIgnoreCase("V1")) {
specificVersionResponse = new VersionResponseV1();
} else if (version.equalsIgnoreCase("V2"))
specificVersionResponse = new VersionResponseV2();
return specificVersionResponse;
}
public BaseVO createVersionVO(String version) {
BaseVO versionVO = null;
if (version.equalsIgnoreCase("V1")) {
versionVO = new VersionVOV1();
} else if (version.equalsIgnoreCase("V2"))
versionVO = new VersionVOV2();
return versionVO;
}
and VersionVOV1 looks like this:
public class VersionVOV1 extends BaseVO {
private String fieldOne = null;
private String fieldTwo = null;
private String fieldThree = null;
public String getFieldOne() {
return fieldOne;
}
public void setFieldOne(String fieldOne) {
this.fieldOne = fieldOne;
}
public String getFieldTwo() {
return fieldTwo;
}
public void setFieldTwo(String fieldTwo) {
this.fieldTwo = fieldTwo;
}
public String getFieldThree() {
return fieldThree;
}
public void setFieldThree(String fieldThree) {
this.fieldThree = fieldThree;
}
}
My problem arises when I try to compile this line of code:
baseVersionResponse.populate(versionVO);
in getVersionInfo(...). I'm getting a message that looks like this:
The method populate(capture#3-of ?) in the type BaseVersionResponse is not applicable for the arguments (BaseVO)
on the populate method above.
My thought was (which is apparently incorrect) that since the baseVersionResponse is, at this point in the code, actually a specific child instance, that the class would know exactly which populate method to call from that specific child class.
What am I doing wrong here? Is there a better way to do this if this isn't the correct approach?
Thank you for your time!
Ok, I took a better look at this today. The problem is that the wildcard, while the right way to go, precludes you from doing:
BaseVO versionVO = createVersionVO(version);
Because the populate call wants an extension of BaseVO, not an actual BaseVO, which doesn't qualify. That means you can't pass that versionVO variable directly.
So, to keep the type checking in place, which I think is good because you'll always want an implementation, leave pretty much everything as-is above, and change your BaseVersionResponse class to something like:
public abstract class BaseVersionResponse<T extends BaseVO> {
public T getVersion(BaseVO versionVO) {
try {
return (T) versionVO;
} catch (ClassCastException e) {
throw new IllegalArgumentException();
}
}
public abstract void populate(BaseVO versionVO);
}
So, populate method now takes a BaseVO, and there's a new getVersion method to do some explicit casting for us. This should be ok since we know that the factory will always supply the right thing, but if another caller doesn't, an IllegalArgumentException is thrown.
Now, in your response class implementation, change the populate method accordingly:
public void populate(BaseVO version) {
VersionVOV1 versionVO = getVersion(version);
this.setTestFieldOne(versionVO.getFieldOne());
this.setTestFieldTwo(versionVO.getFieldTwo());
}
So, we've changed the populate method to take BaseVO, and the getVersion method does the casting for us. All the other type checks still apply, and we're good to go.
The casting makes it feel not as clean, but for the factory approach you're using, it's really the only way (I can think of) to keep the guarantees made by the type declarations and the code pattern in tact.
Hope that helps!
If you just take out the capture of type (the "<?>"), and leave it unchecked, it should work just fine. Even using type Object would have compiled.
But, given your specific example, what you probably want is the method:
public BaseVersionResponse<?> createVersionResponse(String version)
Changed to:
public BaseVersionResponse<? extends BaseVO> createVersionResponse(String version)
Then, instead of using
BaseVersionResponse<?>
use
BaseVersionResponse<? extends BaseVO>
Since you know that the return type will be one of those things that implements the interface/class.
I am getting a compilation error. I want my static method here to return a factory that creates and return Event<T> object. How can I fix this?
import com.lmax.disruptor.EventFactory;
public final class Event<T> {
private T event;
public T getEvent() {
return event;
}
public void setEvent(final T event) {
this.event = event;
}
public final static EventFactory<Event<T>> EVENT_FACTORY = new EventFactory<Event<T>>() {
public Event<T> newInstance() {
return new Event<T>();
}
};
}
Generic parameters of a class do not apply to static members.
The obvious solution is to use a method rather than a variable.
public static <U> EventFactory<Event<U>> factory() {
return new EventFactory<Event<U>>() {
public Event<U> newInstance() {
return new Event<U>();
}
};
}
The syntax is more concise in the current version of Java.
It is possible to use a the same instance of EventFactory stored in a static field, but that requires an unsafe cast.
You have:
public final class Event<T> {
...
public final static EventFactory<Event<T>> EVENT_FACTORY = ...
}
You cannot do this. T is a type that is associated with a specific instance of an Event<T>, and you cannot use it in a static context.
It's hard to give you good alternate options without knowing more about what exactly you are trying to do, as this is sort of an odd-looking factory implementation. I suppose you could do something like (put it in a method instead):
public final class Event<T> {
...
public static <U> EventFactory<Event<U>> createEventFactory () {
return new EventFactory<Event<U>>() {
public Event<U> newInstance() {
return new Event<U>();
}
};
};
}
And invoke it like:
EventFactory<Event<Integer>> factory = Event.<Integer>createEventFactory();
Or, if you don't want to be explicit (you don't really need to be, here):
EventFactory<Event<Integer>> factory = Event.createEventFactory();
Why don't you get rid of the whole static member of Event thing and either keep the factories separate, e.g.:
public final class GenericEventFactory<T> extends EventFactory<Event<T>> {
#Override public Event<T> newInstance() {
return new Event<T>();
}
}
And use, e.g., new GenericEventFactory<Integer>() where appropriate?
I have an Enum SupplierCode:
public enum SupplierCode
{
BG("British Gas"), CNG("Contract Natural Gas"), COR("Corona Energy");
private String value;
SupplierCode(String value)
{
if(value != "")
{
this.value = value;
}
}
// ... toString() and fromString() omitted for brevity
// for editor framework (?)
public String getValue()
{
return value;
}
public void setValue(String value)
{
this.value = value;
}
}
I display it in my editors using a ValueListBox:
#UiField(provided = true)
ValueListBox<SupplierCode> supplierCode = new ValueListBox<SupplierCode>(new AbstractRenderer<SupplierCode>()
{
#Override
public String render(SupplierCode object)
{
return object == null ? "" : object.toString();
}
});
// in the constructor
public ContractEditor()
{
initWidget(uiBinder.createAndBindUi(this));
supplierCode.setAcceptableValues(Arrays.asList(SupplierCode.values()));
}
I have to edit this type a few times in my app so I wanted to make an editor for just this dropdown, called SupplierCodeEditor:
public class SupplierCodeEditor extends Composite implements Editor<SupplierCode>
{
private static SupplierCodeEditorUiBinder uiBinder = GWT.create(SupplierCodeEditorUiBinder.class);
interface SupplierCodeEditorUiBinder extends UiBinder<Widget, SupplierCodeEditor>
{
}
#UiField(provided = true)
ValueListBox<SupplierCode> value = new ValueListBox<SupplierCode>(new AbstractRenderer<SupplierCode>()
{
#Override
public String render(SupplierCode object)
{
return object == null ? "" : object.toString();
}
});
public SupplierCodeEditor()
{
initWidget(uiBinder.createAndBindUi(this));
value.setAcceptableValues(Arrays.asList(SupplierCode.values()));
}
}
However, when I use it, although it renders the list ok with the options, it doesn't select the actual value from the list. I thought having the getValue() and setValue() methods would work but seemingly not.
Does anyone know of a way to put this in one editor file? Then I won't have to repeat the code for the renderer and call setAcceptableValues() every place I want to use it.
Use LeafValueEditor<SupplierCode>:
public class SupplierEditor extends Composite implements LeafValueEditor<SupplierCode> {
interface SupplierEditorUiBinder extends UiBinder<Widget, SupplierEditor> {
}
private static SupplierEditorUiBinder uiBinder = GWT.create(SupplierEditorUiBinder.class);
#UiField(provided = true)
ValueListBox<SupplierCode> codes;
public SupplierEditor() {
codes = new ValueListBox<>(new AbstractRenderer<SupplierCode>() {
#Override
public String render(SupplierCode object) {
return object == null ? "" : object.toString();
}
});
initWidget(uiBinder.createAndBindUi(this));
codes.setAcceptableValues(Arrays.asList(SupplierCode.values()));
}
#Override
public SupplierCode getValue() {
return codes.getValue();
}
#Override
public void setValue(SupplierCode value) {
codes.setValue(value);
}
}
This way, your widget will be easily pluggable in a Editor hierarchy.
And you don't need the get/set methods in your SupplierCode enum.
You have to either:
use #Editor.Path("") on your child ValueListBox
make your SupplierCodeEditor implement LeafValueEditor<SupplierCode>, with delegating getValue and setValue to the ValueListBox
make your SupplierCodeEditor implement IsEditor<LeafValueEditor<SupplierCode>, returning the ValueListBox's asEditor() from your own asEditor().
BTW, you absolutely don't need the getValue and setValue on your enum values.
I am having an abstract factory class StudentValidatorFactory which is suppossed to create(based on a specified parameter) various StudentValidator class instances to which a validation map has to be injected (see the code bellow).
public class StudentValidatorFactory{
public static final int JUNIOR_STUDENT_TYPE = 1;
public static final int SENIOR_STUDENT_TYPE = 2;
public StudentValidator createStudentValidator(int studentType) throws StudentValidatorCreationException{
Map<String,ValidationBean> validationMap = readValiationMapFromPersistentOrCachedStorage(studentType);
switch (studentType){
case JUNIOR_STUDENT:
return new JuniorStudentValidator(validationMap);
case SENIOR_STUDENT:
return new SeniorStudentValidator(validationMap);
}
}
}
public interface StudentValidator{
void validate(Student student) throws StudentValidationException;
}
public class JuniorStudentValidator{
private Map<String, ValidationBean> validationMap;
public JuniorStudentValidator(Map<String,ValidationBean> validationMap){
this.validationMap = validationMap;
}
public void validate(Student student) throws StudentValidationException{
// make use of validation map for apply junior student related validations on the student
}
}
public class SeniorStudentValidator{
private Map<String, ValidationBean> validationMap;
public SeniorStudentValidator(Map<String,ValidationBean> validationMap){
this.validationMap = validationMap;
}
public void validate(Student student) throws StudentValidationException{
// make use of validation map for apply senior student related validations on the student
}
}
My question is about the StudentValidatorFactory.createStudentValidator(int studentType) method whether reading the validation map from a persistent storage (based on the student type) should be done within the create method ? Otherwise said, should the factory be aware/dependent about such implementation details?
I'd appreciate if there would be a solution to avoid the switch(studentType) statement when creating the student validator - an idea on top of my head is to have an internally managed map and perform the StudentValidator concrete class instantiation via reflection .
Advantages of using such a technique is that the validators are much easier to be tested (through dependency injection).
Extract the readValiationMapFromPersistentOrCachedStorage(studentType) in a separated service interface StudentValidatorService and inject an instance of the service in the StudentValidatorFactory using a property or constructor argument:
public interface StudentValidatorService {
Map<String,ValidationBean> getValidationMap(int studentType);
}
public class StudentValidatorFactory{
public static final int JUNIOR_STUDENT_TYPE = 1;
public static final int SENIOR_STUDENT_TYPE = 2;
public StudentValidatorFactory(StudentValidatorService studentValidatorService) {
this.studentValidatorService = studentValidatorService;
}
public StudentValidator createStudentValidator(int studentType) throws StudentValidatorCreationException{
Map<String,ValidationBean> validationMap = studentValidatorService.getValidationMap(studentType);
switch (studentType){
case JUNIOR_STUDENT:
return new JuniorStudentValidator(validationMap);
case SENIOR_STUDENT:
return new SeniorStudentValidator(validationMap);
}
}
}
Now you can write an implementation of StudentValidatorService backed by database. Or you can write a mock implementation for testing. The implementation is now decoupled from the usage.
To remove the switch-case, invert it using an enum:
public enum StudentType {
JUNIOR_STUDENT {
public StudentValidator getValidator(Map<String,ValidationBean> validationMap) {
return new JuniorStudentValidator(validationMap);
}
},
SENIOR_STUDENT {
public StudentValidator getValidator(Map<String,ValidationBean> validationMap) {
return new SeniorStudentValidator(validationMap);
}
};
public abstract StudentValidator getValidator(Map<String,ValidationBean> validationMap);
}
public class StudentValidatorFactory{
public StudentValidatorFactory(StudentValidatorService studentValidatorService) {
this.studentValidatorService = studentValidatorService;
}
public StudentValidator createStudentValidator(StudentType studentType) throws StudentValidatorCreationException{
Map<String,ValidationBean> validationMap = studentValidatorService.getValidationMap(studentType);
return studentType.getValidator(validationMap);
}
}