/* * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.amqp.support.converter; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.Matchers.containsString; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; import static org.junit.Assert.fail; import static org.mockito.BDDMockito.given; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Spy; import org.mockito.junit.MockitoJUnitRunner; import org.springframework.amqp.core.MessageProperties; import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.type.CollectionType; import com.fasterxml.jackson.databind.type.MapType; import com.fasterxml.jackson.databind.type.TypeFactory; /** * @author James Carr * @author Sam Nelson * @author Andreas Asplund * @author Gary Russell */ @RunWith(MockitoJUnitRunner.class) public class DefaultJackson2JavaTypeMapperTests { @Spy DefaultJackson2JavaTypeMapper javaTypeMapper = new DefaultJackson2JavaTypeMapper(); private final MessageProperties properties = new MessageProperties(); @SuppressWarnings("rawtypes") private final Class<ArrayList> containerClass = ArrayList.class; @SuppressWarnings("rawtypes") private final Class<HashMap> mapClass = HashMap.class; @Test public void getAnObjectWhenClassIdNotPresent() { JavaType javaType = javaTypeMapper.toJavaType(properties); assertEquals(Object.class, javaType.getRawClass()); } @Test public void shouldLookInTheClassIdFieldNameToFindTheClassName() { properties.getHeaders().put("type", "java.lang.String"); given(javaTypeMapper.getClassIdFieldName()).willReturn("type"); JavaType javaType = javaTypeMapper.toJavaType(properties); assertThat(javaType, equalTo(TypeFactory.defaultInstance().constructType(String.class))); } @Test public void shouldUseTheClassProvidedByTheLookupMapIfPresent() { properties.getHeaders().put("__TypeId__", "trade"); javaTypeMapper.setIdClassMapping(map("trade", SimpleTrade.class)); JavaType javaType = javaTypeMapper.toJavaType(properties); assertEquals(javaType, TypeFactory.defaultInstance().constructType(SimpleTrade.class)); } @Test public void fromJavaTypeShouldPopulateWithJavaTypeNameByDefault() { javaTypeMapper.fromJavaType(TypeFactory.defaultInstance().constructType(SimpleTrade.class), properties); String className = (String) properties.getHeaders().get(javaTypeMapper.getClassIdFieldName()); assertThat(className, equalTo(SimpleTrade.class.getName())); } @Test public void shouldUseSpecialNameForClassIfPresent() throws Exception { javaTypeMapper.setIdClassMapping(map("daytrade", SimpleTrade.class)); javaTypeMapper.fromJavaType(TypeFactory.defaultInstance().constructType(SimpleTrade.class), properties); String className = (String) properties.getHeaders().get(javaTypeMapper.getClassIdFieldName()); assertThat(className, equalTo("daytrade")); } @Test public void shouldThrowAnExceptionWhenContentClassIdIsNotPresentWhenClassIdIsContainerType() { properties.getHeaders().put(javaTypeMapper.getClassIdFieldName(), ArrayList.class.getName()); try { javaTypeMapper.toJavaType(properties); } catch (MessageConversionException e) { String contentClassIdFieldName = javaTypeMapper.getContentClassIdFieldName(); assertThat(e.getMessage(), containsString("Could not resolve " + contentClassIdFieldName + " in header")); return; } fail(); } @Test public void shouldLookInTheContentClassIdFieldNameToFindTheContainerClassIDWhenClassIdIsContainerType() { properties.getHeaders().put("contentType", "java.lang.String"); properties.getHeaders().put(javaTypeMapper.getClassIdFieldName(), ArrayList.class.getName()); given(javaTypeMapper.getContentClassIdFieldName()).willReturn("contentType"); JavaType javaType = javaTypeMapper.toJavaType(properties); assertThat((CollectionType) javaType, equalTo(TypeFactory.defaultInstance().constructCollectionType(ArrayList.class, String.class))); } @Test public void shouldUseTheContentClassProvidedByTheLookupMapIfPresent() { properties.getHeaders().put(javaTypeMapper.getClassIdFieldName(), containerClass.getName()); properties.getHeaders().put("__ContentTypeId__", "trade"); Map<String, Class<?>> map = map("trade", SimpleTrade.class); map.put(javaTypeMapper.getClassIdFieldName(), containerClass); javaTypeMapper.setIdClassMapping(map); JavaType javaType = javaTypeMapper.toJavaType(properties); assertThat((CollectionType) javaType, equalTo(TypeFactory.defaultInstance().constructCollectionType(containerClass, TypeFactory.defaultInstance().constructType(SimpleTrade.class)))); } @Test public void fromJavaTypeShouldPopulateWithContentTypeJavaTypeNameByDefault() { javaTypeMapper.fromJavaType(TypeFactory.defaultInstance().constructCollectionType(containerClass, TypeFactory.defaultInstance().constructType(SimpleTrade.class)), properties); String className = (String) properties.getHeaders().get(javaTypeMapper.getClassIdFieldName()); String contentClassName = (String) properties.getHeaders().get(javaTypeMapper.getContentClassIdFieldName()); assertThat(className, equalTo(ArrayList.class.getName())); assertThat(contentClassName, equalTo(SimpleTrade.class.getName())); } @Test public void shouldThrowAnExceptionWhenKeyClassIdIsNotPresentWhenClassIdIsAMap() { properties.getHeaders().put(javaTypeMapper.getClassIdFieldName(), HashMap.class.getName()); properties.getHeaders().put(javaTypeMapper.getKeyClassIdFieldName(), String.class.getName()); try { javaTypeMapper.toJavaType(properties); } catch (MessageConversionException e) { String contentClassIdFieldName = javaTypeMapper.getContentClassIdFieldName(); assertThat(e.getMessage(), containsString("Could not resolve " + contentClassIdFieldName + " in header")); return; } fail(); } @Test public void shouldLookInTheValueClassIdFieldNameToFindTheValueClassIDWhenClassIdIsAMap() { properties.getHeaders().put("keyType", "java.lang.Integer"); properties.getHeaders().put(javaTypeMapper.getContentClassIdFieldName(), "java.lang.String"); properties.getHeaders().put(javaTypeMapper.getClassIdFieldName(), HashMap.class.getName()); given(javaTypeMapper.getKeyClassIdFieldName()).willReturn("keyType"); JavaType javaType = javaTypeMapper.toJavaType(properties); assertThat((MapType) javaType, equalTo(TypeFactory.defaultInstance().constructMapType(HashMap.class, Integer.class, String.class))); } @Test public void shouldUseTheKeyClassProvidedByTheLookupMapIfPresent() { properties.getHeaders().put(javaTypeMapper.getClassIdFieldName(), mapClass.getName()); properties.getHeaders().put(javaTypeMapper.getContentClassIdFieldName(), "java.lang.String"); properties.getHeaders().put("__KeyTypeId__", "trade"); Map<String, Class<?>> map = map("trade", SimpleTrade.class); map.put(javaTypeMapper.getClassIdFieldName(), mapClass); map.put(javaTypeMapper.getContentClassIdFieldName(), String.class); javaTypeMapper.setIdClassMapping(map); JavaType javaType = javaTypeMapper.toJavaType(properties); assertThat((MapType) javaType, equalTo(TypeFactory.defaultInstance().constructMapType(mapClass, TypeFactory.defaultInstance().constructType(SimpleTrade.class), TypeFactory.defaultInstance().constructType(String.class)))); } @Test public void fromJavaTypeShouldPopulateWithKeyTypeAndContentJavaTypeNameByDefault() { javaTypeMapper.fromJavaType(TypeFactory.defaultInstance().constructMapType(mapClass, TypeFactory.defaultInstance().constructType(SimpleTrade.class), TypeFactory.defaultInstance().constructType(String.class)), properties); String className = (String) properties.getHeaders().get(javaTypeMapper.getClassIdFieldName()); String contentClassName = (String) properties.getHeaders().get(javaTypeMapper.getContentClassIdFieldName()); String keyClassName = (String) properties.getHeaders().get(javaTypeMapper.getKeyClassIdFieldName()); assertThat(className, equalTo(HashMap.class.getName())); assertThat(contentClassName, equalTo(String.class.getName())); assertThat(keyClassName, equalTo(SimpleTrade.class.getName())); } @Test public void fromClassShouldPopulateWithJavaTypeNameByDefault() { javaTypeMapper.fromClass(SimpleTrade.class, properties); String className = (String) properties.getHeaders().get(javaTypeMapper.getClassIdFieldName()); assertThat(className, equalTo(SimpleTrade.class.getName())); } @Test public void toClassShouldUseTheClassProvidedByTheLookupMapIfPresent() { properties.getHeaders().put("__TypeId__", "trade"); javaTypeMapper.setIdClassMapping(map("trade", SimpleTrade.class)); Class<?> clazz = javaTypeMapper.toClass(properties); assertEquals(SimpleTrade.class, clazz); } private Map<String, Class<?>> map(String string, Class<?> clazz) { Map<String, Class<?>> map = new HashMap<String, Class<?>>(); map.put(string, clazz); return map; } }