0

I am having an object with 30 instance variables, depending on one instance variable eg:

if obj.var1 == 'A' : Get 5 variable values
else if obj.var1 == 'B' : Get another 5 variable values

I have a mapping of condition to required fields from obj eg:

A -> {FieldName1, FieldName2, FieldName3}
B -> {FieldName1, FieldName3, FieldName5, FieldName7}

Reflection would give me the values of the instance variables, how to achieve this with java8 in an efficient way.

Few of my references: Get the class instance variables and print their values using reflection , https://codereview.stackexchange.com/questions/108222/getting-a-list-of-all-fields-in-an-object

eg:test mock code

public class Test {

private String var1;
private String var2;
private String var3;
private String var4;
private String var5;
private String var6;
private String var7;
private String var8;
private String var9;
private String var10;

// getters and setters

public Test() {
}


public static void main(String[] args) {
    Test obj = new Test();
    // Assume all ins variables are set with some value
    List resp = new ArrayList();
    if(obj.var1 == "A") {
        resp.add(obj.var2 + DescriptionEnum.Var2); // Also Here I need to get the variable description from enum)
        resp.add(obj.var3 + DescriptionEnum.);
        resp.add(obj.var7 + DescriptionEnum.);
        resp.add(obj.var8 + DescriptionEnum.);
    }

    else if(obj.var1 == "B") {
        resp.add(obj.var1 + DescriptionEnum.);
        resp.add(obj.var2 + DescriptionEnum.);
        resp.add(obj.var9  + DescriptionEnum.);
        resp.add(obj.var10 + DescriptionEnum.);
    }
}

Instead of above if-else, I thought of put the condition and list of fields in hashmap and do the operations eg:

map.put("A1", new String[]{'fieldName1', 'fieldName2'})
map.put("B1", new String[]{'fieldName1', 'fieldName2'})

So if the obj.var1 == 'A', I can get the list of required fields from map, now how to get the values from object and from enum to form the response?

Rinsen S
  • 461
  • 3
  • 10
  • 26
  • IMHO your question is too broad. If you're trying to instantiate an Object depending on 30 (or less/more) variables, you should consider a different approach. Enum, or else.... – zlakad Feb 18 '18 at 14:46
  • It would be much easier to answer with a test case – c0der Feb 18 '18 at 14:49
  • I already have an object :( now i need to work on that to get the details – Rinsen S Feb 18 '18 at 14:55

1 Answers1

3

Using functions

import java.util.List;
import java.util.Map;
import java.util.function.Function;

class Big {
    String director;
    String a;
    String b;
    String c;
    String d;
    String e;
    String f;
    String g;
}

public class Ex2 {
    Map<String, Function<Big, List<String>>> mappers = Map.of(
            "A", a -> List.of(a.a, a.b),
            "B", a -> List.of(a.c, a.d)
    );

    public List<String> parse(Big input) {
        return mappers.get(input.director).apply(input);
    }
}

The code above uses Map.of and List.of from Java 9 to improve readability, if you want to do this using Java 8 you can swap these out like this:

Map<String, Function<Big, List<String>>> mappers = new HashMap<String, Function<Big, List<String>>>() {
    {
        put("A", a -> Arrays.asList(a.a, a.b));
        put("B", a -> Arrays.asList(a.c, a.d));
    }
};

public List<String> parse(Big input) {
    return mappers.get(input.director).apply(input);
}

If you can avoid having such a large object you probably should, as it will simplify your code massively.

jrtapsell
  • 6,719
  • 1
  • 26
  • 49
  • Thanks for the solution, but we are using only java8 in production, so I cannot use java9. I will try to understand the above code :) Thanks for it, but can i know what changes to do for java8 instead of java9 – Rinsen S Feb 18 '18 at 15:13
  • 1
    Added it 10s before the comment :), I am using double brace though, which you might want to swap for initialising the object in the constructor. – jrtapsell Feb 18 '18 at 15:13
  • sure, thanks bro !!! i will read function and try above solution, once again thanks !! – Rinsen S Feb 18 '18 at 15:17
  • 2
    The double brace is evil, so definitely avoid that. Otherwise, a very nice solution that dodges reflection but retains the brevity. – kaqqao Feb 19 '18 at 07:50
  • 1
    @kaqqao and a clean `… mappers = new HashMap<>(); mappers.put("A", a -> Arrays.asList(a.a, a.b)); mappers.put("B", a -> Arrays.asList(a.c, a.d));` is even shorter… – Holger Feb 19 '18 at 10:40
  • @jrtapsell, thanks for the above solution, can I also know how to efficiently check if the ins variables are not null eg: whether a.a or a.b is not null and then add a.a + displaytext for that field from enum to get the result list.. – Rinsen S Feb 20 '18 at 14:34
  • So you are looking to try items and get the first non-null answer? – jrtapsell Feb 20 '18 at 15:13
  • @jrtapsell, no the above answer works well, but I want to ensure that the value is not null and add enum value to it and add to final arraylist. eg: instead of put("A", a -> Arrays.asList(a.a, a.b)) , I want to check for not null too eg: put("A", a-> { List arr = new ArrayList<>(); if(a.a != null) arr.add( Enum.A.getDisplayText() + " : " + a.a) if(a.b != null) arr.add( Enum.B.getDisplayText() + " : " + a.b) }) Is the above solution efficient and good ?? as I have around 7 values to be added to arraylist – Rinsen S Feb 21 '18 at 08:04
  • At that level of complexity you may be better off making a factory that makes display classes (you could have the enum members extract the relevant fields, which may decrease the complexity slightly) – jrtapsell Feb 21 '18 at 15:07
  • @jrtapsell, sorry for replying late, as I haven't seen the comment, oh but I am not sure of how to implement that, so I am implementing like put("A", a-> { List arr = new ArrayList<>(); if(a.a != null) arr.add( Enum.A.getDisplayText() + " : " + a.a) if(a.b != null) arr.add( Enum.B.getDisplayText() + " : " + a.b) }). Thanks !! Let me know if anything can be optimized or corrected – Rinsen S Feb 26 '18 at 12:01