|
27 | 27 | import java.util.AbstractList; |
28 | 28 | import java.util.AbstractMap; |
29 | 29 | import java.util.AbstractSet; |
30 | | -import java.util.Collection; |
31 | 30 | import java.util.Date; |
32 | 31 | import java.util.HashMap; |
33 | 32 | import java.util.Iterator; |
@@ -669,6 +668,37 @@ public V setValue(V value) { |
669 | 668 | }; |
670 | 669 | } |
671 | 670 |
|
| 671 | + /** |
| 672 | + * Returns the properties of a given type. |
| 673 | + * |
| 674 | + * @param type |
| 675 | + * The bean type. |
| 676 | + * |
| 677 | + * @return |
| 678 | + * A map containing the properties of the given type. |
| 679 | + */ |
| 680 | + public static Map<String, Type> getProperties(Class<?> type) { |
| 681 | + Method[] methods = type.getMethods(); |
| 682 | + |
| 683 | + TreeMap<String, Type> properties = new TreeMap<>(); |
| 684 | + |
| 685 | + for (int i = 0; i < methods.length; i++) { |
| 686 | + Method method = methods[i]; |
| 687 | + |
| 688 | + if (method.getDeclaringClass() == Object.class) { |
| 689 | + continue; |
| 690 | + } |
| 691 | + |
| 692 | + String key = getKey(method); |
| 693 | + |
| 694 | + if (key != null) { |
| 695 | + properties.put(key, method.getGenericReturnType()); |
| 696 | + } |
| 697 | + } |
| 698 | + |
| 699 | + return properties; |
| 700 | + } |
| 701 | + |
672 | 702 | /** |
673 | 703 | * Returns the value at a given key path. |
674 | 704 | * |
@@ -706,180 +736,4 @@ public static <V> V valueAt(Object root, String path) { |
706 | 736 |
|
707 | 737 | return (V)value; |
708 | 738 | } |
709 | | - |
710 | | - /** |
711 | | - * Describes a type. Types are encoded as follows: |
712 | | - * |
713 | | - * <ul> |
714 | | - * <li>{@link Object}: "any"</li> |
715 | | - * <li>{@link Void} or <code>void</code>: "void"</li> |
716 | | - * <li>{@link Byte} or <code>byte</code>: "byte"</li> |
717 | | - * <li>{@link Short} or <code>short</code>: "short"</li> |
718 | | - * <li>{@link Integer} or <code>int</code>: "integer"</li> |
719 | | - * <li>{@link Long} or <code>long</code>: "long"</li> |
720 | | - * <li>{@link Float} or <code>float</code>: "float"</li> |
721 | | - * <li>{@link Double} or <code>double</code>: "double"</li> |
722 | | - * <li>Any other {@link Number}: "number"</li> |
723 | | - * <li>{@link CharSequence}: "string"</li> |
724 | | - * <li>{@link Enum}: "enum"</li> |
725 | | - * <li>{@link Date}: "date"</li> |
726 | | - * <li>{@link LocalDate}: "date-local"</li> |
727 | | - * <li>{@link LocalTime}: "time-local"</li> |
728 | | - * <li>{@link LocalDateTime}: "datetime-local"</li> |
729 | | - * <li>{@link URL}: "url"</li> |
730 | | - * <li>{@link Iterable}, {@link Collection}, or {@link List}: "[<i>element type</i>]"</li> |
731 | | - * <li>{@link Map}: "[<i>key type</i>: <i>value type</i>]"</li> |
732 | | - * <li>Any other type: "{property1: <i>property 1 type</i>, property2: <i>property 2 type</i>, ...}"</li> |
733 | | - * </ul> |
734 | | - * |
735 | | - * @param type |
736 | | - * The type to describe. |
737 | | - * |
738 | | - * @param structures |
739 | | - * A map that will be populated with descriptions of all bean types |
740 | | - * referenced by this type. |
741 | | - * |
742 | | - * @return |
743 | | - * The type's description. |
744 | | - */ |
745 | | - public static String describe(Type type, Map<Class<?>, String> structures) { |
746 | | - if (type instanceof Class<?>) { |
747 | | - return describe((Class<?>)type, structures); |
748 | | - } else if (type instanceof WildcardType) { |
749 | | - WildcardType wildcardType = (WildcardType)type; |
750 | | - |
751 | | - return describe(wildcardType.getUpperBounds()[0], structures); |
752 | | - } else if (type instanceof ParameterizedType) { |
753 | | - ParameterizedType parameterizedType = (ParameterizedType)type; |
754 | | - |
755 | | - Type rawType = parameterizedType.getRawType(); |
756 | | - Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); |
757 | | - |
758 | | - if (rawType == Iterable.class || rawType == Collection.class || rawType == List.class) { |
759 | | - return "[" + describe(actualTypeArguments[0], structures) + "]"; |
760 | | - } else if (rawType == Map.class) { |
761 | | - return "[" + describe(actualTypeArguments[0], structures) + ": " + describe(actualTypeArguments[1], structures) + "]"; |
762 | | - } else { |
763 | | - throw new IllegalArgumentException(); |
764 | | - } |
765 | | - } else { |
766 | | - throw new IllegalArgumentException(); |
767 | | - } |
768 | | - } |
769 | | - |
770 | | - private static String describe(Class<?> type, Map<Class<?>, String> structures) { |
771 | | - if (type == Object.class) { |
772 | | - return "any"; |
773 | | - } else if (type == Void.TYPE || type == Void.class) { |
774 | | - return "void"; |
775 | | - } else if (type == Byte.TYPE || type == Byte.class) { |
776 | | - return "byte"; |
777 | | - } else if (type == Short.TYPE || type == Short.class) { |
778 | | - return "short"; |
779 | | - } else if (type == Integer.TYPE || type == Integer.class) { |
780 | | - return "integer"; |
781 | | - } else if (type == Long.TYPE || type == Long.class) { |
782 | | - return "long"; |
783 | | - } else if (type == Float.TYPE || type == Float.class) { |
784 | | - return "float"; |
785 | | - } else if (type == Double.TYPE || type == Double.class) { |
786 | | - return "double"; |
787 | | - } else if (Number.class.isAssignableFrom(type)) { |
788 | | - return "number"; |
789 | | - } else if (type == Boolean.TYPE || type == Boolean.class) { |
790 | | - return "boolean"; |
791 | | - } else if (CharSequence.class.isAssignableFrom(type)) { |
792 | | - return "string"; |
793 | | - } else if (Enum.class.isAssignableFrom(type)) { |
794 | | - return "enum"; |
795 | | - } else if (Date.class.isAssignableFrom(type)) { |
796 | | - return "date"; |
797 | | - } else if (type == LocalDate.class) { |
798 | | - return "date-local"; |
799 | | - } else if (type == LocalTime.class) { |
800 | | - return "time-local"; |
801 | | - } else if (type == LocalDateTime.class) { |
802 | | - return "datetime-local"; |
803 | | - } else if (type == URL.class) { |
804 | | - return "url"; |
805 | | - } else if (Iterable.class.isAssignableFrom(type)) { |
806 | | - return describe(new ParameterizedType() { |
807 | | - @Override |
808 | | - public Type[] getActualTypeArguments() { |
809 | | - return new Type[] {Object.class}; |
810 | | - } |
811 | | - |
812 | | - @Override |
813 | | - public Type getRawType() { |
814 | | - return Iterable.class; |
815 | | - } |
816 | | - |
817 | | - @Override |
818 | | - public Type getOwnerType() { |
819 | | - return null; |
820 | | - } |
821 | | - }, structures); |
822 | | - } else if (Map.class.isAssignableFrom(type)) { |
823 | | - return describe(new ParameterizedType() { |
824 | | - @Override |
825 | | - public Type[] getActualTypeArguments() { |
826 | | - return new Type[] {Object.class, Object.class}; |
827 | | - } |
828 | | - |
829 | | - @Override |
830 | | - public Type getRawType() { |
831 | | - return Map.class; |
832 | | - } |
833 | | - |
834 | | - @Override |
835 | | - public Type getOwnerType() { |
836 | | - return null; |
837 | | - } |
838 | | - }, structures); |
839 | | - } else { |
840 | | - if (!structures.containsKey(type)) { |
841 | | - structures.put(type, null); |
842 | | - |
843 | | - Method[] methods = type.getMethods(); |
844 | | - |
845 | | - TreeMap<String, String> properties = new TreeMap<>(); |
846 | | - |
847 | | - for (int i = 0; i < methods.length; i++) { |
848 | | - Method method = methods[i]; |
849 | | - |
850 | | - if (method.getDeclaringClass() == Object.class) { |
851 | | - continue; |
852 | | - } |
853 | | - |
854 | | - String key = getKey(method); |
855 | | - |
856 | | - if (key != null) { |
857 | | - properties.put(key, describe(method.getGenericReturnType(), structures)); |
858 | | - } |
859 | | - } |
860 | | - |
861 | | - int j = 0; |
862 | | - |
863 | | - StringBuilder descriptionBuilder = new StringBuilder(); |
864 | | - |
865 | | - descriptionBuilder.append("{\n"); |
866 | | - |
867 | | - for (Map.Entry<String, String> entry : properties.entrySet()) { |
868 | | - if (j > 0) { |
869 | | - descriptionBuilder.append(",\n"); |
870 | | - } |
871 | | - |
872 | | - descriptionBuilder.append(" " + entry.getKey() + ": " + entry.getValue()); |
873 | | - |
874 | | - j++; |
875 | | - } |
876 | | - |
877 | | - descriptionBuilder.append("\n}"); |
878 | | - |
879 | | - structures.put(type, descriptionBuilder.toString()); |
880 | | - } |
881 | | - |
882 | | - return type.getSimpleName(); |
883 | | - } |
884 | | - } |
885 | 739 | } |
0 commit comments