简体   繁体   中英

How to avoid reflection using enums

I recently asked a question about some code of mine where I used reflection and one who wanted to help me with this problem mentioned that I shouldn't use reflection like this and that there is a better way doing it.

So I have an Interface for searching in external Systems:

public interface ReferenceController {

  public Map<String, ReferenceElement> searchElements(String searchField, List<String> searchItems, SystemStage systemStage) throws Exception;

  public String getStateMapping(String value);

  public Boolean isAvailable(SystemStage systemStage) throws Exception;
}

And I have an ENUM where I declare which external systems I have and how their class is named which uses this interface. So if any other programmer want's to implement a new external system he has only to fill the interface and put two values in this ENUM and tada it should work.

So the part where I used the reflection was

public static void performSingleSearch(ReferenceSystem referenceSystem, String searchField, List<String> searchValues, SystemStage systemStage) throws Exception {

    if(!isAvailable(referenceSystem, systemStage)) return;
    Map<String, ReferenceElement> result = new HashMap<>();
    try {
        Class<?> classTemp = Class.forName(referenceSystem.getClassname());
        Method method = classTemp.getMethod("searchElements", String.class , List.class, SystemStage.class);
        result = (Map<String, ReferenceElement>) method.invoke(classTemp.newInstance(), searchField, searchValues, systemStage);
    } catch (Exception e) { 
        return;
    }
    if(result != null) orderResults(result, referenceSystem);
}

In the ENUM ther is a function getClassname, which answers with the fqcn. The Enum looks like this:

public enum ReferenceSystem {
    UCMDB    (refSystems.ucmdb.UcmdbFunctions.class),
    PROIPS   (refSystems.proips.ProIPSFunctions.class),
    KV       (refSystems.kv.KvFunctions.class),
    FISERVICE(refSystems.fiservice.FiServiceFunctions.class),
    COMMAND  (refSystems.command.CommandFunctions.class),
    FII          (refSystems.fii.FiiFunctions.class);

    private Class<?> clazz;

    private ReferenceSystem(Class<?> controllerClass) {
        this.clazz = controllerClass;
    }

    public String displayName() {
        ResourceBundle bundle = ResourceBundle.getBundle("EnumI18n", Locale.GERMAN);
        return bundle.getString(toString()); 
    }

    public String localizedDisplayName(Locale locale) {
        ResourceBundle bundle = ResourceBundle.getBundle("EnumI18n", locale);
        return bundle.getString(toString()); 
    }

    public Class<?> getClassname() { return clazz; }
}

I've already altered it according to @jhamon 's answer.

But I get an error when I try

classTemp.newInstance().searchElemets(...)

Because it doesn't know about searchElemts().

So the other user here said there would be the possibility of implementing the interface into the enum and then I don't have to reflect. Could anyone tell me how, because I don't know and I don't know where or what to search. Thanks

It seems all your search engines have a common method searchElements and it's defined in the interface

Knowing that, why not call this method directly, and not by looking for it first. -> no more reflection to find the method.

public interface ReferenceController {

    public Map<String, ReferenceElement> searchElements(String searchField, List<String> searchItems, SystemStage systemStage) throws Exception;

    public String getStateMapping(String value);

    public Boolean isAvailable(SystemStage systemStage) throws Exception;
}

Instead of storing the class name as String in the Enum, store the .class -> no more reflection to find the class.

public static void performSingleSearch(ReferenceSystem referenceSystem, String searchField, List<String> searchValues, SystemStage systemStage) throws Exception {

    if(!isAvailable(referenceSystem, systemStage)) return;
    Map<String, ReferenceElement> result = new HashMap<>();
    try {
        Class<?> classTemp = referenceSystem.getClazz();
        result = ((ReferenceController) classTemp.newInstance()).searchElements(searchField, searchValues, systemStage);
    } catch (Exception e) { 
        return;
    }
    if(result != null) orderResults(result, referenceSystem);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM