BACKGROUND:
I am trying to implement a tiny template, i.e. generic class, which would allow me to achieve a pass-by-reference functionality as follows.
public static class Ref<T> {
T value;
public Ref(T InitValue) { this.set(InitValue); }
public void set(T Value) { this.value = Value; }
public T get() { return this.value; }
}
So, I could define a function that takes a 'Ref' where the value can actually be changed, e.g.
public static void function(Ref<Byte> x)
{
x.set((byte)0x7E);
}
The initialization of the variable to be passed by reference looks not so elegant.
Ref<Byte> to_be_changed = new Ref<Byte>((byte)0);
...
function(to_be_changed);
...
Byte result = to_be_changed.get()
QUESTION:
Is there a way in Java to do it better? Can the constructor initialize directly a '0' according to the primitive type related to the wrapper type which is passed as template type? I.e something like
...
public Ref() { this.value = (T.relatedPrimitiveClass())0; }
...
where Integer.relatedPrimitiveClass() shall deliver int; Byte.relatedPrimitiveClass() delivers byte.
First and the most important thing to understand is that java generics are not templates. Generics are classes/interfaces that are parameterized over types. I recommend reading generics tutorial from oracle: https://docs.oracle.com/javase/tutorial/java/generics/types.html
It is possible to use reflection to get the parametrized type T of your Ref class and use that to determinate the initial value for default construtor, but I would not recommend doing so.
Instead of reflection you can create subclasses for types, that require default constructors (e.g. object versions of primitives):
public static class ByteRef extends Ref<Byte> {
public ByteRef() {
super((byte)0);
}
public ByteRef(byte value) {
super(value);
}
// I'm not sure, if I like this one :-)
public void set(int value) {
super.set((byte)value);
}
}
Instead of subclassing, you can also add new methods to Ref class:
public static class Ref<T> {
T value;
public Ref(T initValue) {
this.set(initValue);
}
public void set(T Value) {
this.value = Value;
}
public T get() {
return this.value;
}
public static Ref<Byte> createByteRef() {
return new Ref<Byte>((byte)0);
}
public static Ref<Byte> createByteRef(byte value) {
return new Ref<Byte>(value);
}
}
Or you could create separate factory classes:
public class Refs {
public static Ref createByteRef() {
return new Ref((byte)0);
}
public static Ref<Byte> createByteRef(byte value) {
return new Ref<Byte>(value);
}
}
The last option is to use reflection to get the parameterized type. I personally would not use this solution, because number of primitive classes is finite and you have option to create much neater interfaces with subclassing
public abstract static class PrimitiveNumberRef<T extends Number> extends
Ref<T> {
private Class<T> type;
public PrimitiveNumberRef() {
// This requires default constructor for Ref class
type = getGenericType(getClass());
super.set((T) getInitialValue(type));
}
#Override
public void set(T value) {
if (value == null) {
throw new IllegalArgumentException(
"Null value is not allowed for PrimitiveNumerRef type: "
+ type);
}
if (!type.isInstance(value)) {
throw new IllegalArgumentException("Unsupported value type: "
+ value.getClass());
}
super.set(value);
}
#SuppressWarnings("unchecked")
private static <T> Class<T> getGenericType(Class<?> clz) {
return (Class<T>) ((ParameterizedType) clz.getGenericSuperclass())
.getActualTypeArguments()[0];
}
private static <T> T getInitialValue(Class<T> clz) {
if (clz == Byte.class) {
return clz.cast((byte) 0);
} else if (clz == Short.class) {
return clz.cast((short) 0);
} else if (clz == Integer.class) {
return clz.cast((int) 0);
} else if (clz == Double.class) {
return clz.cast((double) 0);
} else if (clz == Float.class) {
return clz.cast((float) 0);
} else if (clz == Long.class) {
return clz.cast((long) 0);
} else {
throw new IllegalArgumentException("Unsupported type: "
+ clz.getName());
}
}
}
PrimitiveNumberRef is instantiated as follows:
Ref<Long> val1 = new PrimitiveNumberRef<Long>() { };
Related
I am looking for some help in designing the factory of concrete implementations of a generic interface. Java version 7, can not use 8+
Given such interface and abstract class:
public interface ValidationStrategy<T> {
String getNativeQuery();
ValidationStrategy<T> withValue(T value);
}
public abstract class AbstractValidationStrategy<T> implements ValidationStrategy<T> {
protected T value;
public void setValue(T value) {
this.value = value;
}
}
I want to have multiple implementations of such interface like:
public class DocumentValidationStrategy extends AbstractValidationStrategy<String> {
#Override
public String getNativeQuery() {
// here goes customer native query
return null;
}
#Override
public ValidationStrategy<String> withValue(String value) {
setValue(value);
return this;
}
}
The ValidationStrategy would be decided upon predefined enum (interface, has to be cross-platform unified) by the, ideally, a factory. The problems are generics and I can not really go around them with nor I haven't crossed any question that would address my problem
public class ValidationStrategyFactory {
private static final Map<CustomerValueValidationEnum, Class<? extends ValidationStrategy<?>>> validationStrategiesMap = new HashMap<>();
{
validationStrategiesMap.put(CustomerValueValidationEnum.VALIDATE_DOCUMENT, DocumentValidationStrategy.class);
}
private static Class<? extends ValidationStrategy<?>> getInstance(CustomerValueValidationEnum validationEnum) {
return validationStrategiesMap.get(validationEnum);
}
public static ValidationStrategy<?> createInstance(CustomerValueValidationEnum validationEnum)
throws IllegalAccessException, InstantiationException {
return getInstance(validationEnum).newInstance();
}
}
This obviously leads to problems where I can not create the proper implemntation of the ValidationStrategy interface due to my bad usage of java generics where I try to:
public boolean isValueUnique(CustomerValueValidationEnum type, Object value) {
try {
ValidationStrategyFactory.createInstance(type).withValue(value);
} catch (IllegalAccessException | InstantiationException e) {
throw new UnsupportedOperationException();
}
return false;
}
which obviously does not work as I can not feed value the way I want (value can be everything, a String, Integer or a List). I know that I am trying to combine factory and strategy patterns and I tried my best to combine both of them, I guess it is a bad pattern but now I do not really know how else can I create easily extensible validation mechanism that would only require me to create a single class.
EDIT: as requested, simple enum class that is shared between multiple services and it should not contain any business logic.
public enum CustomerValueValidationEnum {
VALIDATE_DOCUMENT("validateDocumentNumber")
;
private final String name;
private CustomerValueValidationEnum(String name) {
this.name = name;
}
#ValueMapKey
public String getName() {
return this.name;
}
}
It is impossible to type dynamically any generic type as it's checked during compilation. I suggest you to make your factory switch on your enum (using/or not a Map).
Implementation without Map :
enum CustomerValueValidationEnum { // Not provided by OP
VALIDATE_DOCUMENT,
VALIDATE_NUMBER
}
interface ValidationStrategy<T> {
String getNativeQuery();
ValidationStrategy<T> withValue(T value);
}
abstract class AbstractValidationStrategy<T> implements ValidationStrategy<T> {
protected T value;
public void setValue(T value) {
this.value = value;
}
#Override
public String getNativeQuery() {
return null;
}
#Override
public ValidationStrategy<T> withValue(T value) {
setValue(value);
return this;
}
}
class DocumentValidationStrategy<T> extends AbstractValidationStrategy<T> {
#Override
public String getNativeQuery() {
return "Customer Query";
}
}
class ValidationStrategyFactory {
// Generic types are checked during compilation time, can't type it dynamically
public static ValidationStrategy<?> createInstance(CustomerValueValidationEnum validationEnum) {
ValidationStrategy valStrat = null;
switch(validationEnum) {
case VALIDATE_DOCUMENT:
valStrat = new DocumentValidationStrategy<String>();
case VALIDATE_NUMBER:
valStrat = new DocumentValidationStrategy<Integer>();
}
return valStrat;
}
}
Implementation with Map :
import java.util.HashMap;
import java.util.Map;
enum CustomerValueValidationEnum { // Not provided by OP
VALIDATE_DOCUMENT(String.class),
VALIDATE_NUMBER(Integer.class);
private Class validationType;
CustomerValueValidationEnum(Class cls) {
validationType = cls;
}
public Class getValidationType() {
return validationType;
}
}
interface ValidationStrategy<T> {
String getNativeQuery();
ValidationStrategy<T> withValue(T value);
}
abstract class AbstractValidationStrategy<T> implements ValidationStrategy<T> {
protected T value;
public void setValue(T value) {
this.value = value;
}
#Override
public String getNativeQuery() {
return null;
}
#Override
public ValidationStrategy<T> withValue(T value) {
setValue(value);
return this;
}
}
class DocumentValidationStrategy<T> extends AbstractValidationStrategy<T> {
#Override
public String getNativeQuery() {
return "Customer Query";
}
}
class ValidationStrategyFactory {
private static final Map<Class, ValidationStrategy> validationStrategiesMap = new HashMap<>();
{
validationStrategiesMap.put(String.class, new DocumentValidationStrategy<String>());
validationStrategiesMap.put(Integer.class, new DocumentValidationStrategy<Integer>());
}
private static ValidationStrategy<?> getInstance(CustomerValueValidationEnum validationEnum) {
return validationStrategiesMap.get(validationEnum.getValidationType());
}
}
You can't use generic type through enum (without implementing an interface) : Post
You can't type dynamically any generic type : Post
One workaround is using a way to get each generic type strategy with a separate method getting from a separate map.
The lower number of various strategy generic types, the more appropriate this way is.
public class StrategyFactory {
static final Map<CustomerValueValidationEnum, ValidationStrategy<String>> validationStringStrategiesMap = new HashMap<>() {{
validationStringStrategiesMap.put(CustomerValueValidationEnum.VALIDATE_DOCUMENT_STRING, new DocumentStringValidationStrategy());
}};
static final Map<CustomerValueValidationEnum, ValidationStrategy<Integer>> validationIntegerStrategiesMap = new HashMap<>() {{
validationIntegerStrategiesMap.put(CustomerValueValidationEnum.VALIDATE_DOCUMENT_INTEGER, new DocumentIntegerValidationStrategy());
}};
public static ValidationStrategy<String> stringStrategy(CustomerValueValidationEnum e) {
return validationStringStrategiesMap.get(e);
}
public static ValidationStrategy<Integer> integerStrategy(CustomerValueValidationEnum e) {
return validationIntegerStrategiesMap.get(e);
}
}
public class DocumentStringValidationStrategy extends AbstractValidationStrategy<String> { ... }
public class DocumentIntegerValidationStrategy extends AbstractValidationStrategy<Integer> { ... }
Advantages:
The generic type will be always inferred: StrategyFactory.integerStrategy(null).withValue(1); which means the user-call is very comfortable.
Scales with a low number of generic types: 2 generic type of strategies -> 2 maps -> 2 methods.
Disadvantage:
The user must know if the String-type or Integer-type is to be requested.
Doesn't scale with a high number of generic types: if each strategy has a custom type, then this solution will not help you at all.
Characteristics:
Not null-safe, the map can return null (I'd use null-object pattern for safe behavior). This would be issue even in any of your solutions
Could someone please help.
I would like to create a Factory, which would return specific class.
Having problem on the line - filterFactory.getFilter(myColumn.getType()).setMin(5);
There is an error: Cannot resolve method 'setMin' in 'Object'
public enum Columns {
Name(ColumnType.String),
Age(ColumnType.Numeric);
private final ColumnType type;
Columns(ColumnType type) {
this.type = type;
}
public ColumnType getType() {
return type;
}
}
public enum ColumnType {
String,
Numeric
}
public class NumericFilter extends ColumnFilter {
public void setMin(int min) {
System.out.println("min is set" + min);
}
}
public class StringFilter extends ColumnFilter {
public void setFilter(String filter) {
System.out.println("filter is set to:" + filter);
}
}
public class ColumnFilterFactory {
public <T> T getFilter(ColumnType type) {
if (type == null) {
return null;
}
if (type == ColumnType.String) {
return (T) new StringFilter();
} else if (type == ColumnType.Numeric) {
return (T) new NumericFilter();
}
return null;
}
}
public class BasicTest {
public static void main(String[] args) {
Columns myColumn = Columns.Age;
ColumnFilterFactory filterFactory = new ColumnFilterFactory();
filterFactory.getFilter(myColumn.getType()).setMin(5);
}
}
There's no way the compiler can know what type the factory is going to return, so you need to give it a little help. For example by using an intermediate variable:
NumericFilter nf = filterFactory.getFilter(myColumn.getType());
nf.setMin(5);
I'm working on building some classes which will represent data to be converted to JSON.
The values of these fields could be of various types (might be an int, might be a boolean).
This is an example of what I have so far (minimum reproducible example):
import javax.json.Json;
import javax.json.JsonObjectBuilder;
abstract class AttributeValue {}
class AttributeValueInt extends AttributeValue {
private int value;
AttributeValueInt( int value ) {this.value = value;}
int getValue() { return value; }
}
class AttributeValueBool extends AttributeValue {
private boolean value;
AttributeValueBool( boolean value ) {this.value = value;}
boolean getValue() { return value; }
}
class Attribute {
private AttributeValue attrValue;
Attribute( AttributeValue attrValue ) { this.attrValue = attrValue; }
AttributeValue getAttrValue() { return attrValue; }
}
class Example {
void getJSON( Attribute attribute ) {
JsonObjectBuilder builder = Json.createObjectBuilder();
builder.add( "key", attribute.getAttrValue().getValue() );
// Cannot resolve method 'getValue()'
}
}
i.e. AttributeValueInt and AttributeValueBool extend the abstract class AttributeValue. value (towards the bottom) may be either an AttributeValueInt or an AttributeValueBool.
Since both these classes implement a getValue method, I was hoping that attribute.getAttrValue().getValue() would resolve to either an int or a boolean accordingly.
The full error is this:
Error:(39, 61) java: cannot find symbol
symbol: method getValue()
location: class com.fanduel.brazepublishing.AttributeValue
How can I get this working? I thought about adding an abstract getValue method to the abstract class, but what would its return type be?
You can use a generic for that. Here an example:
abstract class AttributeValue<AttributeType> {
AttributeType value;
AttributeType getValue() {
return value;
}
}
class AttributeValueInt extends AttributeValue<Integer> {
AttributeValueInt(int value) {
this.value = value;
}
}
class AttributeValueBool extends AttributeValue<Boolean> {
AttributeValueBool(boolean value) {
this.value = value;
}
}
class Main {
static String getJson(AttributeValue<?> attribute) {
return "key: " + attribute.getValue();
}
public static void main(String[] args) {
AttributeValue<?> attributeInt = new AttributeValueInt(42);
AttributeValue<?> attributeBool = new AttributeValueBool(true);
System.out.println(getJson(attributeInt));
System.out.println(getJson(attributeBool));
}
}
Here you can call getValue on an AttributeValue instance as the type of the attribute is specified by <AttributeType>. One drawback is that you can't use primitive types anymore.
There are many ways to solve this. But since you have mentioned the AttributeValue can be of any type, you can simply use Map<K, V>
// String - key
// Object - Any value type
Map<String, Object> jsonFields = new HashMap<>();
// populate the Map
JsonObjectBuilder builder = Json.createObjectBuilder();
for(Map.Entry<String, Object> currentEntry : jsonFields.entrySet()) {
builder.add(currentEntry.getKey(), currentEntry.getValue());
}
With this way, you would have separate keys for each mapped values. Or if you still wanna stick with AttributeValue implementations, you can acheive like below. Since, Object is the parent class for all the Java classes, this will work.
abstract class AttributeValue {
public abstract Object getValue();
}
class AttributeValueInt extends AttributeValue {
private int value;
public AttributeValueInt(int value) {this.value = value;}
#Override
public Object getValue() { return value; }
}
class AttributeValueBool extends AttributeValue {
private boolean value;
public AttributeValueBool(boolean value) {this.value = value;}
#Override
public Object getValue() { return value; }
}
public class Main {
static void getJSON( Attribute attribute ) {
JsonObjectBuilder builder = Json.createObjectBuilder();
builder.add( "key", attribute.getAttrValue().getValue() );
// rest of your code
}
public static void main(String[] args) {
// your code
}
}
I would like to create a class that will take in different types. It should handle some basic operations like .equals() for all given types, but I'd like to create specific implementations for Strings and Booleans for example.
I'd like to use the same constructor but control what happens based on the type.
public class TestObject<T>{
private T value;
public TestObject{
}
public setValue(T value){
this.value=value;
}
public return Type??? getSpecificType(){
if (value instanceof Boolean){
return new TestObjectBoolean(this);
}
if (value instanceof String){
return new TestObjectString(this);
}
}
}
The desired usage below:
TestObject<String> test = new TestObject<String>();
test.setValue("Test");
boolean result = test.getSpecificType().stringSpecificMethod()
TestObject<Integer> test2 = new TestObject<Boolean>();
test.setValue(true);
boolean result2= test2.getSpecificType().booleanSpecificMethod();
I would like the below example to fail to compile:
TestObject<String> test3 = new TestObject<String>();
test.setValue("Test");
boolean result3= test3.getSpecificType().booleanSpecificMethod();
//should not compile because test2 should return a boolean specific class
//with the boolean specific methods
It may seem silly but I would like to avoid calling differently named constructors for different types like this:
TestObjectString test4 = new TestObjectString();
test.setValue("Test");
boolean result4= test4.stringSpecificMethod();
I am lost on how to implement this. Any advice or help on searching additional information on this would be appreciated.
Thank you.
I’m not sure I understand what you’re asking for, but I think you want to make the constructor private, and add public factory methods:
public class TestObject<T> {
private T value;
private final Supplier<? extends TestObject<T>> typeSpecificConstructor;
private TestObject(T initialValue,
Supplier<? extends TestObject<T>> constructor) {
this.value = initialValue;
this.typeSpecificConstructor = constructor;
}
protected TestObject(Supplier<? extends TestObject<T>> constructor) {
this.typeSpecificConstructor = constructor;
}
public boolean test(T valueToTest) {
throw new UnsupportedOperationException(
"Must be implemented by subclasses");
}
public static TestObject<Boolean> newInstance(boolean initialValue) {
return new TestObject<>(initialValue, TestObjectBoolean::new);
}
public static TestObject<String> newInstance(String initialValue) {
return new TestObject<>(initialValue, TestObjectString::new);
}
public TestObject<T> getSpecificType() {
return typeSpecificConstructor.get();
}
public T getValue() {
return value;
}
public void setValue(T newValue) {
this.value = newValue;
}
}
But methods particular to a subtype still won’t be accessible. There is simply no way for a variable whose type is a general superclass to make subclass methods available without casting.
I’m not sure what your intended purpose of getSpecificType() is, but you could probably do away with that method and make things simpler:
public abstract class TestObject<T> {
private T value;
public abstract boolean test(T valueToTest);
public static TestObject<Boolean> newInstance(boolean initialValue) {
TestObject<Boolean> instance = new TestObjectBoolean();
instance.setValue(initialValue);
return instance;
}
public static TestObject<String> newInstance(String initialValue) {
TestObject<String> instance = new TestObjectString();
instance.setValue(initialValue);
return instance;
}
public T getValue() {
return value;
}
public void setValue(T newValue) {
this.value = newValue;
}
}
I have an third-party RPC-API that provides an interface similar to that of java.sql.ResultSet (for reading values) and java.sql.PreparedStatement (for writing values). Assume it looks something like this:
public interface RemoteDeviceProxy {
public void setBoolean(Boolean value);
public void setInteger(Integer value);
// ...
public Boolean getBoolean();
public Integer getInteger();
// ...
}
I want to write a wrapper for this API that uses generics to create instances of specific types:
public class <T> RemoteVariable {
private final RemoteDeviceProxy wrappedDevice;
public RemoteVariable(RemoteDeviceProxy wrappedDevice) {
this.wrappedDevice = wrappedDevice;
}
public T get() {
// should call wrappedDevice.getBoolean() if T is Boolean, etc.
// how to implement?
}
public void set(T newValue) {
// should call wrappedDevice.setBoolean(newValue) if T is Boolean, etc.
// implement using instanceof
}
}
How can I implement the getter in my generic wrapper? I have found this answer which explains a similar scenario in depth, but I am not able to transfer this to my problem. Specifically, when I write this:
public T get() {
Type[] actualTypeArguments = ((ParameterizedType) getClass())
.getActualTypeArguments();
}
I get a compiler error saying I cannot cast to ParameterizedType, and I do not understand why. Can anyone explain how to achieve this?
Here is one way:
public class <T> RemoteVariable {
private final RemoteDeviceProxy wrappedDevice;
private final Class<T> clazz;
public RemoteVariable(RemoteDeviceProxy wrappedDevice, Class<T> clazz) {
this.wrappedDevice = wrappedDevice;
this.clazz = clazz;
}
public T get() {
if(clazz == Boolean.class){return clazz.cast(wrappedDevice.getBoolean());}
else if(clazz == Integer.class){return clazz.cast(wrappedDevice.getInteger());}
// ...
}
// ...
}
I thought over this quite a while and finally came up with a different approach:
First I added a getter to you RemoteVariable class:
protected RemoteDeviceProxy getWrappedProxy() {
return wrappedProxy;
}
Second I created a builder interface that will be used by a factory later:
public interface RemoteVariableBuilder {
public <T> RemoteVariable<T> buildNewVariable(RemoteDeviceProxy wrappedProxy);
}
Then I created non generic sub classes for Boolean...
public class RemoteBooleanVariable extends RemoteVariable<Boolean> implements RemoteVariableBuilder {
public RemoteBooleanVariable(RemoteDeviceProxy wrappedProxy) {
super(wrappedProxy);
}
#SuppressWarnings("unchecked")
#Override
public <T> RemoteVariable<T> buildNewVariable(RemoteDeviceProxy wrappedProxy) {
return (RemoteVariable<T>) new RemoteBooleanVariable(wrappedProxy);
}
#Override
public Boolean get() {
return getWrappedProxy().getBoolean();
}
#Override
public void set(Boolean value) {
getWrappedProxy().setBoolean(value);
}
}
... and Integer ...
public class RemoteIntegerBuilder extends RemoteVariable<Integer> implements RemoteVariableBuilder {
public RemoteIntegerBuilder(RemoteDeviceProxy wrappedProxy) {
super(wrappedProxy);
}
#SuppressWarnings("unchecked")
#Override
public <T> RemoteVariable<T> buildNewVariable(RemoteDeviceProxy wrappedProxy) {
return (RemoteVariable<T>) new RemoteIntegerBuilder(wrappedProxy);
}
#Override
public Integer get() {
return getWrappedProxy().getInteger();
}
#Override
public void set(Integer value) {
getWrappedProxy().setInteger(value);
}
}
actually eclipse created most of the code once it knew base class and interface.
The final step was to create a factory
public class RemoteVariableFactory {
private static final Map<String, RemoteVariableBuilder> BUILDERS = new HashMap<>();
static {
BUILDERS.put(Boolean.class.getName(), new RemoteBooleanVariable(null));
BUILDERS.put(Integer.class.getName(), new RemoteIntegerBuilder(null));
// add more builders here
}
public static <T> RemoteVariable<T> getRemoteVariable(RemoteDeviceProxy wrappedProxy, Class<T> typeClass) {
RemoteVariableBuilder remoteVariableBuilder = BUILDERS.get(typeClass.getName());
if (remoteVariableBuilder == null) {
return null; // or throw an exception whichever is better in your case
}
return remoteVariableBuilder.buildNewVariable(wrappedProxy);
}
}
Now we are ready to create new RemoteVariables...
RemoteVariable<Boolean> var1 = RemoteVariableFactory.getRemoteVariable(new RemoteDevice(), Boolean.class);
RemoteVariable<Integer> var2 = RemoteVariableFactory.getRemoteVariable(new RemoteDevice(), Integer.class);
To conclude this let's do a quick comparison to the answer of Eng.Fouad:
Disadvantage:
you need to create a new class for every datatype you provide
Advantage:
you only have to add one line to the static block of the factory and not two new if blocks to the getter and setter in RemoteVariable
get and set do not have to work through the if-else-blocks every time