0

I couldn't find a better title (feel free to edit it if you find a better one), but the use case is the following. I have two lists of constants. One of those contains the constants I use in my application, the other contains the different constants that are sent to me via a CSV file (along with data).

To give a rough exemple : in the CSV file, there is a field called "id of the client". In my application, I want to use a field called "clientId". So I basically need to create a static link between the two constants, so that I can easily switch from one to the other depending on what I need to achieve.

I've thought about creating a static Map(String, String) of values, but I figured there might be better solutions.

Thanks !

EDIT : changed title to "N" constants instead of 2, because Hashmap doesn't seem to be an option any longer in that case.

  • What's wrong with using a static Map then? – Thomas Aug 24 '17 at 09:09
  • Mostly that it needs to be filled in a static(){} method which will actually be pretty ugly looking code if the lists get really long. But it might just be the best solution, just wanted to make sure before I do choose it. – Christophe Schutz Aug 24 '17 at 09:12
  • Also, this solution wouldn't work if there needed to be a 3rd layer in my application (like a file I need to create and send to a 3rd party) and thus the need to link 3 constants together. – Christophe Schutz Aug 24 '17 at 09:14
  • Map seems to be best option, but it does not have to be static. Encapsulate it into class. – charlie_pl Aug 24 '17 at 09:25
  • 1
    Guava's `ImmutableMap` is great, and has a nice syntax for constructing it: `ImmutableMap.of("id of the client", "clientId", ...)`. Then you can also be certain that it won't accidentally be modified. – Thomas Aug 24 '17 at 09:26
  • Java 9 is just around the corner! You can use `Map.of(key1, value1, key2, value2, ...)`. – Klitos Kyriacou Aug 25 '17 at 11:08

4 Answers4

1

you can use the double bracket innitializer idiom to keep map initialization close to the map declaration, so it would be not so "ugly" eg:

static Map<String, String> someMap = new HashMap<String, String>() {{
        put("one", "two");
        put("three", "four");
}};

Beware that without the static modifier each anonymous class (there is one created in this example) holds a refernce to the enclosing object and if you'll give a reference to this map to some other class it will prevent the enclosing class from being garbage collect.

Fortunatelly, there is a hope for us with java update, in java 9 there will be very handy Map.of() to help us do it more safely.

Krzysztof Cichocki
  • 6,294
  • 1
  • 16
  • 32
  • Wait WHAT? When is this feature added? I never knew this existed! – Sweeper Aug 24 '17 at 09:20
  • @Sweeper have a look here: https://stackoverflow.com/questions/1958636/what-is-double-brace-initialization-in-java – Krzysztof Cichocki Aug 24 '17 at 09:21
  • Well, this is actually pretty sweet. Didn't know this existed either, take my upvote for science. :) I'm starting to use this atm, if no other/better ideas come up in a while i'll accept it as an answer. Thx ! – Christophe Schutz Aug 24 '17 at 09:23
  • This idiom does have its drawbacks. For example, it creates an extra .class file. And the variable you assign it to is not an actual HashMap but a subclass of it. You can google other drawbacks of the idiom. It's not necessarily a bad idiom; just pointing out some things to be aware of. – Klitos Kyriacou Aug 24 '17 at 09:35
0

The best way to separate the mapping from your application code is to use a properties file where in which you define your mapping.

For example, you could have a csv-mapping.properties in the root of your resources and load them with the following code:

final Properties properties = new Properties();

properties.load( this.getClass().getResourceAsStream( "/csv-mapping.properties" ) );

This will work just like a Map, with the added separation of code from configuration.

alirabiee
  • 1,286
  • 7
  • 14
0

There are many methods that you can use to easily solve these types of problem. One way is to use a Properties file, or file containing the key value pair.

Here is the code for Properties.

import java.util.ResourceBundle;

public class ReadingPropertiesFile {
    public static void main(String[] args) {
         ResourceBundle messages;
         messages = ResourceBundle.getBundle("msg");
         System.out.println(messages.getString("ID"));
    }
} 

msg.properties file contains values::

ID = ClientID. PRODUCT_ID = prod_ID

The output of the program is ClientID.

You can also read from a simple text file. Or you could use the map as you are using. But I would suggest you to use the properties file.

Abhishek Honey
  • 645
  • 4
  • 13
0

One good option would be to use an enum to create such mappings beetween multiple constants to a single common sense value, eg:

import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

public enum MappingEnum {
    CLIENT_ID("clientId",    "id of the client", "clientId", "IdOfTheClient"), 
    CLIENT_NAME("clientName",    "name of the client", "clientName");

    private Set<String> aliases;
    private String commonSenseName;

    private MappingEnum(String commonSenseName, String... aliases) {
        this.commonSenseName = commonSenseName;
        this.aliases = Collections.unmodifiableSet(new HashSet<String>(Arrays.asList(aliases)));
    }

    public static MappingEnum fromAlias(String alias) {
        for (MappingEnum mappingEnum : values()) {
            if (mappingEnum.getAliases().contains(alias)) {
                return mappingEnum;
            }
        }
        throw new RuntimeException("No MappingEnum for mapping: " + alias);
    }

    public String getCommonSenseName() {
        return commonSenseName;
    }
}

and then you can use it like:

String columnName = "id of the client";
String targetFieldName = MappingEnum.fromAlias(columnName).getCommonSenseName();
Krzysztof Cichocki
  • 6,294
  • 1
  • 16
  • 32