I'd like to write a method, that does return something of a PrimitiveType like float, integer, boolean and also String if possible. I'd like to use generics for it but i stuck and dont find a solution for it. I do need it for a Configparser. Ill use it to get different values from the Config.
Current it des look like this and i know that the switch does not work like this but you get an idea of what id like to do:
public class ConfigurationManager extends XmlReader {
private final static String FILE_PATH = "config/config.cfg";
private static Element xml;
public ConfigurationManager() throws IOException {
FileHandle handle = Gdx.files.internal(FILE_PATH);
this.xml = this.parse(handle);
}
public Resolution getResolution() {
Resolution r = new Resolution();
r.height = xml.getFloat("height");
r.width = xml.getFloat("width");
return r;
}
public static <T> T getConfig(Class<T> type, String name) {
if (type.equals(Integer.class)) {
return type.cast(xml.getInt(name));
} else if (type.equals(Float.class)) {
return type.cast(xml.getFloat(name));
} else if (type.equals(Boolean.class)) {
return type.cast(xml.getBoolean(name));
} else if (type.equals(String.class)) {
return type.cast(xml.get(name));
}
throw new AssertionError("Invalid type");
}
}
Thanks alot
Well, I don't think you can do it with primitive types directly, but how about something like this:
public static <T> T getConfig(Class<T> type, String name) {
if(type.equals(Integer.class)){
return type.cast(xml.getInteger(name));
} else if(type.equals(Float.class)){
return type.cast(xml.getFloat(name));
} else if(type.equals(Double.class)) {
return type.cast(xml.getDouble(name));
} else if(type.equals(String.class)) {
return type.cast(xml.getString(name));
}
throw new AssertionError("Invalid type");
}
You could use an Enum to avoid the branching logic and the explicit casting.
public enum TypeSelector {
INTEGER() {
#Override
public Integer getValue(Elements xml, String name) {
return xml.getInteger(name);
}
},
DOUBLE() {
#Override
public Double getValue(Elements xml, String name) {
return xml.getDouble(name);
}
};
private static final Map<Class<?>, TypeSelector> SELECTORS = new HashMap<Class<?>, TypeSelector>() {
{
put(Integer.class, INTEGER);
put(Double.class, DOUBLE);
}
};
public static <T> TypeSelector getSelectorForType(Class<T> c) {
TypeSelector selector = SELECTORS.get(c);
if (selector == null) {
throw new AssertionError("Invalid type");
}
return selector;
}
public abstract <T> T getValue(Elements xml, String name);
}
Related
My two Type classes called SearchType and ResultcodeType need a parent class in an elegant way. How to design these two classes and a parent class both inherit from in an clean and code saving way?
public enum SearchType {
BARCODE(0),
TEXT(1);
SearchType(int i)
{
this.type = i;
}
private int type;
public static SearchType getType(int value) {
for (SearchType searchType : SearchType.values()) {
if (searchType.type == value)
return searchType;
}
throw new IllegalArgumentException("SearchType not found.");
}
public int getNumericType() {
return type;
}
}
and
public enum ResultcodeType {
RESULTS(0),
NO_RESULTS(1),
PROBLEMS(2),
NO_VALUE(-1);
ResultcodeType(int i)
{
this.type = i;
}
private int type;
public static ResultcodeType getType(int value) {
for (ResultcodeType resultcodeType : ResultcodeType.values()) {
if (resultcodeType.type == value)
return resultcodeType;
}
throw new IllegalArgumentException("ResultcodeType not found.");
}
public int getNumericType() {
return type;
}
}
Where do I use SearchType / ResultCodeType?
Layout Data Binding
<ImageView
app:srcCompat="#{item.searchType == SearchType.BARCODE ? #drawable/ic_barcode : #drawable/ic_one_loupe}"
/>
Room database converter class (where there is redundancy again). But for now room can't handle generic types in it's TypeConverter. So this will stay as is.
#TypeConverter
public static SearchType SearchTypeFromInt(Integer value) {
return SearchType.getType(value);
}
#TypeConverter
public static ResultcodeType ResultcodeTypeFromInt(Integer value) {
return ResultcodeType.getType(value);
}
POJO (with room annotation)
#NonNull
#ColumnInfo(name = "resultcode", defaultValue="-1")
private ResultcodeType mResultcode;
Since enums cannot have base classes, I think this is the closest you're going to get:
public interface Typed {
int getNumericType();
static <E extends Enum<E> & Typed> E getType(E[] values, int type) {
for (E value : values)
if (value.getNumericType() == type)
return value;
throw new IllegalArgumentException(values[0].getClass().getSimpleName() +
" not found: " + type);
}
}
public enum SearchType implements Typed {
BARCODE(0),
TEXT(1);
private final int type;
private SearchType(int type) {
this.type = type;
}
#Override
public int getNumericType() {
return this.type;
}
public static SearchType getType(int type) {
return Typed.getType(values(), type);
}
}
public enum ResultcodeType implements Typed {
RESULTS(0),
NO_RESULTS(1),
PROBLEMS(2),
NO_VALUE(-1);
private final int type;
private ResultcodeType(int type) {
this.type = type;
}
#Override
public int getNumericType() {
return this.type;
}
public static ResultcodeType getType(int type) {
return Typed.getType(values(), type);
}
}
Your enums could implement an interface and add default method.
For example:
interface Typed {
Typed getType(int value)
public enum ResultcodeType implements Typed {
public Typed getType(int value) {
for (ResultcodeType resultcodeType :
ResultcodeType.values()) {
if (resultcodeType.type == value)
return resultcodeType;
}
throw new IllegalArgumentException("ResultcodeType not found.");
}
....
}
I also suggest the following approach using a map instead of searching. In fact, all you need is the mapping. You wouldn't even need to supply a value. Note that you can't reference a static value from within a constructor so you have to build the map externally.
enum SearchType {
BARCODE(0), TEXT(1), UNKNOWN(-1);
static Map<Integer, SearchType> map =
Map.of(0, SearchType.BARCODE, 1, SearchType.TEXT);
SearchType(int i) {
this.type = i;
}
private int type;
public static SearchType getType(int value) {
return SearchType.map.getOrDefault(value, SearchType.UNKNOWN);
}
public int getNumericType() {
return type;
}
}
public static void main(String[] args) {
System.out.println(SearchType.getType(0));
System.out.println(SearchType.getType(1));
System.out.println(SearchType.getType(99));
}
I've got a class that looks something like.
public class ParseValue {
public String value;
public final Class classType;
}
And I'd like to make a function that does a conversion and returns a casted value.
public T parseValue(ParseValue parseInfo) {
if(parseInfo.classType == String.class) {
return parseInfo.value;
} else if (parseInfo.classType == Double.class) {
return Double.valueOf(parseInfo.value);
}
}
Right now I can have this function return an Object and then cast it upon getting the result, but is there a way to make the function do the cast based on the input ParseValue's classType field?
The safest way to do it is to make ParseValue generic:
public class ParseValue<T> {
public String value;
public final Class<T> classType;
public T parseValue() {
Object result;
if (classType == String.class) {
result = value;
} else if (classType == Double.class) {
result = Double.valueOf(value);
} else {
throw new RuntimeException("unknown value type");
}
return classType.cast(result);
}
}
My code contain multiple enum like below. Basically that help to use enum via integer instead of enum value. Is it possible apply some sort of optimization like inheritance or something so that all can have behavior like below.
public enum DeliveryMethods {
STANDARD_DOMESTIC(1), STANDARD_INTERNATIONAL(2), EXPRESS_DOMESTIC(3), EXPRESS_INTERNATIONAL(4);
private final int code;
private DeliveryMethods(int code) {
this.code = code;
}
public int getCode() {
return code;
}
private static final HashMap<Integer, DeliveryMethods> valueMap = new HashMap<>(2);
static {
for (DeliveryMethods type : DeliveryMethods.values()) {
valueMap.put(type.code, type);
}
}
public static DeliveryMethods getValue(int code) {
return valueMap.get(code);
}
}
Here is an example showing how you could delegate to another class:
public interface Keyed<K> {
/**
* returns the key of the enum
*/
K getKey();
}
public class KeyEnumMapping<K, E extends Enum<?> & Keyed<K>> {
private Map<K, E> map = new HashMap<>();
public KeyEnumMapping(Class<E> clazz) {
E[] enumConstants = clazz.getEnumConstants();
for (E e : enumConstants) {
map.put(e.getKey(), e);
}
}
public E get(K key) {
return map.get(key);
}
}
public enum Example implements Keyed<Integer> {
A(1),
B(3),
C(7);
private static final KeyEnumMapping<Integer, Example> MAPPING = new KeyEnumMapping<>(Example.class);
private Integer value;
Example(Integer value) {
this.value = value;
}
#Override
public Integer getKey() {
return value;
}
public static Example getByValue(Integer value) {
return MAPPING.get(value);
}
public static void main(String[] args) {
System.out.println(Example.getByValue(3));
}
}
You could also avoid implementing a Keyed interface and simply pass a Function<E, K> to KeyEnumMapping constructor, that would transform the enum into its key:
public class KeyEnumMapping<K, E extends Enum<?>> {
private Map<K, E> map = new HashMap<>();
public KeyEnumMapping(Class<E> clazz, Function<E, K> keyExtractor) {
E[] enumConstants = clazz.getEnumConstants();
for (E e : enumConstants) {
map.put(keyExtractor.apply(e), e);
}
}
public E get(K key) {
return map.get(key);
}
}
public enum Example {
A(1),
B(3),
C(7);
private static final KeyEnumMapping<Integer, Example> MAPPING =
new KeyEnumMapping<>(Example.class, Example::getValue);
private Integer value;
Example(Integer value) {
this.value = value;
}
public Integer getValue() {
return value;
}
public static Example getByValue(Integer value) {
return MAPPING.get(value);
}
public static void main(String[] args) {
System.out.println(Example.getByValue(3));
}
}
You can consider using the getOrdinal() method of Enum instead of maintaining the 'code' yourself.
http://docs.oracle.com/javase/7/docs/api/java/lang/Enum.html#ordinal()
Even if you maintain the 'code' attribute it is not necessary to maintain the 'valueMap'. Instead you can use the 'values()' method of Enum and iterate over all the enums.
There is no need for Hashmap unless until it is necessary.It's better to go with switch-case for enum values
I've written to get enum from Integer as well as string
public enum DeliveryMethods {
STANDARD_DOMESTIC(1), STANDARD_INTERNATIONAL(2), EXPRESS_DOMESTIC(3), EXPRESS_INTERNATIONAL(4);
private final int code;
private DeliveryMethods(int code) {
this.code = code;
}
public int getCode() {
return code;
}
public static DeliveryMethods fromString(String code) {
if (code.matches("[1-4]")) {
return fromInteger(Integer.valueOf(code));
}
throw new RuntimeException("No values for code " + code);
}
public static DeliveryMethods fromInteger(int code) {
switch (code) {
case 1:
return STANDARD_DOMESTIC;
case 2:
return STANDARD_INTERNATIONAL;
case 3:
return EXPRESS_DOMESTIC;
case 4:
return EXPRESS_INTERNATIONAL;
}
throw new RuntimeException("No values for code " + code);
}
public static DeliveryMethods fromIntegerType2(int code) {
for (DeliveryMethods d : DeliveryMethods.values()) {
if (d.getCode() == code) {
return d;
}
}
throw new RuntimeException("No values for code " + code);
}
}
I'm new to using Java Enums and I've read that replace IF logic that compares String literals should be replaced with an Enum. I don't quite understand how to replace my below code with an Enum, any ideas? Based on the col value being passed into applyEQ, I need to do a base the next method call on it's value. I do know the possible values of col ahead of time and I'm using a constants file for now. Should I create an Enum and place it in my Interface of Constants file?
public class FilterHelper implements IFilterHelper {
private final EQuery eQuery;
public FilterHelper(EQuery query) {
eQuery = query;
}
#Override
public void applyEQ(String col, String val) throws Exception {
int return = 0;
if (col.equalsIgnoreCase(EConstants.NAME)) {
ret = Sample.addName(eQuery, val);
} else if (col.equalsIgnoreCase(EConstants.KEYWORDS)) {
ret = Sample.addKey(eQuery, val);
} else if (col.equalsIgnoreCase(EConstants.ROLE)) {
ret = Sample.addRole(eQuery, val);
}
if (return != 0) {
throw new Exception("failed");
}
}
}
EConstants.java
public final class EConstants {
public static final String NAME = "cewName";
public static final String KEYWORDS = "cewKeywords";
public static final String ROLE = "cewRole";
}
First create an enum:
public enum EConstants {
CEWNAME,
CEWROLE,
CEWKEYWORDS;
}
Then convert col String to this enum and use switch:
public void applyEQ(String col, String val) throws Exception {
int ret = 0;
final EConstants constant = EConstants.valueOf(col.toUpperCase());
switch(constant) {
case CEWNAME:
ret = Sample.addName(eQuery, val);
break;
case CEWROLE:
ret = Sample.addRole(eQuery, val);
break;
case CEWKEYWORDS:
ret = Sample.addKey(eQuery, val);
break;
default:
throw new Exception("Unhandled enum constant: " + constant);
}
}
Note that EConstants.valueOf() can throw IllegalArgumentException if col.toUpperCase() does not match any of constant values.
BTW I hate local variables initialized in multiple places (and break keyword), try extracting method:
final EConstants constant = EConstants.valueOf(col.toUpperCase());
final int ret = processSample(val, constant);
And the method itself:
private int processSample(String val, EConstants constant) throws Exception {
switch(constant) {
case CEWNAME:
return Sample.addName(eQuery, val);
case CEWROLE:
return Sample.addRole(eQuery, val);
case CEWKEYWORDS:
return Sample.addKey(eQuery, val);
default:
throw new Exception("Unhandled enum constant: " + constant);
}
}
You can rewrite your EConstants as enum:
public enum EConstants {
NAME, KEYWORDS, ROLE
}
And evaluate condition using switch statement:
// col has type of EConstants
switch (col) {
case NAME:
// do something
break;
case KEYWORDS:
// do something
break;
case ROLE:
// do something
break;
default:
// what to do otherwise
break;
}
The great thing about Java Enums is that they provide language level support for the type safe enum pattern, because among other things it allows you to define methods and even override them. So you could do this:
public enum CewColumn {
NAME("cewName") {
#Override
public int add(EQuery eQuery, String val) {
return Sample.addName(eQuery, val);
}
},
KEYWORDS("cewKeywords") {
#Override
public int add(EQuery eQuery, String val) {
return Sample.addKey(eQuery, val);
}
},
ROLE("cewRole") {
#Override
public int add(EQuery eQuery, String val) {
return Sample.addRole(eQuery, val);
}
};
private final String colName;
private MyColumn(String colName) {
this.colName = colName;
}
private static final Map<String, CewColumn> COLUMNS = new HashMap<>(values().length);
static{
for (CewColumn cewColumn : values()){
COLUMNS.put(cewColumn.colName, cewColumn);
}
}
public abstract int add(EQuery eQuery, String val);
public static CewColumn getCewColumn(String colName){
return COLUMNS.get(colName);
}
}
Then you can use it like this:
CewColumn cewColumn = CewColumn.getCewColumn(colName);
if (cewColumn != null){
int ret = cewColumn.add(eQuery, val);
}
-> You replaced the switch statement with polymorphism!
it is best to create a Enum.
public Enum AvailableCols{
COL_1,
COL_2;
}
and convert the procedure as
public void applyEQ(AvailableCols col, String val) throws Exception {
switch(col){
case COL1:
...
If you still want the string to be preserved you can see the following post
Basically create an enum and change the type of col and use equals() or == to compare the value of col against the enum values. Alternatively you could use a switch statement but I doubt that would make your code more readable for only 3 constants.
Example:
enum EConstants {
NAME,
KEYWORDS,
ROLE;
}
public void applyEQ(EConstants col, String val) throws Exception {
if( col == EConstants.NAME ) {
...
}
....
}
//or
public void applyEQ(EConstants col, String val) throws Exception {
if( EConstants.NAME.equals(col) ) { //col might be null
...
}
....
}
//or
public void applyEQ(EConstants col, String val) throws Exception {
switch( col ) {
case NAME:
...
break;
case ROLE:
...
}
}
http://docs.oracle.com/javase/tutorial/java/javaOO/enum.html
If your raw data is a string, you will still need to do a string comparison to assign the enum. This might be faster if you do a lot of comparisons on the result data, but if not, it simply adds complication to your code.
You can iterate over the values of the enum like a collection, which gives you an advantage when you need to add constants. That's not bad.
Here is how to do it:
public enum EConstants {
NAME, KEYWORDS, ROLE
}
...
public EConstants setConstant(String from) {
if (from.equalsIgnoreCase("cewName")) {
return NAME;
} else if (col.equalsIgnoreCase("cewKeywords")) {
return KEYWORDS;
} else if (col.equalsIgnoreCase("cewRole")) {
return ROLE;
}
}
You preprocess your data that way and now when you are trying to figure out logic you can use a switch on the enum type value.
Here is a trick for you. No switch/case (just come up with a better name for EConstants).
public enum EConstants {
NAME,
KEYWORDS,
ROLE;
private interface Applier {
void apply(EQuery query, String val);
}
public void apply(EQuery query, String val) {
map.get(this).apply(query, val);
}
private static Map<EConstants, Applier> map = new HashMap<EConstants, EConstants.Applier>();
static {
map.put(NAME, new Applier() {
#Override
public void apply(EQuery query, String val) {
Sample.addName(query, val);
}
});
map.put(KEYWORDS, new Applier() {
#Override
public void apply(EQuery query, String val) {
Sample.addKey(query, val);
}
});
map.put(ROLE, new Applier() {
#Override
public void apply(EQuery query, String val) {
Sample.addRole(query, val);
}
});
}
}
Now you just write:
#Override
public void applyEQ(EConstants econs, String val) {
econs.apply(equery, val);
}
I am refactoring a part of our legacy app which handles exporting and importing of DB tables from/to Excel sheets. We have a Formatter subclass for each table, to provide the definition of that table: how many columns it has, and what is the name, format and validator of each column. The getters which supply this data are then called by a Template Method which exports/imports the table. I have extracted the column data into an enum, which greatly simplified the code. A formatter now looks like this (some details omitted for brevity):
public class DamageChargeFormatter extends BaseFormatter {
public static final int NUM_COLUMNS = 7;
public enum Column {
VEHICLE_GROUP(0, "Vehicle Group", /* more params */),
NAME_OF_PART(1, "Name of Part", /* more params */),
//...
LOSS_OF_USE(6, "Loss of Use", /* more params */);
private static final Map<Integer, Column> intToColumn = new HashMap<Integer, Column>();
static {
for (Column type : values()) {
intToColumn.put(type.getIndex(), type);
}
}
public static TableColumn valueOf(int index) {
return intToColumn.get(index);
}
private int index;
private String name;
Column(int index, String name, /* more params */) {
this.index = index;
this.name = name;
//...
}
public int getIndex() { return index; }
public String getName() { return name; }
// more members and getters...
}
protected String getSheetName() {
return "Damage Charges";
}
public String getColumnName(int columnNumber) {
TableColumn column = Column.valueOf(columnNumber);
if (column != null) {
return column.getName();
}
return null;
}
// more getters...
protected int getNumColumns() {
return NUM_COLUMNS;
}
protected boolean isVariableColumnCount() {
return false;
}
}
Now, I have about a dozen such classes, each of which containing exactly the same code except that NUM_COLUMNS and the enum values of Column are different. Is there any way to genericize this somehow? The main obstacle to this is the static Column.valueOf() method and the static constant NUM_COLUMNS. Another concern with latter is that it really belongs to an abstraction one level higher, i.e. to the table, not to an individual column - it would be nice to somehow incorporate this into the generic solution.
Technically I could solve this with a base interface (TableColumn below) and reflection, but I don't really like that, as apart from trading compile time errors to runtime errors, it makes the code ugly (to me):
public class GenericFormatter<E extends TableColumn> extends BaseFormatter {
private Method valueOfMethod;
public GenericFormatter(Class<E> columnClass) {
try {
valueOfMethod = columnClass.getDeclaredMethod("valueOf", Integer.class);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
public String getColumnName(int columnNumber) {
try {
#SuppressWarnings("unchecked")
E elem = (E) valueOfMethod.invoke(columnNumber);
if (elem != null) {
return elem.getName();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
return null;
}
//...
}
Note that this code is purely experimental, as yet untested...
Is there a nicer, cleaner, safer way?
May be, something like this:
public class TableMetadata<E extends Enum & TableColumn> {
private Map<Integer, TableColumn> columns = new HashMap<Integer, TableColumn>();
public TableMetadata(Class<E> c) {
for (E e: c.getEnumConstants()) {
columns.put(e.getIndex(), e);
}
}
public String getColumnName(int index) {
return columns.get(index).getName();
}
}
public class GenericFormatter<E extends TableColumn> extends BaseFormatter {
private TableMetadata<E> m;
public GenericFormatter(TableMetadata<E> m) {
this.m = m;
}
public String getColumnName(int columnNumber) {
return m.getColumnName(index);
}
//...
}
EDIT: Enum added to the type parameter for more compile-time safety