@@ -1,87 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022 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
|
||||
*
|
||||
* https://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.mongodb.aot;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.springframework.data.mongodb.aot.RepositoryRegistrationAotContributionAssert.*;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.aot.hint.RuntimeHints;
|
||||
import org.springframework.beans.factory.aot.BeanRegistrationAotContribution;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.RegisteredBean;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.core.annotation.SynthesizedAnnotation;
|
||||
import org.springframework.data.annotation.LastModifiedDate;
|
||||
import org.springframework.data.annotation.Transient;
|
||||
import org.springframework.data.aot.RepositoryRegistrationAotContribution;
|
||||
import org.springframework.data.mongodb.aot.configs.ImperativeConfig;
|
||||
import org.springframework.data.mongodb.core.convert.LazyLoadingProxy;
|
||||
import org.springframework.data.mongodb.core.mapping.Address;
|
||||
import org.springframework.data.mongodb.core.mapping.DBRef;
|
||||
import org.springframework.data.mongodb.core.mapping.Document;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 2022/04
|
||||
*/
|
||||
public class AotMongoRepositoryPostProcessorUnitTests {
|
||||
|
||||
@Test
|
||||
void contributesProxiesForDataAnnotations() {
|
||||
|
||||
RepositoryRegistrationAotContribution repositoryBeanContribution = computeConfiguration(ImperativeConfig.class)
|
||||
.forRepository(ImperativeConfig.PersonRepository.class);
|
||||
|
||||
assertThatContribution(repositoryBeanContribution) //
|
||||
.codeContributionSatisfies(contribution -> {
|
||||
|
||||
contribution.contributesJdkProxy(Transient.class, SynthesizedAnnotation.class);
|
||||
contribution.contributesJdkProxy(LastModifiedDate.class, SynthesizedAnnotation.class);
|
||||
contribution.contributesJdkProxy(Document.class, SynthesizedAnnotation.class);
|
||||
contribution.contributesJdkProxy(DBRef.class, SynthesizedAnnotation.class);
|
||||
});
|
||||
}
|
||||
|
||||
BeanContributionBuilder computeConfiguration(Class<?> configuration) {
|
||||
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||
ctx.register(configuration);
|
||||
ctx.refreshForAotProcessing(new RuntimeHints());
|
||||
|
||||
return it -> {
|
||||
|
||||
String[] repoBeanNames = ctx.getBeanNamesForType(it);
|
||||
assertThat(repoBeanNames).describedAs("Unable to find repository %s in configuration %s.", it, configuration)
|
||||
.hasSize(1);
|
||||
|
||||
String beanName = repoBeanNames[0];
|
||||
|
||||
AotMongoRepositoryPostProcessor postProcessor = ctx.getBean(AotMongoRepositoryPostProcessor.class);
|
||||
|
||||
postProcessor.setBeanFactory(ctx.getDefaultListableBeanFactory());
|
||||
|
||||
BeanRegistrationAotContribution beanRegistrationAotContribution = postProcessor
|
||||
.processAheadOfTime(RegisteredBean.of(ctx.getBeanFactory(), beanName));
|
||||
assertThat(beanRegistrationAotContribution).isInstanceOf(RepositoryRegistrationAotContribution.class);
|
||||
return (RepositoryRegistrationAotContribution) beanRegistrationAotContribution;
|
||||
};
|
||||
}
|
||||
|
||||
interface BeanContributionBuilder {
|
||||
RepositoryRegistrationAotContribution forRepository(Class<?> repositoryInterface);
|
||||
}
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022 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
|
||||
*
|
||||
* https://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.mongodb.aot;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.assertj.core.api.AbstractAssert;
|
||||
import org.springframework.aot.generate.GenerationContext;
|
||||
import org.springframework.aot.hint.JdkProxyHint;
|
||||
import org.springframework.aot.hint.predicate.RuntimeHintsPredicates;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 2022/04
|
||||
*/
|
||||
public class CodeContributionAssert extends AbstractAssert<CodeContributionAssert, GenerationContext> {
|
||||
|
||||
public CodeContributionAssert(GenerationContext contribution) {
|
||||
super(contribution, CodeContributionAssert.class);
|
||||
}
|
||||
|
||||
public CodeContributionAssert contributesReflectionFor(Class<?>... types) {
|
||||
|
||||
for (Class<?> type : types) {
|
||||
assertThat(this.actual.getRuntimeHints())
|
||||
.describedAs("No reflection entry found for [%s]", type)
|
||||
.matches(RuntimeHintsPredicates.reflection().onType(type));
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public CodeContributionAssert doesNotContributeReflectionFor(Class<?>... types) {
|
||||
|
||||
for (Class<?> type : types) {
|
||||
assertThat(this.actual.getRuntimeHints())
|
||||
.describedAs("Reflection entry found for [%s]", type)
|
||||
.matches(RuntimeHintsPredicates.reflection().onType(type).negate());
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public CodeContributionAssert contributesJdkProxyFor(Class<?> entryPoint) {
|
||||
|
||||
assertThat(jdkProxiesFor(entryPoint).findFirst())
|
||||
.describedAs("No JDK proxy found for [%s]", entryPoint)
|
||||
.isPresent();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public CodeContributionAssert doesNotContributeJdkProxyFor(Class<?> entryPoint) {
|
||||
|
||||
assertThat(jdkProxiesFor(entryPoint).findFirst())
|
||||
.describedAs("Found JDK proxy matching [%s] though it should not be present", entryPoint)
|
||||
.isNotPresent();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public CodeContributionAssert contributesJdkProxy(Class<?>... proxyInterfaces) {
|
||||
|
||||
assertThat(jdkProxiesFor(proxyInterfaces[0]))
|
||||
.describedAs("Unable to find JDK proxy matching [%s]", Arrays.asList(proxyInterfaces))
|
||||
.anySatisfy(it -> new JdkProxyAssert(it).matches(proxyInterfaces));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public CodeContributionAssert doesNotContributeJdkProxy(Class<?>... proxyInterfaces) {
|
||||
|
||||
assertThat(jdkProxiesFor(proxyInterfaces[0]))
|
||||
.describedAs("Found JDK proxy matching [%s] though it should not be present",
|
||||
Arrays.asList(proxyInterfaces))
|
||||
.noneSatisfy(it -> new JdkProxyAssert(it).matches(proxyInterfaces));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
private Stream<JdkProxyHint> jdkProxiesFor(Class<?> entryPoint) {
|
||||
|
||||
return this.actual.getRuntimeHints().proxies().jdkProxies()
|
||||
.filter(jdkProxyHint -> jdkProxyHint.getProxiedInterfaces().get(0).getCanonicalName()
|
||||
.equals(entryPoint.getCanonicalName()));
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022 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
|
||||
*
|
||||
* https://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.mongodb.aot;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.assertj.core.api.AbstractAssert;
|
||||
import org.springframework.aot.hint.JdkProxyHint;
|
||||
import org.springframework.aot.hint.TypeReference;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 2022/04
|
||||
*/
|
||||
public class JdkProxyAssert extends AbstractAssert<JdkProxyAssert, JdkProxyHint> {
|
||||
|
||||
public JdkProxyAssert(JdkProxyHint jdkProxyHint) {
|
||||
super(jdkProxyHint, JdkProxyAssert.class);
|
||||
}
|
||||
|
||||
public void matches(Class<?>... proxyInterfaces) {
|
||||
assertThat(actual.getProxiedInterfaces().stream().map(TypeReference::getCanonicalName))
|
||||
.containsExactly(Arrays.stream(proxyInterfaces).map(Class::getCanonicalName).toArray(String[]::new));
|
||||
}
|
||||
|
||||
public List<TypeReference> getProxiedInterfaces() {
|
||||
return actual.getProxiedInterfaces();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,111 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022 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
|
||||
*
|
||||
* https://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.mongodb.aot;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.assertj.core.api.AbstractAssert;
|
||||
import org.springframework.aot.generate.ClassNameGenerator;
|
||||
import org.springframework.aot.generate.DefaultGenerationContext;
|
||||
import org.springframework.aot.generate.InMemoryGeneratedFiles;
|
||||
import org.springframework.aot.hint.RuntimeHints;
|
||||
import org.springframework.beans.factory.aot.BeanRegistrationAotContribution;
|
||||
import org.springframework.beans.factory.aot.BeanRegistrationCode;
|
||||
import org.springframework.data.aot.RepositoryRegistrationAotContribution;
|
||||
import org.springframework.data.repository.core.RepositoryInformation;
|
||||
import org.springframework.data.repository.core.support.RepositoryFragment;
|
||||
import org.springframework.lang.NonNull;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 2022/04
|
||||
*/
|
||||
public class RepositoryRegistrationAotContributionAssert
|
||||
extends AbstractAssert<RepositoryRegistrationAotContributionAssert, RepositoryRegistrationAotContribution> {
|
||||
|
||||
@NonNull
|
||||
public static RepositoryRegistrationAotContributionAssert assertThatContribution(
|
||||
@NonNull RepositoryRegistrationAotContribution actual) {
|
||||
|
||||
return new RepositoryRegistrationAotContributionAssert(actual);
|
||||
}
|
||||
|
||||
public RepositoryRegistrationAotContributionAssert(@NonNull RepositoryRegistrationAotContribution actual) {
|
||||
super(actual, RepositoryRegistrationAotContributionAssert.class);
|
||||
}
|
||||
|
||||
public RepositoryRegistrationAotContributionAssert targetRepositoryTypeIs(Class<?> expected) {
|
||||
|
||||
assertThat(getRepositoryInformation().getRepositoryInterface()).isEqualTo(expected);
|
||||
|
||||
return this.myself;
|
||||
}
|
||||
|
||||
public RepositoryRegistrationAotContributionAssert hasNoFragments() {
|
||||
|
||||
assertThat(getRepositoryInformation().getFragments()).isEmpty();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public RepositoryRegistrationAotContributionAssert hasFragments() {
|
||||
|
||||
assertThat(getRepositoryInformation().getFragments()).isNotEmpty();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public RepositoryRegistrationAotContributionAssert verifyFragments(Consumer<Set<RepositoryFragment<?>>> consumer) {
|
||||
|
||||
assertThat(getRepositoryInformation().getFragments())
|
||||
.satisfies(it -> consumer.accept(new LinkedHashSet<>(it)));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public RepositoryRegistrationAotContributionAssert codeContributionSatisfies(
|
||||
Consumer<CodeContributionAssert> assertWith) {
|
||||
|
||||
BeanRegistrationCode mockBeanRegistrationCode = mock(BeanRegistrationCode.class);
|
||||
|
||||
DefaultGenerationContext generationContext =
|
||||
new DefaultGenerationContext(new ClassNameGenerator(Object.class), new InMemoryGeneratedFiles());
|
||||
|
||||
this.actual.applyTo(generationContext, mockBeanRegistrationCode);
|
||||
|
||||
assertWith.accept(new CodeContributionAssert(generationContext));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
private RepositoryInformation getRepositoryInformation() {
|
||||
|
||||
assertThat(this.actual)
|
||||
.describedAs("No repository interface found on null bean contribution")
|
||||
.isNotNull();
|
||||
|
||||
assertThat(this.actual.getRepositoryInformation())
|
||||
.describedAs("No repository interface found on null repository information")
|
||||
.isNotNull();
|
||||
|
||||
return this.actual.getRepositoryInformation();
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022 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
|
||||
*
|
||||
* https://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.mongodb.aot.configs;
|
||||
|
||||
import org.springframework.context.annotation.ComponentScan.Filter;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.FilterType;
|
||||
import org.springframework.data.mongodb.aot.domaintypes.Person;
|
||||
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
@Configuration
|
||||
@EnableMongoRepositories(considerNestedRepositories = true,
|
||||
includeFilters = { @Filter(type = FilterType.REGEX, pattern = ".*PersonRepository$") })
|
||||
public class ImperativeConfig {
|
||||
|
||||
public interface PersonRepository extends CrudRepository<Person, String> {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022 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
|
||||
*
|
||||
* https://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.mongodb.aot.domaintypes;
|
||||
|
||||
import org.springframework.data.mongodb.core.mapping.Field;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 2022/04
|
||||
*/
|
||||
public class Address {
|
||||
|
||||
@Field("the-street")
|
||||
String street;
|
||||
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022 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
|
||||
*
|
||||
* https://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.mongodb.aot.domaintypes;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.annotation.LastModifiedDate;
|
||||
import org.springframework.data.annotation.Transient;
|
||||
import org.springframework.data.mongodb.core.mapping.DBRef;
|
||||
import org.springframework.data.mongodb.core.mapping.Document;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 2022/04
|
||||
*/
|
||||
@Document("persons")
|
||||
public class Person {
|
||||
|
||||
@Id String id;
|
||||
@DBRef(lazy = true) Address address;
|
||||
|
||||
@Transient String transientProperty;
|
||||
|
||||
@LastModifiedDate Instant modifiedAt;
|
||||
}
|
||||
Reference in New Issue
Block a user