001package io.prometheus.jmx;
002
003import java.lang.reflect.InvocationTargetException;
004import java.lang.reflect.Method;
005import java.util.logging.Level;
006import java.util.logging.Logger;
007
008public class OptionalValueExtractor {
009
010    private static final Logger LOGGER = Logger.getLogger(OptionalValueExtractor.class.getName());
011
012    private static final String OPTIONAL_CLASS_NAME = "java.util.Optional";
013    private static final Class<?> OPTIONAL_CLASS = findOptionalClass();
014    private static final Method OR_ELSE_METHOD = findOrElseMethod();
015
016    private static Class<?> findOptionalClass() {
017        Class<?> optionalClass = null;
018        try {
019            optionalClass = Class.forName(OPTIONAL_CLASS_NAME);
020        } catch (ClassNotFoundException e) {
021            LOGGER.log(Level.FINE, "{0}: class not found (not running on Java 8+)", OPTIONAL_CLASS_NAME); // that's okay
022        }
023        if (optionalClass != null) {
024            LOGGER.log(Level.FINE, "{0} will be supported", OPTIONAL_CLASS_NAME);
025        }
026        return optionalClass;
027    }
028
029    private static Method findOrElseMethod() {
030        if (OPTIONAL_CLASS != null) {
031            try {
032                return OPTIONAL_CLASS.getMethod("orElse", Object.class);
033            } catch (NoSuchMethodException e) {
034                LOGGER.log(Level.WARNING, "{0}.orElse(Object): method not found!", OPTIONAL_CLASS_NAME); // that would be weird!
035            }
036        }
037        return null;
038    }
039
040    public boolean isOptional(Object o) {
041        return (o != null)
042                && OPTIONAL_CLASS == o.getClass() // Optional is final, no need for isAssignableFrom()
043                && OR_ELSE_METHOD != null; // would we be able to extract value from this Optional?
044    }
045
046    public Object getOptionalValueOrNull(Object o) {
047        try {
048            return OR_ELSE_METHOD.invoke(o, (Object) null);
049        } catch (IllegalAccessException e) {
050            LOGGER.log(Level.FINE, "IllegalAccessException calling orElse(null) on {0}", o);
051        } catch (IllegalArgumentException e) {
052            LOGGER.log(Level.FINE, "IllegalArgumentException calling orElse(null) on {0}", o);
053        } catch (InvocationTargetException e) {
054            LOGGER.log(Level.FINE, "InvocationTargetException calling orElse(null) on {0}", o);
055        }
056        return null;
057    }
058}