/* * Copyright (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.com * The software in this package is published under the terms of the CPAL v1.0 * license, a copy of which has been included with this distribution in the * LICENSE.txt file. */ package org.mule.runtime.module.extension.internal.util; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertNotNull; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.instanceOf; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.notNullValue; import static org.hamcrest.Matchers.empty; import static org.junit.Assert.assertThat; import static org.mule.metadata.api.model.MetadataFormat.JAVA; import static org.mule.runtime.module.extension.internal.util.IntrospectionUtils.getExposedFields; import static org.mule.runtime.module.extension.internal.util.IntrospectionUtils.getFieldMetadataType; import static org.mule.runtime.module.extension.internal.util.IntrospectionUtils.getFieldsWithGetters; import static org.mule.runtime.module.extension.internal.util.IntrospectionUtils.toDataType; import static org.mule.runtime.module.extension.internal.util.IntrospectionUtils.unwrapGenericFromClass; import static org.mule.test.module.extension.internal.util.ExtensionsTestUtils.TYPE_LOADER; import static org.mule.test.module.extension.internal.util.ExtensionsTestUtils.arrayOf; import static org.mule.test.module.extension.internal.util.ExtensionsTestUtils.assertMessageType; import static org.mule.test.module.extension.internal.util.ExtensionsTestUtils.dictionaryOf; import static org.mule.test.module.extension.internal.util.ExtensionsTestUtils.objectTypeBuilder; import static org.springframework.core.ResolvableType.forType; import org.mule.metadata.api.builder.ArrayTypeBuilder; import org.mule.metadata.api.builder.BaseTypeBuilder; import org.mule.metadata.api.builder.ObjectTypeBuilder; import org.mule.metadata.api.model.ArrayType; import org.mule.metadata.api.model.MetadataType; import org.mule.metadata.api.model.ObjectType; import org.mule.metadata.api.model.StringType; import org.mule.metadata.api.model.VoidType; import org.mule.metadata.java.api.utils.JavaTypeUtils; import org.mule.runtime.api.message.Attributes; import org.mule.runtime.api.metadata.CollectionDataType; import org.mule.runtime.api.metadata.DataType; import org.mule.runtime.api.metadata.MapDataType; import org.mule.runtime.core.util.CollectionUtils; import org.mule.runtime.extension.api.runtime.operation.Result; import org.mule.runtime.extension.api.runtime.streaming.PagingProvider; import org.mule.tck.junit4.AbstractMuleTestCase; import org.mule.tck.size.SmallTest; import org.mule.tck.testmodels.fruit.Apple; import org.mule.tck.testmodels.fruit.Banana; import org.mule.tck.testmodels.fruit.Fruit; import org.mule.tck.testmodels.fruit.FruitBasket; import org.mule.tck.testmodels.fruit.FruitBox; import org.mule.tck.testmodels.fruit.Kiwi; import org.mule.test.petstore.extension.PhoneNumber; import org.junit.Test; import org.springframework.core.ResolvableType; import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; @SmallTest public class IntrospectionUtilsTestCase extends AbstractMuleTestCase { public static final String OPERATION_RESULT = "operationResult"; public static final String PAGING_PROVIDER = "pagingProvider"; public static final String PAGING_PROVIDER_OPERATION_RESULT = "pagingProviderOperationResult"; public static final String FOO = "foo"; private List<FruitBasket> baskets; @Test public void getMethodReturnType() throws Exception { MetadataType metadataType = IntrospectionUtils.getMethodReturnType(getMethod(FOO), TYPE_LOADER); assertDictionary(metadataType, Apple.class); } @Test public void getOperationResultReturnType() throws Exception { assertReturnType(OPERATION_RESULT); assertAttributesType(OPERATION_RESULT); } @Test public void getPagingProviderReturnType() throws Exception { assertPagingProviderReturnType(PAGING_PROVIDER); assertVoidAttributesType(PAGING_PROVIDER); } @Test public void getPagingProviderOperationResultReturnType() throws Exception { assertPagingProviderReturnResultType((PAGING_PROVIDER_OPERATION_RESULT)); assertVoidAttributesType(PAGING_PROVIDER_OPERATION_RESULT); } @Test(expected = IllegalArgumentException.class) public void getNullMethodReturnType() throws Exception { IntrospectionUtils.getMethodReturnType(null, TYPE_LOADER); } @Test public void getArgumentlessMethodArgumentTypes() throws Exception { MetadataType[] types = IntrospectionUtils.getMethodArgumentTypes(getMethod(FOO), TYPE_LOADER); assertNotNull(types); assertEquals(0, types.length); } @Test public void getMethodArgumentTypes() throws Exception { MetadataType[] types = IntrospectionUtils .getMethodArgumentTypes(getMethod("bar", String.class, Long.class, Apple.class, Map.class), TYPE_LOADER); assertNotNull(types); assertEquals(4, types.length); assertType(types[0], String.class); assertType(types[1], Long.class); assertType(types[2], Apple.class); assertDictionary(types[3], Kiwi.class); } @Test(expected = IllegalArgumentException.class) public void getNullMethodArgumentTypes() throws Exception { IntrospectionUtils.getMethodArgumentTypes(null, TYPE_LOADER); } @Test public void getFieldDataType() throws Exception { MetadataType type = getFieldMetadataType(getClass().getDeclaredField("baskets"), TYPE_LOADER); assertList(type, FruitBasket.class); } @Test(expected = IllegalArgumentException.class) public void getNullFieldDataType() throws Exception { getFieldMetadataType(null, TYPE_LOADER); } @Test public void getEmptyExposedPojoFields() { Collection<Field> exposedFields = getExposedFields(FruitBasket.class); assertThat(exposedFields, is(empty())); } @Test public void getFieldsWithGettersOnly() { Collection<Field> fieldsWithGetters = getFieldsWithGetters(PhoneNumber.class); assertThat(fieldsWithGetters.size(), is(4)); } @Test public void getWildCardFieldsDataTypes() { Collection<Field> exposedFields = getFieldsWithGetters(FruitBox.class); assertNotNull(exposedFields); assertEquals(6, exposedFields.size()); assertField("fruitLikeList", arrayOf(List.class, objectTypeBuilder(Fruit.class)), exposedFields); assertField("wildCardList", arrayOf(List.class, objectTypeBuilder(Object.class)), exposedFields); assertField("rawList", arrayOf(List.class, objectTypeBuilder(Object.class)), exposedFields); assertField("wildCardMap", dictionaryOf(Map.class, objectTypeBuilder(Object.class)), exposedFields); assertField("rawMap", dictionaryOf(Map.class, objectTypeBuilder(Object.class)), exposedFields); assertField("fruitLikeMap", dictionaryOf(Map.class, objectTypeBuilder(Fruit.class)), exposedFields); } @Test public void unwrapPagingProviderGenericFromParentClass() { ResolvableType type = unwrapGenericFromClass(PagingProvider.class, forType(TestPagingProvider.class), 1); assertThat(type.getRawClass(), equalTo(Banana.class)); } @Test public void getDataTypeFromList() { Class<List> listClass = List.class; Class<Integer> integerClass = Integer.class; ArrayTypeBuilder arrayTypeBuilder = BaseTypeBuilder.create(JAVA) .arrayType() .id(listClass.getName()); arrayTypeBuilder.of().numberType().id(Integer.class.getName()); CollectionDataType dataType = (CollectionDataType) toDataType(arrayTypeBuilder.build()); assertThat(dataType.getType(), is(equalTo(listClass))); assertThat(dataType.getItemDataType().getType(), is(equalTo(integerClass))); } @Test public void getDataTypeFromMap() { Class<Date> dateClass = Date.class; Class<Map> mapClass = Map.class; ObjectTypeBuilder objectTypeBuilder = BaseTypeBuilder .create(JAVA) .objectType() .id(mapClass.getName()); objectTypeBuilder.openWith().objectType().id(dateClass.getName()); MapDataType dataType = (MapDataType) toDataType(objectTypeBuilder.build()); assertThat(dataType.getType(), is(equalTo(mapClass))); assertThat(dataType.getKeyDataType().getType(), is(equalTo(String.class))); assertThat(dataType.getValueDataType().getType(), is(equalTo(dateClass))); } @Test public void getDataTypeFromObject() { Class<Object> objectClass = Object.class; ObjectTypeBuilder objectTypeBuilder = BaseTypeBuilder .create(JAVA) .objectType() .id(objectClass.getName()); DataType dataType = toDataType(objectTypeBuilder.build()); assertThat(dataType.getType(), is(equalTo(objectClass))); } @Test public void getDataTypeFromString() { Class<String> stringClass = String.class; ObjectTypeBuilder objectTypeBuilder = BaseTypeBuilder .create(JAVA) .objectType() .id(stringClass.getName()); DataType dataType = toDataType(objectTypeBuilder.build()); assertThat(dataType.getType(), is(equalTo(stringClass))); } private void assertField(String name, MetadataType metadataType, Collection<Field> fields) { Field field = findField(name, fields); assertThat(field, is(notNullValue())); assertThat(field.getName(), equalTo(name)); assertThat(field.getType(), equalTo(JavaTypeUtils.getType(metadataType))); } private Field findField(String name, Collection<Field> fields) { return (Field) CollectionUtils.find(fields, f -> name.equals(((Field) f).getName())); } private void assertType(MetadataType type, Class<?> rawType) { assertThat(rawType.isAssignableFrom(JavaTypeUtils.getType(type)), is(true)); } private Method getMethod(String methodName, Class<?>... parameterTypes) throws Exception { return getClass().getMethod(methodName, parameterTypes); } private void assertDictionary(MetadataType metadataType, Class<?> valueType) { assertThat(metadataType, is(instanceOf(ObjectType.class))); ObjectType dictionaryType = (ObjectType) metadataType; assertType(dictionaryType, Map.class); assertThat(dictionaryType.getOpenRestriction().isPresent(), is(true)); assertType(dictionaryType.getOpenRestriction().get(), valueType); } private void assertList(MetadataType metadataType, Class<?> listItemType) { assertThat(metadataType, is(instanceOf(ArrayType.class))); assertType(metadataType, List.class); MetadataType itemMetadataType = ((ArrayType) metadataType).getType(); assertType(itemMetadataType, listItemType); } public Map<String, Apple> foo() { return new HashMap<>(); } public Result<String, Attributes> operationResult() { return null; } public PagingProvider<Object, String> pagingProvider() { return null; } public PagingProvider<Object, Result<String, Attributes>> pagingProviderOperationResult() { return null; } public int bar(String s, Long l, Apple apple, Map<Banana, Kiwi> fruits) { return Objects.hash(s, l, apple, fruits); } public List<FruitBasket> getBaskets() { return baskets; } public void setBaskets(List<FruitBasket> baskets) { this.baskets = baskets; } private void assertAttributesType(String method) throws Exception { MetadataType attributesType = IntrospectionUtils.getMethodReturnAttributesType(getMethod(method), TYPE_LOADER); assertThat(attributesType, is(instanceOf(ObjectType.class))); assertType(attributesType, Attributes.class); } private void assertVoidAttributesType(String method) throws Exception { MetadataType attributesType = IntrospectionUtils.getMethodReturnAttributesType(getMethod(method), TYPE_LOADER); assertThat(attributesType, is(instanceOf(VoidType.class))); } private void assertReturnType(String method) throws Exception { MetadataType returnType = IntrospectionUtils.getMethodReturnType(getMethod(method), TYPE_LOADER); assertThat(returnType, is(instanceOf(StringType.class))); assertType(returnType, String.class); } private void assertPagingProviderReturnType(String method) throws Exception { MetadataType returnType = IntrospectionUtils.getMethodReturnType(getMethod(method), TYPE_LOADER); assertThat(returnType, is(instanceOf(ArrayType.class))); assertThat(((ArrayType) returnType).getType(), is(instanceOf(StringType.class))); assertType(((ArrayType) returnType).getType(), String.class); } private void assertPagingProviderReturnResultType(String method) throws Exception { MetadataType returnType = IntrospectionUtils.getMethodReturnType(getMethod(method), TYPE_LOADER); assertThat(returnType, is(instanceOf(ArrayType.class))); assertMessageType(((ArrayType) returnType).getType(), is(instanceOf(StringType.class)), is(instanceOf(ObjectType.class))); } private class TestPagingProvider implements PagingProvider<Object, Banana> { @Override public List<Banana> getPage(Object connection) { return null; } @Override public Optional<Integer> getTotalResults(Object connection) { return null; } @Override public void close() throws IOException {} } }