Java Code Examples for java.lang.reflect.Method#getGenericParameterTypes()

The following examples show how to use java.lang.reflect.Method#getGenericParameterTypes() . You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example 1
Source File: WildcardTypeTest.java    From j2objc with Apache License 2.0 6 votes vote down vote up
private void checkUpperBoundedParameter(Method method) {
    assertLenghtOne(method.getGenericParameterTypes());
    Type genericParameterType = method.getGenericParameterTypes()[0];
    assertInstanceOf(ParameterizedType.class, genericParameterType);

    ParameterizedType parameterizedType = (ParameterizedType) genericParameterType;
    Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
    assertLenghtOne(actualTypeArguments);
    assertInstanceOf(WildcardType.class, actualTypeArguments[0]);

    WildcardType wildcardType = (WildcardType) actualTypeArguments[0];
    assertEquals("? extends T", wildcardType.toString());
    assertEquals("? extends T", wildcardType.getTypeName());
    assertLenghtZero(wildcardType.getLowerBounds());

    Type[] upperBounds = wildcardType.getUpperBounds();
    assertLenghtOne(upperBounds);
    Type upperBound = upperBounds[0];
    assertEquals(getTypeParameter(method), upperBound);
}
 
Example 2
Source File: ValidMockeryTest.java    From Mockery with Apache License 2.0 6 votes vote down vote up
@Theory
@Test public void When_Call_Legal_Then_Get_Legal(Data data) throws NoSuchMethodException {
  String methodName = data.methodName;

  Method method = Providers.class.getDeclaredMethod(methodName, data.classParam);
  Valid annotation = (Valid) method.getParameterAnnotations()[0][0];
  Type type = method.getGenericParameterTypes()[0];

  Metadata<Valid> metadata = new Metadata<>(Providers.class,
      method, null, annotation, type);

  for (int i = 0; i < 50; i++) {
    Object result = validMockery.legal(metadata);
    assertThat(result, instanceOf(data.classParam));
    validMockery.validate(metadata, result);
  }
}
 
Example 3
Source File: LocalApiProxyFactory.java    From mPaaS with Apache License 2.0 6 votes vote down vote up
/**
 * 构造方法描述信息
 */
private MethodDescriptor buildDescriptor(Class<?> apiClazz,
                                         Method apiMethod, Method ifaceMethod) {
    Class<?> methodClass = apiMethod.getDeclaringClass();
    // 参数的目标是实现类的参数
    Type[] apiTypes = apiMethod.getGenericParameterTypes();
    Type[] ifaceTypes = ifaceMethod.getGenericParameterTypes();
    JavaType[] paramTypes = new JavaType[apiTypes.length];
    for (int i = 0; i < apiTypes.length; i++) {
        paramTypes[i] = toJavaType(ifaceTypes[i], apiTypes[i], methodClass,
                apiClazz);
    }
    // 返回值的目标是接口的返回值
    JavaType returnType = toJavaType(apiMethod.getGenericReturnType(),
            ifaceMethod.getGenericReturnType(),
            ifaceMethod.getDeclaringClass(), apiClazz);
    return new MethodDescriptor(apiMethod, paramTypes, returnType);
}
 
Example 4
Source File: TypeUtilsTest.java    From astor with GNU General Public License v2.0 6 votes vote down vote up
@Test
public void testGetArrayComponentType() throws Exception {
    Method method = getClass().getMethod("dummyMethod", List.class, List.class, List.class,
            List.class, List.class, List.class, List.class, List[].class, List[].class,
            List[].class, List[].class, List[].class, List[].class, List[].class);

    Type[] types = method.getGenericParameterTypes();

    Assert.assertNull(TypeUtils.getArrayComponentType(types[0]));
    Assert.assertNull(TypeUtils.getArrayComponentType(types[1]));
    Assert.assertNull(TypeUtils.getArrayComponentType(types[2]));
    Assert.assertNull(TypeUtils.getArrayComponentType(types[3]));
    Assert.assertNull(TypeUtils.getArrayComponentType(types[4]));
    Assert.assertNull(TypeUtils.getArrayComponentType(types[5]));
    Assert.assertNull(TypeUtils.getArrayComponentType(types[6]));
    Assert.assertEquals(types[0], TypeUtils.getArrayComponentType(types[7]));
    Assert.assertEquals(types[1], TypeUtils.getArrayComponentType(types[8]));
    Assert.assertEquals(types[2], TypeUtils.getArrayComponentType(types[9]));
    Assert.assertEquals(types[3], TypeUtils.getArrayComponentType(types[10]));
    Assert.assertEquals(types[4], TypeUtils.getArrayComponentType(types[11]));
    Assert.assertEquals(types[5], TypeUtils.getArrayComponentType(types[12]));
    Assert.assertEquals(types[6], TypeUtils.getArrayComponentType(types[13]));
}
 
Example 5
Source File: Cloning.java    From AutoLoadCache with Apache License 2.0 6 votes vote down vote up
@Override
public Object[] deepCloneMethodArgs(Method method, Object[] args) throws Exception {
    if (null == args || args.length == 0) {
        return args;
    }
    Type[] genericParameterTypes = method.getGenericParameterTypes();
    if (args.length != genericParameterTypes.length) {
        throw new Exception("the length of " + method.getDeclaringClass().getName() + "." + method.getName()
                + " must " + genericParameterTypes.length);
    }
    Object[] res = new Object[args.length];
    int len = genericParameterTypes.length;
    for (int i = 0; i < len; i++) {
        res[i] = deepClone(args[i], null);
    }
    return res;
}
 
Example 6
Source File: LangUtils.java    From icafe with Eclipse Public License 1.0 5 votes vote down vote up
/**
 * @param m Method we want to probe generic type arguments.
 * @param i the i'th parameter of the method.
 * @return an array of parameterized Types for the i'th argument or an empty array. 
 */
public static Type[] getGenericTypeArguments(Method m, int i) {		 
	 try {
		 Type t = m.getGenericParameterTypes()[i];
	 
		 if(t instanceof ParameterizedType) {
			 ParameterizedType pt = (ParameterizedType) t;
			 return pt.getActualTypeArguments();
		 }
	 } catch(Exception e) {
		 LOGGER.error("Error probing generic type arguments!", e);
     }
	 
	 return new Type[]{};
}
 
Example 7
Source File: FastMathTest.java    From astor with GNU General Public License v2.0 5 votes vote down vote up
private boolean compareClassMethods(Class<?> class1, Class<?> class2){
    boolean allfound = true;
    for(Method method1 : class1.getDeclaredMethods()){
        if (Modifier.isPublic(method1.getModifiers())){
            Type []params = method1.getGenericParameterTypes();
            try {
                class2.getDeclaredMethod(method1.getName(), (Class[]) params);
            } catch (NoSuchMethodException e) {
                allfound = false;
                System.out.println(class2.getSimpleName()+" does not implement: "+method1);
            }
        }
    }
    return allfound;
}
 
Example 8
Source File: ASMHelperTest.java    From cxf with Apache License 2.0 5 votes vote down vote up
@Test
public void testEnumParamType() throws Exception {
    Method method = EnumTest.class.getMethod("test", new Class[] {
        EnumObject.class
    });
    Type[] types = method.getGenericParameterTypes();
    String classCode = ASMHelper.getClassCode(types[0]);
    assertEquals("Lorg/apache/cxf/common/util/ASMHelperTest$EnumObject<Ljava/lang/Enum;>;", classCode);
}
 
Example 9
Source File: Reflector.java    From simplexml with Apache License 2.0 5 votes vote down vote up
/**
 * This is used to acquire the parameterized types from the given
 * methods parameter class at the specified index position. If the
 * parameter class is parameterized this returns the parameters 
 * that have been declared on that class.
 * 
 * @param method this is the method to acquire the parameters from
 * @param index this is the index to acquire the parameter from     
 * 
 * @return this  returns the parameterized types for the method
 */
private static ParameterizedType getParameterType(Method method, int index) {
   Type[] list = method.getGenericParameterTypes();
      
   if(list.length > index) {         
      Type type = list[index];
      
      if(type instanceof ParameterizedType) {
         return (ParameterizedType) type;
      }
   }
   return null;
}
 
Example 10
Source File: GenericMethodsTests.java    From j2objc with Apache License 2.0 5 votes vote down vote up
/**
 * Tests whether the specified method declares a parameter with the
 * type of the type parameter.
 * @param method the method
 */
private void checkParameterType(Method method) {
    TypeVariable<Method> typeParameter = getTypeParameter(method);
    assertLenghtOne(method.getGenericParameterTypes());
    Type genericParameterType = method.getGenericParameterTypes()[0];
    assertEquals(typeParameter, genericParameterType);
    assertInstanceOf(TypeVariable.class, genericParameterType);
    assertEquals(method, ((TypeVariable<?>) genericParameterType).getGenericDeclaration());
}
 
Example 11
Source File: Introspector.java    From jdk8u-jdk with GNU General Public License v2.0 5 votes vote down vote up
/**
 * Adds the property descriptor to the list store.
 */
private void addPropertyDescriptor(PropertyDescriptor pd) {
    String propName = pd.getName();
    List<PropertyDescriptor> list = pdStore.get(propName);
    if (list == null) {
        list = new ArrayList<>();
        pdStore.put(propName, list);
    }
    if (this.beanClass != pd.getClass0()) {
        // replace existing property descriptor
        // only if we have types to resolve
        // in the context of this.beanClass
        Method read = pd.getReadMethod();
        Method write = pd.getWriteMethod();
        boolean cls = true;
        if (read != null) cls = cls && read.getGenericReturnType() instanceof Class;
        if (write != null) cls = cls && write.getGenericParameterTypes()[0] instanceof Class;
        if (pd instanceof IndexedPropertyDescriptor) {
            IndexedPropertyDescriptor ipd = (IndexedPropertyDescriptor) pd;
            Method readI = ipd.getIndexedReadMethod();
            Method writeI = ipd.getIndexedWriteMethod();
            if (readI != null) cls = cls && readI.getGenericReturnType() instanceof Class;
            if (writeI != null) cls = cls && writeI.getGenericParameterTypes()[1] instanceof Class;
            if (!cls) {
                pd = new IndexedPropertyDescriptor(ipd);
                pd.updateGenericsFor(this.beanClass);
            }
        }
        else if (!cls) {
            pd = new PropertyDescriptor(pd);
            pd.updateGenericsFor(this.beanClass);
        }
    }
    list.add(pd);
}
 
Example 12
Source File: MethodCoercions.java    From brooklyn-server with Apache License 2.0 5 votes vote down vote up
/**
 * Tries to find a single-parameter method with a parameter compatible with (can be coerced to) the argument, and
 * invokes it.
 *
 * @param instance the object to invoke the method on
 * @param methodName the name of the method to invoke
 * @param argument the argument to the method's parameter.
 * @return the result of the method call, or {@link org.apache.brooklyn.util.guava.Maybe#absent()} if method could not be matched.
 */
public static Maybe<?> tryFindAndInvokeSingleParameterMethod(final Object instance, final String methodName, final Object argument) {
    Class<?> clazz = instance.getClass();
    Iterable<Method> methods = Arrays.asList(clazz.getMethods());
    Optional<Method> matchingMethod = Iterables.tryFind(methods, matchSingleParameterMethod(methodName, argument));
    if (matchingMethod.isPresent()) {
        Method method = matchingMethod.get();
        Method accessibleMethod = Reflections.findAccessibleMethod(method).get();
        try {
            Type paramType = method.getGenericParameterTypes()[0];
            Maybe<?> coercedArgumentM = TypeCoercions.tryCoerce(argument, TypeToken.of(paramType));
            RuntimeException exception = Maybe.getException(coercedArgumentM);
            if (coercedArgumentM.isPresent() && coercedArgumentM.get()!=null) {
                if (!Boxing.boxedTypeToken(paramType).getRawType().isAssignableFrom(coercedArgumentM.get().getClass())) {
                    exception = new IllegalArgumentException("Type mismatch after coercion; "+coercedArgumentM.get()+" is not a "+TypeToken.of(paramType));
                }
            }
            if (coercedArgumentM.isAbsent() || exception!=null) {
                return Maybe.absent("Cannot convert parameter for "+method+": "+
                    Exceptions.collapseText(Maybe.getException(coercedArgumentM)), exception);
            }
            return Maybe.of(accessibleMethod.invoke(instance, coercedArgumentM.get()));
        } catch (IllegalAccessException | InvocationTargetException e) {
            throw Exceptions.propagate(e);
        }
    } else {
        return Maybe.absent("No method matching '"+methodName+"("+(argument==null ? argument : argument.getClass().getName())+")'");
    }
}
 
Example 13
Source File: ReactiveMethodSupport.java    From alibaba-rsocket-broker with Apache License 2.0 5 votes vote down vote up
public ReactiveMethodSupport(Method method) {
    this.method = method;
    this.paramCount = method.getParameterCount();
    //result type with generic type
    this.returnType = method.getReturnType();
    this.inferredClassForReturn = parseInferredClass(method.getGenericReturnType());
    //kotlin validation
    if (paramCount > 0) {
        Type[] parameterTypes = method.getGenericParameterTypes();
        Type lastParamType = parameterTypes[paramCount - 1];
        if (lastParamType.getTypeName().startsWith("kotlin.coroutines.Continuation<")) {
            this.kotlinSuspend = true;
            if (lastParamType.getTypeName().contains("kotlin.Unit>")) {
                this.inferredClassForReturn = Void.TYPE;
            } else {
                this.inferredClassForReturn = parseInferredClass(lastParamType);
            }
        }
        this.lastParamType = method.getParameterTypes()[paramCount - 1];
    }
    //reactive adapter for return type
    if (this.isKotlinSuspend()) {
        this.reactiveAdapter = ReactiveAdapterKotlin.getInstance();
    } else {
        this.reactiveAdapter = ReactiveAdapter.findAdapter(returnType.getCanonicalName());
    }
}
 
Example 14
Source File: Introspector.java    From openjdk-jdk9 with GNU General Public License v2.0 5 votes vote down vote up
private boolean isEventHandler(Method m) {
    // We assume that a method is an event handler if it has a single
    // argument, whose type inherit from java.util.Event.
    Type argTypes[] = m.getGenericParameterTypes();
    if (argTypes.length != 1) {
        return false;
    }
    return isSubclass(TypeResolver.erase(TypeResolver.resolveInClass(beanClass, argTypes[0])), EventObject.class);
}
 
Example 15
Source File: GenericsUtils.java    From document-management-software with GNU Lesser General Public License v3.0 4 votes vote down vote up
public static Class<?> getMethodGenericParameterTypes(Method method, int paramIndex) {
	Class<?> literalType = method.getParameterTypes()[paramIndex];
	Type genericType = method.getGenericParameterTypes()[paramIndex];
	return chooseOneType(literalType, genericType);
}
 
Example 16
Source File: MethodPane.java    From attic-polygene-java with Apache License 2.0 4 votes vote down vote up
private void reload( CompositeMethodDetailDescriptor descriptor )
{
    Method method = descriptor.descriptor().method();

    clear();

    // mixin type
    rows.add( new TableRow( 2, "return", Classes.simpleGenericNameOf( method.getGenericReturnType() ) ) );

    // method
    StringBuilder parameters = new StringBuilder();
    for( int idx = 0; idx < method.getGenericParameterTypes().length; idx++ )
    {
        Type type = method.getGenericParameterTypes()[idx];
        Annotation[] annotations = method.getParameterAnnotations()[idx];

        if( parameters.length() > 0 )
        {
            parameters.append( ", " );
        }

        for( Annotation annotation : annotations )
        {
            String ann = annotation.toString();
            ann = "@" + ann.substring( ann.lastIndexOf( '.' ) + 1 );
            parameters.append( ann ).append( " " );
        }

        parameters.append( Classes.simpleGenericNameOf( type ) );
    }

    rows.add( new TableRow( 2, "parameters", parameters.toString() ) );

    // concern
    boolean first = true;
    for( MethodConcernDetailDescriptor concern : descriptor.concerns().concerns() )
    {
        if( first )
        {
            rows.add( new TableRow( 2, "concern", concern.descriptor().modifierClass().getSimpleName() ) );
            first = false;
        }
        else
        {
            rows.add( new TableRow( 2, "", concern.descriptor().modifierClass().getSimpleName() ) );
        }
    }

    // sideEffect
    first = false;
    for( MethodSideEffectDetailDescriptor sideEffect : descriptor.sideEffects().sideEffects() )
    {
        if( first )
        {
            rows.add( new TableRow( 2, "sideEffect", sideEffect.descriptor().modifierClass().getSimpleName() ) );
            first = false;
        }
        else
        {
            rows.add( new TableRow( 2, "", sideEffect.descriptor().modifierClass().getSimpleName() ) );
        }
    }

    fireTableDataChanged();
}
 
Example 17
Source File: PipelineOptionsFactory.java    From beam with Apache License 2.0 4 votes vote down vote up
/**
 * This method is meant to emulate the behavior of {@link Introspector#getBeanInfo(Class, int)} to
 * construct the list of {@link PropertyDescriptor}.
 *
 * <p>TODO: Swap back to using Introspector once the proxy class issue with AppEngine is resolved.
 */
private static List<PropertyDescriptor> getPropertyDescriptors(
    Set<Method> methods, Class<? extends PipelineOptions> beanClass)
    throws IntrospectionException {
  SortedMap<String, Method> propertyNamesToGetters = new TreeMap<>();
  for (Map.Entry<String, Method> entry :
      PipelineOptionsReflector.getPropertyNamesToGetters(methods).entries()) {
    propertyNamesToGetters.put(entry.getKey(), entry.getValue());
  }

  List<PropertyDescriptor> descriptors = Lists.newArrayList();
  List<TypeMismatch> mismatches = new ArrayList<>();
  Set<String> usedDescriptors = Sets.newHashSet();
  /*
   * Add all the getter/setter pairs to the list of descriptors removing the getter once
   * it has been paired up.
   */
  for (Method method : methods) {
    String methodName = method.getName();
    if (!methodName.startsWith("set")
        || method.getParameterTypes().length != 1
        || method.getReturnType() != void.class) {
      continue;
    }
    String propertyName = Introspector.decapitalize(methodName.substring(3));
    Method getterMethod = propertyNamesToGetters.remove(propertyName);

    // Validate that the getter and setter property types are the same.
    if (getterMethod != null) {
      Type getterPropertyType = getterMethod.getGenericReturnType();
      Type setterPropertyType = method.getGenericParameterTypes()[0];
      if (!getterPropertyType.equals(setterPropertyType)) {
        TypeMismatch mismatch = new TypeMismatch();
        mismatch.propertyName = propertyName;
        mismatch.getterPropertyType = getterPropertyType;
        mismatch.setterPropertyType = setterPropertyType;
        mismatches.add(mismatch);
        continue;
      }
    }
    // Properties can appear multiple times with subclasses, and we don't
    // want to add a bad entry if we have already added a good one (with both
    // getter and setter).
    if (!usedDescriptors.contains(propertyName)) {
      descriptors.add(new PropertyDescriptor(propertyName, getterMethod, method));
      usedDescriptors.add(propertyName);
    }
  }
  throwForTypeMismatches(mismatches);

  // Add the remaining getters with missing setters.
  for (Map.Entry<String, Method> getterToMethod : propertyNamesToGetters.entrySet()) {
    descriptors.add(
        new PropertyDescriptor(getterToMethod.getKey(), getterToMethod.getValue(), null));
  }
  return descriptors;
}
 
Example 18
Source File: FastMathStrictComparisonTest.java    From astor with GNU General Public License v2.0 4 votes vote down vote up
@Parameters
    public static List<Object[]> data() throws Exception {
        String singleMethod = System.getProperty("testMethod");
        List<Object[]> list = new ArrayList<Object[]>();
        for(Method mathMethod : StrictMath.class.getDeclaredMethods()) {
            method:
            if (Modifier.isPublic(mathMethod.getModifiers())){// Only test public methods
                Type []types = mathMethod.getGenericParameterTypes();
                if (types.length >=1) { // Only check methods with at least one parameter
                    try {
                        // Get the corresponding FastMath method
                        Method fastMethod = FastMath.class.getDeclaredMethod(mathMethod.getName(), (Class[]) types);
                        if (Modifier.isPublic(fastMethod.getModifiers())) { // It must be public too
                            if (singleMethod != null && !fastMethod.getName().equals(singleMethod)) {
                                break method;
                            }
                            Object [][] values = new Object[types.length][];
                            int index = 0;
                            for(Type t : types) {
                                if (t.equals(double.class)){
                                    values[index]=DOUBLE_SPECIAL_VALUES;
                                } else if (t.equals(float.class)) {
                                    values[index]=FLOAT_SPECIAL_VALUES;
                                } else if (t.equals(long.class)) {
                                    values[index]=LONG_SPECIAL_VALUES;
                                } else if (t.equals(int.class)) {
                                    values[index]=INT_SPECIAL_VALUES;
                                } else {
                                    System.out.println("Cannot handle class "+t+" for "+mathMethod);
                                    break method;
                                }
                                index++;
                            }
//                            System.out.println(fastMethod);
                            /*
                             * The current implementation runs each method as a separate test.
                             * Could be amended to run each value as a separate test
                             */
                            list.add(new Object[]{mathMethod, fastMethod, types, values});
//                            setupMethodCall(mathMethod, fastMethod, params, data);
                        } else {
                            System.out.println("Cannot find public FastMath method corresponding to: "+mathMethod);
                        }
                    } catch (NoSuchMethodException e) {
                        System.out.println("Cannot find FastMath method corresponding to: "+mathMethod);
                    }
                }
            }
        }
        return list;
    }
 
Example 19
Source File: TriggerProcessParameterIT.java    From development with Apache License 2.0 4 votes vote down vote up
private String doCompare(List<Object> parents, Object first, Object second)
        throws Exception {
    String result = "";

    for (Method m : first.getClass().getMethods()) {
        if ((!m.getName().startsWith("get")
                && !m.getName().startsWith("is"))
                || "getClass".equals(m.getName())
                || m.getGenericParameterTypes().length > 0) {
            continue;
        }
        Object firstObj = m.invoke(first, (Object[]) null);
        Object secondObj = second.getClass()
                .getMethod(m.getName(), (Class[]) null)
                .invoke(second, (Object[]) null);
        if (firstObj instanceof BaseVO && secondObj instanceof BaseVO) {
            if (!parents.contains(firstObj)) {
                parents.add(first);
                result += doCompare(firstObj, secondObj);
                parents.remove(first);
            }
        } else if (firstObj instanceof List<?>
                && secondObj instanceof List<?>) {
            List<?> firstList = (List<?>) firstObj;
            List<?> secondList = (List<?>) secondObj;
            for (int i = 0; i < firstList.size(); i++) {
                if (!parents.contains(firstList.get(i))) {
                    parents.add(first);
                    result += doCompare(parents, firstList.get(i),
                            secondList.get(i));
                    parents.remove(first);
                }
            }
        } else if (firstObj != null || secondObj != null) {
            if (firstObj == null || !firstObj.equals(secondObj)) {
                result = result + m.getName() + ": (" + firstObj + ") <-> ("
                        + secondObj + ")\n";
            }
        }
    }
    return result;
}
 
Example 20
Source File: InjectionUtil.java    From camunda-bpm-platform with Apache License 2.0 4 votes vote down vote up
public static Object[] resolveInjections(DeploymentOperation operationContext, Method lifecycleMethod) {

    final Type[] parameterTypes = lifecycleMethod.getGenericParameterTypes();
    final List<Object> parameters = new ArrayList<Object>();

    for (Type parameterType : parameterTypes) {

      boolean injectionResolved = false;

      if(parameterType instanceof Class) {

        Class<?> parameterClass = (Class<?>)parameterType;

        // support injection of the default process engine
        if(ProcessEngine.class.isAssignableFrom(parameterClass)) {
          parameters.add(getDefaultProcessEngine(operationContext));
          injectionResolved = true;
        }

        // support injection of the ProcessApplicationInfo
        else if(ProcessApplicationInfo.class.isAssignableFrom(parameterClass)) {
          parameters.add(getProcessApplicationInfo(operationContext));
          injectionResolved = true;
        }

      } else if(parameterType instanceof ParameterizedType) {

        ParameterizedType parameterizedType = (ParameterizedType) parameterType;
        Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();

        // support injection of List<ProcessEngine>
        if(actualTypeArguments.length==1 && ProcessEngine.class.isAssignableFrom((Class<?>) actualTypeArguments[0])) {
          parameters.add(getProcessEngines(operationContext));
          injectionResolved = true;
        }
      }

      if(!injectionResolved) {
        throw LOG.unsuppoertedParameterType(parameterType);
      }

    }

    return parameters.toArray();
  }