I've got widely used method like:
public Map<String, Double> parseData(String[] data) {
.................
Where data is something like new String[] { "column1 -> 2.00", "column2 -> New York", ... }
Problem: It appears that data can contains both: String -> Double & String -> String values. So I need smth like:
public Map<String, String or Double> parseData(String[] data) {
................
Question: Any ideas besides return Map<String, Object>?
Create a Wrapper StringOrDouble which will look a bit like this:
public class StringOrDouble {
private String internalString;
private Double internalDouble;
public StringOrDouble(String input) {
internalString = input;
}
public StringOrDouble(Double input) {
internalDouble = input;
}
public boolean hasString() {
return internalString != null;
}
public boolean hasDouble() {
return internalDouble != null;
}
public String getString() {
return internalString;
}
public Double getDouble() {
return internalDouble;
}
}
Then have a map of type Map<String, StringOrDouble> and use that. When you use the values, you can check which one it is by testing with hasString() and/or hasDouble(). Alternatively you could have an enum which determines which type it is.
public Map<String, Container> parseData(String[] data)
You can introduce a wrapper class for this
public class Container {
private String s;
private Double d;
public Container(String s) {
this.s=s;
}
public Container(Double d) {
this.d=d;
}
public hasString() {
return s!=null;
}
public hasDouble() {
return d!=null;
}
//getters/setters
}
As far as I understand, you want something like Map<String, ? extends String || Double as the return type, but no such thing is supported in Java:
4.9 Intersection Types An intersection type takes the form T1 & ... & Tn, n>0, where Ti, 1in, are type expressions. Intersection types arise
in the processes of capture conversion (§5.1.10) and type inference
(§15.12.2.7). It is not possible to write an intersection type
directly as part of a program; no syntax supports this. The values of
an intersection type are those objects that are values of all of the
types Ti, for 1in.
So you'd better parse the input array and hold different arrays for each different type or you can use a wrapper class to represent the values in the map returned, as some other answerers explained.
Use superclass:
public Map<String, Object> parseData(String[] data)
Just an alternative to #blalasaadri. don't pretend to be better:
public static class StringDoubleValue {
private final Optional<String> sValue;
private final Optional<Double> dValue;
public MetricValue(String sValue) {
this.sValue = Optional.of(sValue);
this.dValue = Optional.absent();
}
public MetricValue(Double dValue) {
this.sValue = Optional.absent();
this.dValue = Optional.of(dValue);
}
public Object get() {
return (sValue.isPresent()) ? sValue.get() : dValue.get();
}
#Override
public String toString() {
if (sValue.isPresent()) ? sValue.get() : dValue.get().toString();
}
}
Related
I have an enum like below. Until recently, all variables were single-valued. However, now TYPE4 can have one of three acceptable values. I was hoping to simply modify this enum to accommodate for TYPE4, but thinking perhaps having only one type that is multi-valued means I need to use an object for mapping rather than an enum. I would be grateful for any insights. Thank you.
public enum Record {
TYPE1("TYPE1"),
TYPE2("TYPE2"),
TYPE3("TYPE3"),
TYPE4_MULTI(TYPE_A or TYPE_B or TYPE_C);
private final String value;
public static final Map<Record, String> enumMap = new EnumMap<Record, String>(
Record.class);
static {
for (Record e : Record.values())
enumMap.put(e, e.getValue());
}
Record(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
Operationally, I use this enum in a factory class to determine which of 4 types of subclasses I should instantiate. I do this by have each of the subclasses know its own type like this:
#Override
public String getType() {
return Record.TYPE1.getValue();
}
,and then the factory class pre-builds a set of the subclasses like this:
#Component
public class RecordProcessorFactory {
#Autowired
public RecordProcessorFactory(List<RecordProcessor> processors) {
for (RecordProcessor recordProcessor : processors) {
processorCache.put(recordProcessor.getType(), recordProcessor);
}
}
private static final Map<String, RecordProcessor> processorCache = new HashMap<String, RecordProcessor>();
public RecordProcessor getSyncProcessor(String type) {
RecordProcessor service = processorCache.get(type);
if(service == null) throw new RuntimeException("Unknown service type: " + type);
return service;
}
}
You could use a String array to store multiple values, note that your logic may change with enumMap that way.
public enum Record {
TYPE1("TYPE1"),
TYPE2("TYPE2"),
TYPE3("TYPE3"),
TYPE4_MULTI("TYPE_A", "TYPE_B", "TYPE_C");
private final String[] values;
public static final Map<Record, String[]> enumMap = new EnumMap<Record, String[]>(Record.class);
static {
for (Record e : Record.values())
enumMap.put(e, e.getValues());
}
Record(String... values) {
this.values = values;
}
public String[] getValues() {
return values;
}
}
In case you need to get the Enum from a String value, you could add this static method:
public static Optional<Record> optionalValueOf(final String value) {
for (Record record : values()) {
for (String recordValue : record.values) {
if (null == value && null == recordValue || value.equals(recordValue)) {
return Optional.of(record);
}
}
}
return Optional.empty();
}
I think it's better to encapsulate values in the enum. It should be immutable (array is not immutable data storage).
#lombok.Getter
public enum Record {
TYPE1("TYPE1"),
TYPE2("TYPE2"),
TYPE3("TYPE3"),
TYPE4_MULTI("TYPE_A", "TYPE_B", "TYPE_C");
// immutable list
private final List<String> values;
Record(String... values) {
this.values = Arrays.stream(values)
.collect(Collectors.toList());
}
}
P.S. Map<Record, String> enumMap I think is useless, because you have a Record already and all you need just call record.getValues() instead of Record.enumMaps.get(record). Also, this is breakes OOP encapsulation.
I have either one of following Objects, ObjOne and ObjTwo, going into my function, both sharing similar getters/setters.
Currently I have an intermediary, a mapper, used across internal methods, but there might be a cleaner way to do this without a mapper but lacking specific syntax.
public String mapper(Object obj){
Map<String, String> map = new HashMap<>();
if(obj instanceof ObjOne){
ObjOne obj1 = (ObjOne)obj;
map.put("firstKey", obj1.getFirstValue());
}
else if(obj instanceof ObjTwo){
ObjTwo obj2 = (ObjTwo)obj
map.put("firstKey", obj1.getFirstValue());
}
return secondFunction(map);
}
private String secondFunction(Map<String, String> map){
return thirdFunction(map.get("firstKey"));
}
Is there such syntax for (ObjOne || ObjTwo)obj).getFirstValue() to feed into thirdFunction herein?
Edit: I imported these Objects, so I can't declare a parent class for them, they do share getters/setters that are convenient for my scenario.
A more OO approach is to compose the objects you don't control within a new object that you do control. Then write your API in terms of the object you control.
final class ObjOne {
String getFirstValue() {
return "foo";
}
}
final class ObjTwo {
String getFirstValue() {
return "bar";
}
}
class MyAdapter {
final Map<String, String> map = new HashMap<>();
MyAdapter(ObjOne o1) {
this(o1.getFirstValue());
}
MyAdapter(ObjTwo o2) {
this(o2.getFirstValue());
}
MyAdapter(String firstKey) {
map.put("firstKey", firstKey);
}
}
public String secondFunction(MyAdapter adapter) {
return thirdFunction(adapter.map.get("firstKey"));
}
One suggestion don't pass Object instead do something like this create a base model use here polymorphism. for example.
abstract class BaseObj {
abstract public String getFirstValue();
}
class ObjOne extends BaseObj{
#Override
public String getFirstValue() {
return "something useful";
}
}
class ObjTwo extends BaseObj{
#Override
public String getFirstValue() {
return "something useful";
}
}
not sure what is the use case here but you can always mold accordingly.
public String mapper(BaseObj obj){
Map<String, String> map = new HashMap<>();
map.put("firstKey", obj.getFirstValue()); //common function call
return secondFunction(map);
}
private String secondFunction(Map<String, String> map){
return thirdFunction(map.get("firstKey"));
}
private String thirdFunction(String firstKey) {
return null;
}
Coming from C++ and currently employed in a Java environment, I was wondering how I would be able to create a mapping of void* and void* in Java in order to create a generic mapping from A to B and from B to A. I am aware that Java doesn't have pointers and references the way C++ does, but am failing to find a method that would still allow this.
An example of what I am trying to achieve:
public class A{
#GenericMapping(1)
private Integer temp1;
}
public class B{
#GenericMapping(1)
private Integer temp2;
}
public class Mapper{
private List<Pair<Integer, Integer>> mapping;
public void map(Object ObjectOfAnyClassButLetsAssumeA, Object ObjectOfAnyClassButLetsAssumeB){
// Get all parameters with GenericMapping above it, get its value
// and match the corresponding value with the value of B
// Resulting in A.temp1 = B.temp2;
}
}
However, if possible I'd rather create a map (like map[A.temp1] = B.temp2) in order to avoid using the #GenericMapping, seeing as that would allow me to not modify the class in any way and still facilitate its mapping.
I think I understand what you want to do here and you can accomplish it with some metadata and Java 8's Lambdas.
What we do is set up a helper class that contains all mappings identified by class and IDs (analogous to your #GenericMapping but without actually annotating the classes) and containing methods for setting and getting the value. It's important that all mappings for the same ID have the same value type or a ClassCastException may be thrown when transferring values.
My example uses three classes where not all mappings apply to all classes.
Here's the code:
public class GenericMappingDemo {
static class A {
private Integer integerA;
private String stringA;
private Float floatA;
public A(final Integer integerA, final String stringA, final Float floatA) {
this.integerA = integerA;
this.stringA = stringA;
this.floatA = floatA;
}
public Integer getIntegerA() {
return integerA;
}
public void setIntegerA(final Integer integerA) {
this.integerA = integerA;
}
public String getStringA() {
return stringA;
}
public void setStringA(final String stringA) {
this.stringA = stringA;
}
public Float getFloatA() {
return floatA;
}
public void setFloatA(final Float floatA) {
this.floatA = floatA;
}
#Override
public String toString() {
return "A{integerA=" + integerA + ", stringA='" + stringA + "', floatA=" + floatA + '}';
}
}
static class B {
private Integer integerB;
private String stringB;
public Integer getIntegerB() {
return integerB;
}
public void setIntegerB(final Integer integerB) {
this.integerB = integerB;
}
public String getStringB() {
return stringB;
}
public void setStringB(final String stringB) {
this.stringB = stringB;
}
#Override
public String toString() {
return "B{integerB=" + integerB + ", stringB='" + stringB + '\'' + '}';
}
}
static class C {
private Float floatC;
private String stringC;
public Float getFloatC() {
return floatC;
}
public void setFloatC(final Float floatC) {
this.floatC = floatC;
}
public String getStringC() {
return stringC;
}
public void setStringC(final String stringC) {
this.stringC = stringC;
}
#Override
public String toString() {
return "C{floatC=" + floatC + ", stringC='" + stringC + "'}";
}
}
static class GenericMapping<C, T> {
final int id;
final Class<C> type;
final Function<C, T> getter;
final BiConsumer<C, T> setter;
public GenericMapping(final int id,
final Class<C> type,
final Function<C, T> getter,
final BiConsumer<C, T> setter) {
this.id = id;
this.type = type;
this.getter = getter;
this.setter = setter;
}
}
static class Mapper {
// All mappings by class and id
private final Map<Class<?>, Map<Integer, GenericMapping<?, ?>>> mappings
= new HashMap<>();
public void addMapping(GenericMapping<?, ?> mapping) {
mappings.computeIfAbsent(mapping.type,
c -> new TreeMap<>()).put(mapping.id, mapping);
}
/**
* Map values from one object to another,
* using any mapping ids that apply to both classes
* #param from The object to transfer values from
* #param to The object to transfer values to
*/
public <From, To> void map(From from, To to) {
Map<Integer, GenericMapping<?, ?>> getters
= mappings.get(from.getClass());
Map<Integer, GenericMapping<?, ?>> setters
= mappings.get(to.getClass());
if (getters == null || setters == null) {
// Nothing to do
return;
}
// Create a set with the ids in both getters and
// setters, i.e. the mappings that apply
Set<Integer> ids = new HashSet<>(getters.keySet());
ids.retainAll(setters.keySet());
// Transfer all mappings
for (Integer id : ids) {
GenericMapping<From, ?> getter
= (GenericMapping<From, ?>) getters.get(id);
GenericMapping<To, ?> setter
= (GenericMapping<To, ?>) setters.get(id);
transfer(from, to, getter, setter);
}
}
private <From, To, V> void transfer(final From from,
final To to, final GenericMapping<From, ?> getter,
final GenericMapping<To, V> setter) {
// This will throw an exception if the mappings are invalid
final V value = (V) getter.getter.apply(from);
setter.setter.accept(to, value);
}
}
public static void main(String[] args) {
final Mapper mapper = new Mapper();
// Mapping definition for class A
mapper.addMapping(new GenericMapping<>(1, A.class,
A::getIntegerA, A::setIntegerA));
mapper.addMapping(new GenericMapping<>(2, A.class,
A::getStringA, A::setStringA));
mapper.addMapping(new GenericMapping<>(3, A.class,
A::getFloatA, A::setFloatA));
// Mapping definition for class B
mapper.addMapping(new GenericMapping<>(1, B.class,
B::getIntegerB, B::setIntegerB));
mapper.addMapping(new GenericMapping<>(2, B.class,
B::getStringB, B::setStringB));
// Mapping definition for class C
mapper.addMapping(new GenericMapping<>(2, C.class,
C::getStringC, C::setStringC));
mapper.addMapping(new GenericMapping<>(3, C.class,
C::getFloatC, C::setFloatC));
// Use the mappings
A a = new A(7, "foo", 3.7f);
B b = new B();
C c = new C();
System.out.printf("A before map: %s%n", a);
System.out.printf("B before map: %s%n", b);
System.out.printf("C before map: %s%n", c);
// This will transfer a.integerA to b.integerB and a.stringA to b.stringB
mapper.map(a, b);
// This will transfer a.stringA to c.stringC and a.floatA to c.floatC
mapper.map(a, c);
System.out.println();
System.out.printf("A after map: %s%n", a);
System.out.printf("B after map: %s%n", b);
System.out.printf("C after map: %s%n", c);
}
}
And the result after running it:
A before map: A{integerA=7, stringA='foo', floatA=3.7}
B before map: B{integerB=null, stringB='null'}
C before map: C{floatC=null, stringC='null'}
A after map: A{integerA=7, stringA='foo', floatA=3.7}
B after map: B{integerB=7, stringB='foo'}
C after map: C{floatC=3.7, stringC='foo'}
Java 7
The same general solution can be used for Java 7, but it will be a lot more verbose. Since Java 7 doesn't have the functional interfaces Function<U, V> and BiConsumer<U, V> you'll need to define these yourself, which isn't that much trouble. It could be argued that they should be defined in Java 8 too so interface and method names makes more sense (e.g. Getter.get and Setter.set).
The big thing is the mapping definitions which will have to use anonymous classes instead of lambdas - lambdas is mostly syntactic sugar for anonymous classes with only one method anyways, but they make the code a lot more readable.
The mapping for a.integerA will look like this in Java 7:
mapper.addMapping(new GenericMapping<>(1, A.class,
new Function<A, Integer>() {
#Override
public Integer apply(final A a1) {
return a1.getIntegerA();
}
},
new BiConsumer<A, Integer>() {
#Override
public void accept(final A a1, final Integer integerA) {
a1.setIntegerA(integerA);
}
}));
You could also have a look at Apache Commons BeanUtils, which also have a quite sophisticated, although explicit (not Annotation-based), Converter API:
http://commons.apache.org/proper/commons-beanutils/javadocs/v1.9.3/apidocs/org/apache/commons/beanutils/Converter.html
http://commons.apache.org/proper/commons-beanutils/javadocs/v1.9.3/apidocs/org/apache/commons/beanutils/ConvertUtilsBean.html
I am struggling to find a way to dispatch this to functions in java8
Person p = registry.getPerson();
if (field == Field.LASTNAME) {
p.setLastName(str);
}
if (field == Field.FIRSTNAME) {
p.setFirstName(str);
}
if (field == Field.MIDDLENAME) {
p.setMiddleName(str);
}
My idea is to use some kind of function dispatch table to replace the if statements in the case of more cases:
Map<Integer, Function> map = new HashMap<Integer, Function>
static {
map.put(1, new Function<String, String>() {
#Override
public Object apply(String str) {
person.setLastName(str);
return str;
}
}
}
But the code cannot compile, because i need to pass the person object some place. Anyone knows a pattern for this?
Assuming Field is an enum, you can add BiConsumer<Person,String> as an enum field:
class Person {
static enum Field {
FIRSTNAME(Person::setFirstName),
MIDDLENAME(Person::setMiddleName),
LASTNAME(Person::setLastName)
;
private BiConsumer<Person, String> setter;
private Field(BiConsumer<Person, String> setter) {
this.setter = setter;
}
}
public void set(Field field, String str) {
field.setter.accept(this, str);
}
......
}
Instead of storing Function<String,String>, you can store BiFunction<Person,String,String> and pass the Person instance in as a parameter.
Map<Integer, BiFunction<Person,String,String>> map =
new HashMap<Integer, BiFunction<Person,String,String>>();
static {
map.put(1, (person, str)->person.setLastName(str));
}
In the interest of simplicity, you could also just store a List of the functions, if you're just going to index them by an integer, it's faster for random access and makes for less complicated generic code:
List<BiFunction<Person,String,String>> list = new ArrayList<BiFunction<Person,String,String>>();
static {
list.add((person, str)->person.setLastName(str));
}
Here's my code .Basically I trying to return a Map from my intToEnumMap method.But compiler is not allowing this.Why can't the compiler infer the return type for my method?
public enum INVALIDTHRESHOLDSTATE{
ONE(0,GAUGE_MIN_LOWER_THRESHOLD1_MESSAGE),
TWO(1,GAUGE_THRESHOLD1_LOWER_THRESHOLD2_MESSAGE),
THREE(2,GAUGE_THRESHOLD2_LOWER_MAX_MESSAGE);
private static final Map<Integer,INVALIDTHRESHOLDSTATE> intToEnum = new HashMap<Integer, INVALIDTHRESHOLDSTATE>();
static {
int i=0;
for (INVALIDTHRESHOLDSTATE invalidState : values()){
i++;
intToEnum.put(Integer.valueOf(i), invalidState);
}
}
private int value;
private String message;
private INVALIDTHRESHOLDSTATE(int value,String message){
this.value = value;
this.message = message;
}
public int getValue() {
return value;
}
public String getString() {
return message;
}
// Generic method
public static <K,V> Map<K,V> intToEnumMap() {
return intToEnum; //doesn't compile
^^^^^^^^^
}
}
You've created a generic method, so anyone could call:
Map<String, Long> map = INVALIDTHRESHOLDSTATE.<String, Long> intToEnumMap();
I assume that's not what you intended - if you're returning intToEnum it looks to me like you don't want the callers to specify generic type arguments at all, and it should just be:
public static Map<Integer, INVALIDTHRESHOLDSTATE> intToEnumMap() {
return intToEnum;
}
(I'd also strongly suggest renaming your enum to follow normal Java naming conventions, but that's a different matter.)