|
| 1 | +package graphql.validation.locale; |
| 2 | + |
| 3 | +import graphql.Internal; |
| 4 | +import graphql.schema.DataFetchingEnvironment; |
| 5 | + |
| 6 | +import java.lang.reflect.InvocationTargetException; |
| 7 | +import java.lang.reflect.Method; |
| 8 | +import java.util.Locale; |
| 9 | +import java.util.Map; |
| 10 | +import java.util.concurrent.ConcurrentHashMap; |
| 11 | + |
| 12 | +public class LocaleUtil { |
| 13 | + |
| 14 | + /** |
| 15 | + * This will try to determine the Locale from the data fetching env in a number of ways, searching |
| 16 | + * via the context and source objects and the data fetching environment itself. This plugs a gap while |
| 17 | + * graphql-java does not have a getLocale on ExecutionInput / DataFetchingEnvironment |
| 18 | + * |
| 19 | + * @param environment the fetching env |
| 20 | + * @param defaultLocale the default to use |
| 21 | + * |
| 22 | + * @return a Locale |
| 23 | + */ |
| 24 | + public static Locale determineLocale(DataFetchingEnvironment environment, Locale defaultLocale) { |
| 25 | + // |
| 26 | + // in a future version of graphql java the DFE will have the Locale but in the mean time |
| 27 | + Locale locale; |
| 28 | + locale = extractLocale(environment); |
| 29 | + if (locale == null) { |
| 30 | + locale = extractLocale(environment.getContext()); |
| 31 | + if (locale == null) { |
| 32 | + locale = extractLocale(environment.getSource()); |
| 33 | + if (locale == null) { |
| 34 | + locale = extractLocale(environment.getRoot()); |
| 35 | + if (locale == null) { |
| 36 | + locale = defaultLocale; |
| 37 | + } |
| 38 | + } |
| 39 | + } |
| 40 | + } |
| 41 | + return locale; |
| 42 | + } |
| 43 | + |
| 44 | + private static Locale extractLocale(Object object) { |
| 45 | + if (object != null) { |
| 46 | + if (object instanceof LocaleProvider) { |
| 47 | + return ((LocaleProvider) object).getLocale(); |
| 48 | + } |
| 49 | + return reflectGetLocale(object); |
| 50 | + } |
| 51 | + return null; |
| 52 | + } |
| 53 | + |
| 54 | + private static final Map<Class, Method> METHOD_CACHE = new ConcurrentHashMap<>(); |
| 55 | + private static final Map<Class, Class> FAILED_CLASS_CACHE = new ConcurrentHashMap<>(); |
| 56 | + |
| 57 | + @Internal |
| 58 | + public static void clearMethodCaches() { |
| 59 | + METHOD_CACHE.clear(); |
| 60 | + FAILED_CLASS_CACHE.clear(); |
| 61 | + } |
| 62 | + |
| 63 | + private static Locale reflectGetLocale(Object object) { |
| 64 | + Class<?> clazz = object.getClass(); |
| 65 | + if (FAILED_CLASS_CACHE.containsKey(clazz)) { |
| 66 | + return null; |
| 67 | + } |
| 68 | + try { |
| 69 | + Method getLocaleMethod = METHOD_CACHE.get(clazz); |
| 70 | + if (getLocaleMethod == null) { |
| 71 | + getLocaleMethod = clazz.getMethod("getLocale"); |
| 72 | + if (Locale.class.equals(getLocaleMethod.getReturnType())) { |
| 73 | + METHOD_CACHE.put(clazz, getLocaleMethod); |
| 74 | + } else { |
| 75 | + getLocaleMethod = null; // wat - very tricksy hobbit?? |
| 76 | + } |
| 77 | + } |
| 78 | + if (getLocaleMethod != null) { |
| 79 | + return (Locale) getLocaleMethod.invoke(object); |
| 80 | + } |
| 81 | + |
| 82 | + } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException ignored) { |
| 83 | + } |
| 84 | + FAILED_CLASS_CACHE.put(clazz, clazz); |
| 85 | + return null; |
| 86 | + } |
| 87 | + |
| 88 | + |
| 89 | +} |
0 commit comments