/* * Copyright 2015-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.data.repository.query; import static org.assertj.core.api.Assertions.*; import java.lang.reflect.Method; import java.math.BigInteger; import java.time.LocalDateTime; import java.util.List; import org.junit.Test; import org.springframework.beans.factory.annotation.Value; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.projection.SpelAwareProxyProjectionFactory; import org.springframework.data.repository.Repository; import org.springframework.data.repository.core.support.DefaultRepositoryMetadata; /** * Unit tests for {@link ReturnedType}. * * @author Oliver Gierke * @author Mark Paluch */ public class ReturnedTypeUnitTests { @Test // DATACMNS-89 public void treatsSimpleDomainTypeAsIs() throws Exception { ReturnedType type = getReturnedType("findAll"); assertThat(type.getTypeToRead()).isEqualTo(Sample.class); assertThat(type.getInputProperties()).isEmpty(); assertThat(type.isProjecting()).isFalse(); assertThat(type.needsCustomConstruction()).isFalse(); } @Test // DATACMNS-89 public void detectsDto() throws Exception { ReturnedType type = getReturnedType("findAllDtos"); assertThat(type.getTypeToRead()).isEqualTo(SampleDto.class); assertThat(type.getInputProperties()).contains("firstname"); assertThat(type.isInstance(new SampleDto("firstname"))).isTrue(); assertThat(type.isProjecting()).isTrue(); assertThat(type.needsCustomConstruction()).isTrue(); } @Test // DATACMNS-89 public void detectsProjection() throws Exception { ReturnedType type = getReturnedType("findAllProjection"); assertThat(type.getTypeToRead()).isNull(); assertThat(type.getInputProperties()).contains("lastname"); } @Test // DATACMNS-89 public void detectsVoidMethod() throws Exception { ReturnedType type = getReturnedType("voidMethod"); assertThat(type.getDomainType()).isEqualTo(Sample.class); assertThat(type.getReturnedType()).isEqualTo(void.class); } @Test // DATACMNS-89 public void detectsClosedProjection() throws Exception { ReturnedType type = getReturnedType("findOneProjection"); assertThat(type.getReturnedType()).isEqualTo(SampleProjection.class); assertThat(type.isProjecting()).isTrue(); assertThat(type.needsCustomConstruction()).isTrue(); } @Test // DATACMNS-89 public void detectsOpenProjection() throws Exception { ReturnedType type = getReturnedType("findOneOpenProjection"); assertThat(type.getReturnedType()).isEqualTo(OpenProjection.class); assertThat(type.isProjecting()).isTrue(); assertThat(type.needsCustomConstruction()).isFalse(); assertThat(type.getTypeToRead()).isEqualTo(Sample.class); } @Test // DATACMNS-89 public void detectsComplexNumberTypes() throws Exception { ReturnedType type = getReturnedType("countQuery"); assertThat(type.isProjecting()).isFalse(); assertThat(type.needsCustomConstruction()).isFalse(); assertThat(type.getTypeToRead()).isEqualTo(BigInteger.class); } @Test // DATACMNS-840 public void detectsSampleDtoWithDefaultConstructor() throws Exception { ReturnedType type = getReturnedType("dtoWithMultipleConstructors"); assertThat(type.getInputProperties()).isEmpty(); assertThat(type.needsCustomConstruction()).isFalse(); } @Test // DATACMNS-840 public void doesNotConsiderAnEnumProjecting() throws Exception { ReturnedType type = getReturnedType("findEnum"); assertThat(type.needsCustomConstruction()).isFalse(); assertThat(type.isProjecting()).isFalse(); } @Test // DATACMNS-850 public void considersAllJavaTypesAsNotProjecting() throws Exception { ReturnedType type = getReturnedType("timeQuery"); assertThat(type.needsCustomConstruction()).isFalse(); assertThat(type.isProjecting()).isFalse(); } @Test // DATACMNS-862 public void considersInterfaceImplementedByDomainTypeNotProjecting() throws Exception { ReturnedType type = getReturnedType("findOneInterface"); assertThat(type.needsCustomConstruction()).isFalse(); assertThat(type.isProjecting()).isFalse(); } @Test // DATACMNS-963 public void detectsDistinctInputProperties() { ReturnedType type = ReturnedType.of(Child.class, Object.class, new SpelAwareProxyProjectionFactory()); List<String> properties = type.getInputProperties(); assertThat(properties).hasSize(1); assertThat(properties).containsExactly("firstname"); } private static ReturnedType getReturnedType(String methodName, Class<?>... parameters) throws Exception { return getQueryMethod(methodName, parameters).getResultProcessor().getReturnedType(); } private static QueryMethod getQueryMethod(String name, Class<?>... parameters) throws Exception { Method method = SampleRepository.class.getMethod(name, parameters); return new QueryMethod(method, new DefaultRepositoryMetadata(SampleRepository.class), new SpelAwareProxyProjectionFactory()); } interface SampleRepository extends Repository<Sample, Long> { void voidMethod(); List<Sample> findAll(); List<SampleDto> findAllDtos(); List<SampleProjection> findAllProjection(); Sample findOne(); SampleDto findOneDto(); SampleProjection findOneProjection(); OpenProjection findOneOpenProjection(); Page<SampleProjection> findPageProjection(Pageable pageable); BigInteger countQuery(); SampleDtoWithMultipleConstructors dtoWithMultipleConstructors(); MyEnum findEnum(); LocalDateTime timeQuery(); SampleInterface findOneInterface(); static enum MyEnum { VALUE } } static interface SampleInterface {} static class Sample implements SampleInterface { public String firstname, lastname; public Sample(String firstname, String lastname) { this.firstname = firstname; this.lastname = lastname; } } static class SampleDto { public SampleDto(String firstname) { } } static class SampleDtoWithMultipleConstructors { SampleDtoWithMultipleConstructors(String firstname) {} SampleDtoWithMultipleConstructors(int age) {} } interface SampleProjection { String getLastname(); } interface OpenProjection { String getLastname(); @Value("#{target.firstname + ' ' + target.lastname}") String getFullName(); } static interface Parent { String getFirstname(); } static interface Child extends Parent { String getFirstname(); } }