How to Handle two different Objects for same Function - java

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;
}

Related

Java - enum where one variable can be multi-valued

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.

Java 8 - Map between class to one of its function

I have multiple types of objects, I'd like to generalise the 'id' of the objects in a way that will dynamically change what field is selected as the id.
Example
public class ObjectA{
//Attribute name attA
private String attA;
.... More attributes
public String getAttA(){
return attA
}
.....More getters/setters
}
public class ObjectB{
//Attribute named attB
private String attB;
.... More attributes
public String getAttB(){
return attB
}
.... More getters and setters
}
Id like to be able to run something like this:
Map<????, ????> customIdMap = new HashMap<>();
//We decide that ObjectA main attribute is AttA
customIdMap.add(ObjectA.class, ObjectA::getAttA);
//We decide that ObjectB main attribute is AttB
customIdMap.add(ObjectB.class, ObjectB::getAttB);
Then I'll be able to have a list of general objects and ill be able to retrieve their ids from the map if it is a known object with:
public String getCustomId(Object object){
if(customIdMap.contains(object.getClass()){
//Parameters are messed up, but this is the general idea of how
//i thought this would look
return customIdMap.get(object.getClass()).apply(object);
}
}
The code above does not run since getAttA is a call to a none static method in a static context so i assume this maybe should be wrapped in some kind of generic object.
Can it be done?
Preferably you change ObjectA and ObjectB to have a common interface. If that's not possible you can put them into a map like this:
Map<Class<? extends Object>, Function<Object, String>> map = new HashMap<>();
map.put(ObjectA.class, a -> ((ObjectA) a).getAttA());
map.put(ObjectB.class, b -> ((ObjectB) b).getAttB());
EDIT:
Or if you would like to encapsulate it into a typesafe heterogeneous container:
public static class ToIdMap {
private final Map<Class<?>, Function<Object, String>> map = new HashMap<>();
public <X> void put(Class<X> clazz, Function<X, String> func) {
map.put(clazz, (Function<Object, String>) func);
}
public String toIdString(Object o) {
return map.get(o.getClass()).apply(o);
}
}
EDIT2: Note that neither of these solutions work for subclasses, but it could be supported by traversing the class hierarchy in toIdString.
Your wording is a bit unclear, but I assume you want to get the ID of an object, even when they are different classes. This is the problem that interfaces solve.
You can create an interface, with one method called getId(), which will return the id. Then, you can just call getId() on any type of object with an id.
For example:
public interface Identifiable {
String getId();
}
public class ObjectA implements Identifiable {
// same for ObjectB
#Override
public String getId() {
return id;
}
}
Then, in your code:
Identifiable i1 = new ObjectA();
Identifiable i2 = new ObjectB();
System.out.println(i1.getId());
System.out.println(i2.getId());
EDIT:
It still looks like an interface is the cleanest way of solving your problem. For completeness, the following will work:
Map<Class, Function<?, String> map = new HashMap<>();
map.put(Object1.class, (Object1 o) -> o.getAttrA); // repeat for ObjectB
It can then be called with:
if (obj instanceof Object1) return map.get(Object1.class).apply((ObjectA) obj);
Ended up doing this weird solution:
class Mapping<T> {
private Function<T, String> idFunc;
public Mapping(Function<T, String> idFunc) {
this.idFunc = idFunc;
}
public String apply(T obj) {
return idFunc.apply(obj);
}
}
}
private Map<Class, Mapping> mappings = new HashMap<>();
mappings.put(ObjectA.class, new Mapping<>(ObjectA::getAttA);
mappings.put(ObjectB.class, new Mapping<>(ObjectB::getAttB);
public String getObjectID(Object object){
String id = null;
if(mappings.containsKey(object.getClass())){
id = mappings.get(object.getClass()).apply(object);
}
return id;
}

How to reuse code in multiple enum names?

I have below Enum from which I am calling appropriate execute method basis on what type of enum (eventType) is passed.
public enum EventType {
EventA {
#Override
public Map<String, Map<String, String>> execute(String eventMapHolder) {
final Map<String, String> holder = parseStringToMap(eventMapHolder);
if (holder.isEmpty() || Strings.isNullOrEmpty(holder.get("m_itemId"))) {
return ImmutableMap.of();
}
String itemId = holder.get("m_itemId");
Map<String, String> clientInfoHolder = getClientInfo(itemId);
holder.putAll(clientInfoHolder);
return ImmutableMap.<String, Map<String, String>>builder().put(EventA.name(), holder)
.build();
}
},
EventB {
#Override
public Map<String, Map<String, String>> execute(String eventMapHolder) {
final Map<String, String> holder = parseStringToMap(eventMapHolder);
if (holder.isEmpty() || Strings.isNullOrEmpty(holder.get("m_itemId"))) {
return ImmutableMap.of();
}
return ImmutableMap.<String, Map<String, String>>builder().put(EventB.name(), holder)
.build();
}
},
EventC {
#Override
public Map<String, Map<String, String>> execute(String eventMapHolder) {
final Map<String, String> holder = parseStringToMap(eventMapHolder);
if (holder.isEmpty() || Strings.isNullOrEmpty(holder.get("m_itemId"))) {
return ImmutableMap.of();
}
String itemId = holder.get("m_itemId");
Map<String, String> clientInfoHolder = getClientInfo(itemId);
holder.putAll(clientInfoHolder);
return ImmutableMap.<String, Map<String, String>>builder().put(EventC.name(), holder)
.build();
}
};
public abstract Map<String, Map<String, String>> execute(String eventMapHolder);
public Map<String, String> parseStringToMap(String eventMapHolder) {
// parse eventMapHolder String to Map
}
public Map<String, String> getClientInfo(final String clientId) {
// code to populate the map and return it
}
}
For example: If I get "EventA", then I am calling it's execute method. Similarly if I get "EventB" then I am callings it's execute method and so on.
String eventType = String.valueOf(payload.get("eventType"));
String eventMapHolder = String.valueOf(payload.get("eventMapHolder"));
Map<String, Map<String, String>> processedMap = EventType.valueOf(eventType).execute(eventMapHolder);
In general I will have more event types (around 10-12) in the same enum class and mostly they will do same operation as EventA, EventB and EventC.
Question:
Now as you can see, code in execute method of EventA and EventC are identically similar but the only difference is what I put as "key" (event name) in the returned immutable map. Is there any way to remove that duplicated code but still achieve the same functionality in the enum.
For example, something on this ground. By writing multiple enums side by side separated by comma (if the execute method functionality is same). I know this doesn't work because I have a abstract method which I need to implement it everywhere but is it still possible by making some changes or any other better way?
public enum EventType {
EventA,
EventC {
#Override
public Map<String, Map<String, String>> execute(String eventMapHolder) {
// same code which is there in execute method for EventA and EventC
}
},
EventB {
#Override
public Map<String, Map<String, String>> execute(String eventMapHolder) {
// same code which is there in execute method of EventB
}
};
// other methods which are there already
}
I know one way is to make a method with all the common things and call those method by passing appropriate Event type enum name. Is there any other way apart from that by using enum features or any other changes?
If there is any other better way or any other design pattern to do this then I am open for suggestions as welll which can help me remove duplicated code.
Idea is - basis on what type of event is passed, I want to call its execute method and avoid duplication if possible.
There are two simple mechanisms (that can of course be combined).
The first one consists in having the execute() in the base class, delegating to specific code defined in each subclass (i.e. the template method pattern):
enum Foo {
A {
#Override
protected void specificCode() {
//...
}
},
B {
#Override
public void specificCode() {
//...
}
};
public void execute() {
// ... common code
specificCode();
// ... common code
}
protected abstract void specificCode();
}
The second one consists in having the execute() overridden in each subclass but delegating to a common method defined in the base class:
enum Foo {
A {
#Override
public void execute() {
//...
commonCode();
// ...
}
},
B {
#Override
public void execute() {
//...
commonCode();
// ...
}
};
public abstract void execute();
protected void commonCode() {
// ...
}
}
Something like this?
package enumCodeReuse;
import java.util.Map;
import com.google.common.collect.ImmutableMap;
public enum EventType2 {
EventA
, EventB
, EventC
;
public Map<String, Map<String, String>> execute(String eventMapHolder) {
final Map<String, String> holder = parseStringToMap(eventMapHolder);
if (holder.isEmpty() || Strings.isNullOrEmpty(holder.get("m_itemId"))) {
return ImmutableMap.of();
}
String itemId = holder.get("m_itemId");
Map<String, String> clientInfoHolder = getClientInfo(itemId);
holder.putAll(clientInfoHolder);
return ImmutableMap.<String, Map<String, String>>builder()
.put(this.name(), holder)
.build();
};
public Map<String, String> parseStringToMap(String eventMapHolder) {
// parse eventMapHolder String to Map
return null; // FIXME
}
public Map<String, String> getClientInfo(final String clientId) {
// code to populate the map and return it
return null; // FIXME
}
}

Convert multiple if statements to dispatch functions

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));
}

Refactoring: Map<String, Double> to Map<String, Double or String>

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();
}
}

Categories

Resources