Skip to content

Commit

Permalink
DATACMNS-1734 - Defer initialization of Repositories in DomainClassCo…
Browse files Browse the repository at this point in the history
…nverter.

DomainClassConverter now delays the initialization of the Repositories instances used to avoid the premature initialization of repository instances as that can cause deadlocks if the infrastructure backing the repositories is initialized on a separate thread.

Refactored nested converter classes to allow them to be static ones.

Related issues: spring-projects/spring-boot#16230, spring-projects/spring-framework#25131.
Original pull request: #445.
  • Loading branch information
odrotbohm authored and mp911de committed May 29, 2020
1 parent 0dcbc94 commit 7af075f
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 9 deletions.
Expand Up @@ -30,6 +30,7 @@
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.core.EntityInformation;
import org.springframework.data.repository.core.RepositoryInformation;
import org.springframework.data.util.Lazy;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
Expand All @@ -47,7 +48,7 @@ public class DomainClassConverter<T extends ConversionService & ConverterRegistr
implements ConditionalGenericConverter, ApplicationContextAware {

private final T conversionService;
private Repositories repositories = Repositories.NONE;
private Lazy<Repositories> repositories = Lazy.of(Repositories.NONE);
private Optional<ToEntityConverter> toEntityConverter = Optional.empty();
private Optional<ToIdConverter> toIdConverter = Optional.empty();

Expand Down Expand Up @@ -97,7 +98,7 @@ public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
* @return
*/
private Optional<? extends ConditionalGenericConverter> getConverter(TypeDescriptor targetType) {
return repositories.hasRepositoryFor(targetType.getType()) ? toEntityConverter : toIdConverter;
return repositories.get().hasRepositoryFor(targetType.getType()) ? toEntityConverter : toIdConverter;
}

/*
Expand All @@ -106,13 +107,18 @@ private Optional<? extends ConditionalGenericConverter> getConverter(TypeDescrip
*/
public void setApplicationContext(ApplicationContext context) {

this.repositories = new Repositories(context);
this.repositories = Lazy.of(() -> {

this.toEntityConverter = Optional.of(new ToEntityConverter(this.repositories, this.conversionService));
this.toEntityConverter.ifPresent(it -> this.conversionService.addConverter(it));
Repositories repositories = new Repositories(context);

this.toIdConverter = Optional.of(new ToIdConverter());
this.toIdConverter.ifPresent(it -> this.conversionService.addConverter(it));
this.toEntityConverter = Optional.of(new ToEntityConverter(repositories, conversionService));
this.toEntityConverter.ifPresent(it -> conversionService.addConverter(it));

this.toIdConverter = Optional.of(new ToIdConverter(repositories, conversionService));
this.toIdConverter.ifPresent(it -> conversionService.addConverter(it));

return repositories;
});
}

/**
Expand All @@ -121,9 +127,11 @@ public void setApplicationContext(ApplicationContext context) {
* @author Oliver Gierke
* @since 1.10
*/
private class ToEntityConverter implements ConditionalGenericConverter {
private static class ToEntityConverter implements ConditionalGenericConverter {

private final RepositoryInvokerFactory repositoryInvokerFactory;
private final Repositories repositories;
private final ConversionService conversionService;

/**
* Creates a new {@link ToEntityConverter} for the given {@link Repositories} and {@link ConversionService}.
Expand All @@ -132,7 +140,10 @@ private class ToEntityConverter implements ConditionalGenericConverter {
* @param conversionService must not be {@literal null}.
*/
public ToEntityConverter(Repositories repositories, ConversionService conversionService) {

this.repositoryInvokerFactory = new DefaultRepositoryInvokerFactory(repositories, conversionService);
this.repositories = repositories;
this.conversionService = conversionService;
}

/*
Expand Down Expand Up @@ -206,7 +217,16 @@ public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
* @author Oliver Gierke
* @since 1.10
*/
class ToIdConverter implements ConditionalGenericConverter {
static class ToIdConverter implements ConditionalGenericConverter {

private final Repositories repositories;
private final ConversionService conversionService;

public ToIdConverter(Repositories repositories, ConversionService conversionService) {

this.repositories = repositories;
this.conversionService = conversionService;
}

/*
* (non-Javadoc)
Expand Down
Expand Up @@ -177,6 +177,7 @@ public void supportsConversionFromEntityToString() {
public void toIdConverterDoesNotMatchIfTargetTypeIsAssignableFromSource() throws Exception {

converter.setApplicationContext(initContextWithRepo());
assertMatches(false);

@SuppressWarnings("rawtypes")
Optional<ToIdConverter> toIdConverter = (Optional<ToIdConverter>) ReflectionTestUtils.getField(converter,
Expand Down

0 comments on commit 7af075f

Please sign in to comment.