ProjectionService implements InitializingBean { void addProjectionInterface(NamedProjection annotation, Class<?> annotatedInterface) throws MultipleSimilarlyNamedProjectionsException, MultipleDefaultProjectionsException { var projectionName = getProjectionName(annotation, annotatedInterface); var projectionTarget = annotation.target(); var defaultProjection = annotation.defaultProjection(); Pair<String, Class<?>> nameTargetPair = Pair.of(projectionName, projectionTarget); if(projectionClassMap.containsKey(nameTargetPair)) { throw new MultipleSimilarlyNamedProjectionsException(projectionName, projectionTarget); } projectionClassMap.put(nameTargetPair, annotatedInterface); log.debug(String.format("Added projection for target '%s' with name '%s'!", projectionTarget.toString(), projectionName)); if(defaultProjection) { if(defaultProjectionClassMap.containsKey(projectionTarget)) { throw new MultipleDefaultProjectionsException(projectionTarget); } defaultProjectionClassMap.put(projectionTarget, annotatedInterface); log.debug(String.format("Added default projection for target '%s' with name '%s'!", projectionTarget.toString(), projectionName)); } } @Autowired  ProjectionService(AnnotatedTypeScanner typeScanner, AnnotationUtilsWrapper annotationUtilsWrapper); Class<?> getByNameOrDefault(@NonNull String projectionName, @NonNull Class<?> projectionTarget); Class<?> getDefault(Class<?> projectionTarget); @Override void afterPropertiesSet();  }
@Test public void addProjectionInterfaceAddsProjectionWithSimpleClassNameWhenNameNotSet() throws MultipleDefaultProjectionsException, MultipleSimilarlyNamedProjectionsException { var expectedTarget = (Class) Integer.class; var expectedName = annotatedClass.getSimpleName().toLowerCase(); given(namedProjectionAnnotationMock.target()).willReturn(expectedTarget); given(namedProjectionAnnotationMock.name()).willReturn(""); given(namedProjectionAnnotationMock.defaultProjection()).willReturn(false); projectionService.addProjectionInterface(namedProjectionAnnotationMock, annotatedClass); var softly = new SoftAssertions(); softly.assertThat(projectionService.projectionClassMap) .containsExactly(entry(Pair.of(expectedName, expectedTarget), (Class<?>) annotatedClass)); softly.assertThat(projectionService.defaultProjectionClassMap).isEmpty(); softly.assertAll(); }
@Test public void addProjectionInterfaceAddsProjectionAsDefaultWithSimpleClassNameWhenMarkedAsDefaultAndNameNotSet() throws MultipleDefaultProjectionsException, MultipleSimilarlyNamedProjectionsException { var expectedTarget = (Class) Integer.class; var expectedName = annotatedClass.getSimpleName().toLowerCase(); given(namedProjectionAnnotationMock.target()).willReturn(expectedTarget); given(namedProjectionAnnotationMock.name()).willReturn(""); given(namedProjectionAnnotationMock.defaultProjection()).willReturn(true); projectionService.addProjectionInterface(namedProjectionAnnotationMock, annotatedClass); var softly = new SoftAssertions(); softly.assertThat(projectionService.projectionClassMap) .containsOnly(entry(Pair.of(expectedName, expectedTarget), (Class<?>) annotatedClass)); softly.assertThat(projectionService.defaultProjectionClassMap) .containsExactly(entry((Class<?>) expectedTarget, (Class<?>) annotatedClass)); softly.assertAll(); }
@Test public void addProjectionInterfaceAddsProjectionWithName() throws MultipleDefaultProjectionsException, MultipleSimilarlyNamedProjectionsException { var expectedTarget = (Class) Integer.class; var expectedName = "cool-projection-name"; given(namedProjectionAnnotationMock.target()).willReturn(expectedTarget); given(namedProjectionAnnotationMock.name()).willReturn(expectedName); given(namedProjectionAnnotationMock.defaultProjection()).willReturn(false); projectionService.addProjectionInterface(namedProjectionAnnotationMock, annotatedClass); var softly = new SoftAssertions(); softly.assertThat(projectionService.projectionClassMap) .containsOnly(entry(Pair.of(expectedName, expectedTarget), (Class<?>) annotatedClass)); softly.assertThat(projectionService.defaultProjectionClassMap) .isEmpty(); softly.assertAll(); }
@Test public void addProjectionInterfaceAddsProjectionAsDefaultWithNameWhenMarkedAsDefault() throws MultipleDefaultProjectionsException, MultipleSimilarlyNamedProjectionsException { var expectedTarget = (Class) Integer.class; var expectedName = "cool-projection-name"; given(namedProjectionAnnotationMock.target()).willReturn(expectedTarget); given(namedProjectionAnnotationMock.name()).willReturn(expectedName); given(namedProjectionAnnotationMock.defaultProjection()).willReturn(true); projectionService.addProjectionInterface(namedProjectionAnnotationMock, annotatedClass); var softly = new SoftAssertions(); softly.assertThat(projectionService.projectionClassMap) .containsOnly(entry(Pair.of(expectedName, expectedTarget), (Class<?>) annotatedClass)); softly.assertThat(projectionService.defaultProjectionClassMap) .containsExactly(entry((Class<?>) expectedTarget, (Class<?>) annotatedClass)); softly.assertAll(); }
@Test public void addProjectionInterfaceThrowsExceptionWhenMultipleSimilarlyNamedPresent() { var projectionName = "projection-name"; var projectionTarget = (Class) Integer.class; projectionService.projectionClassMap.put(Pair.of(projectionName, projectionTarget), annotatedClass); given(namedProjectionAnnotationMock.name()).willReturn(projectionName); given(namedProjectionAnnotationMock.target()).willReturn(projectionTarget); given(namedProjectionAnnotationMock.defaultProjection()).willReturn(false); assertThatThrownBy(() -> projectionService.addProjectionInterface(namedProjectionAnnotationMock, annotatedClass)) .isInstanceOf(MultipleSimilarlyNamedProjectionsException.class) .hasMessage(String.format("Multiple interfaces annotated with @NamedInterface " + "have the same name ('%s') for the target class '%s'!", projectionName, projectionTarget.getName())); }
@Test public void addProjectionInterfaceThrowsExceptionWhenMultipleDefaultsPresent() { var projectionName = "any-name"; var projectionTarget = (Class) Integer.class; projectionService.defaultProjectionClassMap.put(projectionTarget, annotatedClass); given(namedProjectionAnnotationMock.name()).willReturn(projectionName); given(namedProjectionAnnotationMock.target()).willReturn(projectionTarget); given(namedProjectionAnnotationMock.defaultProjection()).willReturn(true); assertThatThrownBy(() -> projectionService.addProjectionInterface(namedProjectionAnnotationMock, annotatedClass)) .isInstanceOf(MultipleDefaultProjectionsException.class) .hasMessage(String.format("Multiple interfaces annotated with @NamedInterface " + "are marked as the default projections for target class '%s'!", projectionTarget.getName())); }