@Override @Nullable public TypeDescriptor nested(int level) { return TypeDescriptor.nested(property(this.pd), level); }
@Override @Nullable public TypeDescriptor nested(int level) { return TypeDescriptor.nested(this.field, level); }
@Override @Nullable public TypeDescriptor nested(int level) { return TypeDescriptor.nested(property(this.pd), level); }
@Override @Nullable public TypeDescriptor nested(int level) { return TypeDescriptor.nested(this.field, level); }
/** * Create a type descriptor for a nested type declared within the field. * <p>For example, if the field is a {@code List<String>} and the nesting * level is 1, the nested type descriptor will be {@code String.class}. * <p>If the field is a {@code List<List<String>>} and the nesting level is * 2, the nested type descriptor will also be a {@code String.class}. * <p>If the field is a {@code Map<Integer, String>} and the nesting level * is 1, the nested type descriptor will be String, derived from the map value. * <p>If the field is a {@code List<Map<Integer, String>>} and the nesting * level is 2, the nested type descriptor will be String, derived from the map value. * <p>Returns {@code null} if a nested type cannot be obtained because it was not * declared. For example, if the field is a {@code List<?>}, the nested type * descriptor returned will be {@code null}. * @param field the field * @param nestingLevel the nesting level of the collection/array element or * map key/value declaration within the field * @return the nested type descriptor at the specified nesting level, * or {@code null} if it could not be obtained * @throws IllegalArgumentException if the types up to the specified nesting * level are not of collection, array, or map types */ @Nullable public static TypeDescriptor nested(Field field, int nestingLevel) { return nested(new TypeDescriptor(field), nestingLevel); }
/** * Create a type descriptor for a nested type declared within the property. * <p>For example, if the property is a {@code List<String>} and the nesting * level is 1, the nested type descriptor will be {@code String.class}. * <p>If the property is a {@code List<List<String>>} and the nesting level * is 2, the nested type descriptor will also be a {@code String.class}. * <p>If the property is a {@code Map<Integer, String>} and the nesting level * is 1, the nested type descriptor will be String, derived from the map value. * <p>If the property is a {@code List<Map<Integer, String>>} and the nesting * level is 2, the nested type descriptor will be String, derived from the map value. * <p>Returns {@code null} if a nested type cannot be obtained because it was not * declared. For example, if the property is a {@code List<?>}, the nested type * descriptor returned will be {@code null}. * @param property the property * @param nestingLevel the nesting level of the collection/array element or * map key/value declaration within the property * @return the nested type descriptor at the specified nesting level, or * {@code null} if it could not be obtained * @throws IllegalArgumentException if the types up to the specified nesting * level are not of collection, array, or map types */ @Nullable public static TypeDescriptor nested(Property property, int nestingLevel) { return nested(new TypeDescriptor(property), nestingLevel); }
/** * Create a type descriptor for a nested type declared within the method parameter. * <p>For example, if the methodParameter is a {@code List<String>} and the * nesting level is 1, the nested type descriptor will be String.class. * <p>If the methodParameter is a {@code List<List<String>>} and the nesting * level is 2, the nested type descriptor will also be a String.class. * <p>If the methodParameter is a {@code Map<Integer, String>} and the nesting * level is 1, the nested type descriptor will be String, derived from the map value. * <p>If the methodParameter is a {@code List<Map<Integer, String>>} and the * nesting level is 2, the nested type descriptor will be String, derived from the map value. * <p>Returns {@code null} if a nested type cannot be obtained because it was not declared. * For example, if the method parameter is a {@code List<?>}, the nested type * descriptor returned will be {@code null}. * @param methodParameter the method parameter with a nestingLevel of 1 * @param nestingLevel the nesting level of the collection/array element or * map key/value declaration within the method parameter * @return the nested type descriptor at the specified nesting level, * or {@code null} if it could not be obtained * @throws IllegalArgumentException if the nesting level of the input * {@link MethodParameter} argument is not 1, or if the types up to the * specified nesting level are not of collection, array, or map types */ @Nullable public static TypeDescriptor nested(MethodParameter methodParameter, int nestingLevel) { if (methodParameter.getNestingLevel() != 1) { throw new IllegalArgumentException("MethodParameter nesting level must be 1: " + "use the nestingLevel parameter to specify the desired nestingLevel for nested type traversal"); } return nested(new TypeDescriptor(methodParameter), nestingLevel); }
@Test(expected = IllegalArgumentException.class) public void nestedMethodParameterNot1NestedLevel() throws Exception { TypeDescriptor.nested(new MethodParameter(getClass().getMethod("test4", List.class), 0, 2), 2); }
@Test(expected = IllegalArgumentException.class) public void nestedMethodParameterTypeInvalidNestingLevel() throws Exception { TypeDescriptor.nested(new MethodParameter(getClass().getMethod("test5", String.class), 0, 2), 2); }
@Test public void nestedPropertyTypeMapTwoLevels() throws Exception { Property property = new Property(getClass(), getClass().getMethod("getTest4"), getClass().getMethod("setTest4", List.class)); TypeDescriptor t1 = TypeDescriptor.nested(property, 2); assertEquals(String.class, t1.getType()); }
@Test public void nestedTooManyLevels() throws Exception { TypeDescriptor t1 = TypeDescriptor.nested(new MethodParameter(getClass().getMethod("test4", List.class), 0), 3); assertNull(t1); }
@Test public void nestedMethodParameterTypeNotNestable() throws Exception { TypeDescriptor t1 = TypeDescriptor.nested(new MethodParameter(getClass().getMethod("test5", String.class), 0), 2); assertNull(t1); }
@Test public void nestedFieldTypeMapTwoLevels() throws Exception { TypeDescriptor t1 = TypeDescriptor.nested(getClass().getField("test4"), 2); assertEquals(String.class, t1.getType()); }
@Test public void nestedMethodParameterType2Levels() throws Exception { TypeDescriptor t1 = TypeDescriptor.nested(new MethodParameter(getClass().getMethod("test2", List.class), 0), 2); assertEquals(String.class, t1.getType()); }
@Test public void nestedMethodParameterTypeMap() throws Exception { TypeDescriptor t1 = TypeDescriptor.nested(new MethodParameter(getClass().getMethod("test3", Map.class), 0), 1); assertEquals(String.class, t1.getType()); }
@Test public void nestedNotParameterized() throws Exception { TypeDescriptor t1 = TypeDescriptor.nested(new MethodParameter(getClass().getMethod("test6", List.class), 0), 1); assertEquals(List.class,t1.getType()); assertEquals("java.util.List<?>", t1.toString()); TypeDescriptor t2 = TypeDescriptor.nested(new MethodParameter(getClass().getMethod("test6", List.class), 0), 2); assertNull(t2); }
@Test public void nestedMethodParameterTypeMapTwoLevels() throws Exception { TypeDescriptor t1 = TypeDescriptor.nested(new MethodParameter(getClass().getMethod("test4", List.class), 0), 2); assertEquals(String.class, t1.getType()); }
@Override public void contributeMethodArgument(MethodParameter parameter, @Nullable Object value, UriComponentsBuilder builder, Map<String, Object> uriVariables, ConversionService conversionService) { Class<?> paramType = parameter.getNestedParameterType(); if (Map.class.isAssignableFrom(paramType) || MultipartFile.class == paramType || Part.class == paramType) { return; } RequestParam requestParam = parameter.getParameterAnnotation(RequestParam.class); String name = (requestParam == null || StringUtils.isEmpty(requestParam.name()) ? parameter.getParameterName() : requestParam.name()); Assert.state(name != null, "Unresolvable parameter name"); if (value == null) { if (requestParam != null && (!requestParam.required() || !requestParam.defaultValue().equals(ValueConstants.DEFAULT_NONE))) { return; } builder.queryParam(name); } else if (value instanceof Collection) { for (Object element : (Collection<?>) value) { element = formatUriValue(conversionService, TypeDescriptor.nested(parameter, 1), element); builder.queryParam(name, element); } } else { builder.queryParam(name, formatUriValue(conversionService, new TypeDescriptor(parameter), value)); } }
@Test public void parameterList() throws Exception { MethodParameter methodParameter = new MethodParameter(getClass().getMethod("testParameterList", List.class), 0); TypeDescriptor desc = new TypeDescriptor(methodParameter); assertEquals(List.class, desc.getType()); assertEquals(List.class, desc.getObjectType()); assertEquals("java.util.List", desc.getName()); assertEquals("java.util.List<java.util.List<java.util.Map<java.lang.Integer, java.lang.Enum<?>>>>", desc.toString()); assertTrue(!desc.isPrimitive()); assertEquals(0, desc.getAnnotations().length); assertTrue(desc.isCollection()); assertFalse(desc.isArray()); assertEquals(List.class, desc.getElementTypeDescriptor().getType()); assertEquals(TypeDescriptor.nested(methodParameter, 1), desc.getElementTypeDescriptor()); assertEquals(TypeDescriptor.nested(methodParameter, 2), desc.getElementTypeDescriptor().getElementTypeDescriptor()); assertEquals(TypeDescriptor.nested(methodParameter, 3), desc.getElementTypeDescriptor().getElementTypeDescriptor().getMapValueTypeDescriptor()); assertEquals(Integer.class, desc.getElementTypeDescriptor().getElementTypeDescriptor().getMapKeyTypeDescriptor().getType()); assertEquals(Enum.class, desc.getElementTypeDescriptor().getElementTypeDescriptor().getMapValueTypeDescriptor().getType()); assertFalse(desc.isMap()); }
@Test public void parameterMap() throws Exception { MethodParameter methodParameter = new MethodParameter(getClass().getMethod("testParameterMap", Map.class), 0); TypeDescriptor desc = new TypeDescriptor(methodParameter); assertEquals(Map.class, desc.getType()); assertEquals(Map.class, desc.getObjectType()); assertEquals("java.util.Map", desc.getName()); assertEquals("java.util.Map<java.lang.Integer, java.util.List<java.lang.String>>", desc.toString()); assertTrue(!desc.isPrimitive()); assertEquals(0, desc.getAnnotations().length); assertFalse(desc.isCollection()); assertFalse(desc.isArray()); assertTrue(desc.isMap()); assertEquals(TypeDescriptor.nested(methodParameter, 1), desc.getMapValueTypeDescriptor()); assertEquals(TypeDescriptor.nested(methodParameter, 2), desc.getMapValueTypeDescriptor().getElementTypeDescriptor()); assertEquals(Integer.class, desc.getMapKeyTypeDescriptor().getType()); assertEquals(List.class, desc.getMapValueTypeDescriptor().getType()); assertEquals(String.class, desc.getMapValueTypeDescriptor().getElementTypeDescriptor().getType()); }