BeanAdapter extends AbstractMap<String, Object> { public static String describe(Type type, Map<Class<?>, String> structures) { if (type instanceof Class<?>) { return describe((Class<?>)type, structures); } else if (type instanceof WildcardType) { WildcardType wildcardType = (WildcardType)type; return describe(wildcardType.getUpperBounds()[0], structures); } else if (type instanceof ParameterizedType) { ParameterizedType parameterizedType = (ParameterizedType)type; Type rawType = parameterizedType.getRawType(); Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); if (rawType == Iterable.class || rawType == Collection.class || rawType == List.class) { return "[" + describe(actualTypeArguments[0], structures) + "]"; } else if (rawType == Map.class) { return "[" + describe(actualTypeArguments[0], structures) + ": " + describe(actualTypeArguments[1], structures) + "]"; } else { throw new IllegalArgumentException(); } } else { throw new IllegalArgumentException(); } } BeanAdapter(Object bean); private  BeanAdapter(Object bean, HashMap<Class<?>, HashMap<String, Method>> accessorCache); @Override Object get(Object key); @Override Set<Entry<String, Object>> entrySet(); @SuppressWarnings("unchecked") static T adapt(Object value); @SuppressWarnings("unchecked") static T adapt(Object value, Type type); static List<E> adaptList(List<?> list, Type elementType); static Map<K, V> adaptMap(Map<K, ?> map, Type valueType); @SuppressWarnings("unchecked") static V valueAt(Object root, String path); static String describe(Type type, Map<Class<?>, String> structures);  }
@Test public void testDescribe() { HashMap<Class<?>, String> structures = new HashMap<>(); BeanAdapter.describe(TestBean.class, structures); assertEquals( "{\n" + " URL: url,\n" + " bigInteger: number,\n" + " date: date,\n" + " dayOfWeek: enum,\n" + " double: double,\n" + " i: integer,\n" + " list: [any],\n" + " localDate: date-local,\n" + " localDateTime: datetime-local,\n" + " localTime: time-local,\n" + " long: long,\n" + " map: [string: any],\n" + " nestedBean: NestedBean,\n" + " nestedBeanList: [NestedBean],\n" + " nestedBeanMap: [string: NestedBean],\n" + " string: string,\n" + " testArrayList: [any],\n" + " testHashMap: [any: any]\n" + "}", structures.get(TestBean.class) ); assertEquals( "{\n" + " flag: boolean\n" + "}", structures.get(TestBean.NestedBean.class) ); }