Search code examples
javagenericsjava-8code-reuse

Is it possible to create a generic method that is suitable for different classes in Java?


I have different classes that have a structure like this:

public class MyClass {
    private String name;
    private List<International> internationalList;
}

What I want is to have a generic method that given a localization (example: "en-us") it searches at the internationalList and set the name with the correct language.

Example:

 public MyClass myMethod(String local, MyClass object){

            for (International international : object.internationalList){
                if(local.equals(international.language)){
               object.name = international.translation
         }
      }
    return myObject;
 }

I didn't want to re-write this code to every class. Is it possible to create a generic method that is suitable for all classes that have this structure?


Solution

  • Define your interfaces

    You can create a interface that will be implemented by MyClass

    public interface LocationAware {
        String getName();
        void setName(String name);
        List<International> getInternationals();
        void setInternationals(List<International> internationals);
    }
    

    Then implement the class like

    public static class MyClass implements LocationAware {
        private String name;
        private List<International> internationalList;
        // getter and setters
    }
    

    You can also use an interface for International and implement the class.

    public interface International {
        String getLanguage();
        String getTranslation();
    }
    

    Using a helper method

    And you would have the helper method with generics, in any class that you want, e.g. StaticClass.

    public static <T extends LocationAware> T changeLocationName(String local, T object) {
        for (International international : object.getInternationals()) {
            if(local.equals(international.getLanguage())) {
                object.setName(international.getTranslation());
            }
        }
        return object;
    }
    

    That can be called with:

    StaticClass.changeLocationName("en-us", myClass);
    

    Using a default method

    Since you are already using an interface you can have a default method that gives you the same functionallity without a helper method.

    public interface LocationAware {
        default void changeLocationName(String local) {
            for (International international : getInternationals()) {
                if(local.equals(international.getLanguage())) {
                    setName(international.getTranslation());
                }
            }
        }
        String getName();
        void setName(String name);
        List<International> getInternationals();
        void setInternationals(List<International> internationals);
    }
    

    And just use the class method:

    MyClass myClass = new Myclass(); // create and add name and internationals
    myClass.changeLocationName("en-us"); // then change the location
    

    Here you can decide many other ways on how to handle local, you can for instance, store the value, and when you use getName(), return the current name dinamically, so you don't change the current name every time, (can use a map for little performance gain also).

    public interface LocationAware {
        default String getName() {
            return getInternationals().get(getLocal());
        }
        void setName(String local);
        String getLocal();
        void setLocal(String local);
        Map<String, International> getInternationals();
        void setInternationals(Map<String, International> internationals);
    }
    

    note: you should handle the cases where the location dos not exists