Skip to content

Commit

Permalink
Refactor ConversionService to remove mutable operations from `Conve…
Browse files Browse the repository at this point in the history
…rsionService.SHARED` (#8156)

Co-authored-by: Graeme Rocher <graeme.rocher@gmail.com>
  • Loading branch information
dstepanov and graemerocher authored Oct 28, 2022
1 parent c1fcb71 commit 8b2d53b
Show file tree
Hide file tree
Showing 139 changed files with 976 additions and 600 deletions.
14 changes: 13 additions & 1 deletion aop/src/main/java/io/micronaut/aop/InterceptedMethod.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import io.micronaut.aop.internal.intercepted.InterceptedMethodUtil;
import io.micronaut.context.exceptions.ConfigurationException;
import io.micronaut.core.annotation.Experimental;
import io.micronaut.core.convert.ConversionService;
import io.micronaut.core.type.Argument;
import org.reactivestreams.Publisher;

Expand All @@ -40,7 +41,18 @@ public interface InterceptedMethod {
* @return The {@link InterceptedMethod}
*/
static InterceptedMethod of(MethodInvocationContext<?, ?> context) {
return InterceptedMethodUtil.of(context);
return of(context, ConversionService.SHARED);
}

/**
* Creates a new instance of intercept method supporting intercepting different reactive invocations.
*
* @param context The {@link MethodInvocationContext}
* @param conversionService The conversion service
* @return The {@link InterceptedMethod}
*/
static InterceptedMethod of(MethodInvocationContext<?, ?> context, ConversionService conversionService) {
return InterceptedMethodUtil.of(context, conversionService);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,13 @@
@Internal
@Experimental
class CompletionStageInterceptedMethod implements InterceptedMethod {
private final ConversionService<?> conversionService = ConversionService.SHARED;

private final MethodInvocationContext<?, ?> context;
private final ConversionService conversionService;
private final Argument<?> returnTypeValue;

CompletionStageInterceptedMethod(MethodInvocationContext<?, ?> context) {
CompletionStageInterceptedMethod(MethodInvocationContext<?, ?> context, ConversionService conversionService) {
this.context = context;
this.conversionService = conversionService;
this.returnTypeValue = context.getReturnType().asArgument().getFirstTypeVariable().orElse(Argument.OBJECT_ARGUMENT);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import io.micronaut.core.annotation.Internal;
import io.micronaut.core.annotation.NonNull;
import io.micronaut.core.annotation.Nullable;
import io.micronaut.core.convert.ConversionService;
import io.micronaut.core.type.ReturnType;

import java.util.List;
Expand All @@ -48,10 +49,13 @@ private InterceptedMethodUtil() {
/**
* Find possible {@link InterceptedMethod} implementation.
*
* @param context The {@link MethodInvocationContext}
* @param context The {@link MethodInvocationContext}
* @param conversionService The {@link ConversionService}
* @return The {@link InterceptedMethod}
* @since 4.0.0
*/
public static InterceptedMethod of(MethodInvocationContext<?, ?> context) {
@NonNull
public static InterceptedMethod of(@NonNull MethodInvocationContext<?, ?> context, @NonNull ConversionService conversionService) {
if (context.isSuspend()) {
KotlinInterceptedMethod kotlinInterceptedMethod = KotlinInterceptedMethod.of(context);
if (kotlinInterceptedMethod != null) {
Expand All @@ -65,9 +69,9 @@ public static InterceptedMethod of(MethodInvocationContext<?, ?> context) {
// Micro Optimization
return new SynchronousInterceptedMethod(context);
} else if (CompletionStage.class.isAssignableFrom(returnTypeClass) || Future.class.isAssignableFrom(returnTypeClass)) {
return new CompletionStageInterceptedMethod(context);
return new CompletionStageInterceptedMethod(context, conversionService);
} else if (PublisherInterceptedMethod.isConvertibleToPublisher(returnTypeClass)) {
return new PublisherInterceptedMethod(context);
return new PublisherInterceptedMethod(context, conversionService);
} else {
return new SynchronousInterceptedMethod(context);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,13 @@
@Experimental
class PublisherInterceptedMethod implements InterceptedMethod {
private static final boolean AVAILABLE = ClassUtils.isPresent("io.micronaut.core.async.publisher.Publishers", PublisherInterceptedMethod.class.getClassLoader());
private final ConversionService<?> conversionService = ConversionService.SHARED;

private final MethodInvocationContext<?, ?> context;
private final ConversionService conversionService;
private final Argument<?> returnTypeValue;

PublisherInterceptedMethod(MethodInvocationContext<?, ?> context) {
PublisherInterceptedMethod(MethodInvocationContext<?, ?> context, ConversionService conversionService) {
this.context = context;
this.conversionService = conversionService;
this.returnTypeValue = context.getReturnType().asArgument().getFirstTypeVariable().orElse(Argument.OBJECT_ARGUMENT);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

import io.micronaut.context.annotation.BootstrapContextCompatible;
import io.micronaut.core.annotation.Internal;
import io.micronaut.core.convert.ConversionService;
import io.micronaut.core.convert.MutableConversionService;
import io.micronaut.core.io.buffer.ByteBuffer;
import io.micronaut.core.io.buffer.ByteBufferFactory;
import io.netty.buffer.ByteBuf;
Expand Down Expand Up @@ -59,7 +59,7 @@ public NettyByteBufferFactory(ByteBufAllocator allocator) {
}

@PostConstruct
final void register(ConversionService<?> conversionService) {
final void register(MutableConversionService conversionService) {
conversionService.addConverter(ByteBuf.class, ByteBuffer.class, DEFAULT::wrap);
conversionService.addConverter(ByteBuffer.class, ByteBuf.class, byteBuffer -> {
if (byteBuffer instanceof NettyByteBuffer) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
import io.micronaut.core.annotation.Internal;
import io.micronaut.core.annotation.TypeHint;
import io.micronaut.core.convert.ConversionContext;
import io.micronaut.core.convert.ConversionService;
import io.micronaut.core.convert.MutableConversionService;
import io.micronaut.core.convert.TypeConverter;
import io.micronaut.core.convert.TypeConverterRegistrar;
import io.micronaut.core.convert.format.Format;
Expand Down Expand Up @@ -81,7 +81,7 @@ public class TimeConverterRegistrar implements TypeConverterRegistrar {
private static final int MILLIS = 3;

@Override
public void register(ConversionService<?> conversionService) {
public void register(MutableConversionService conversionService) {
final BiFunction<CharSequence, ConversionContext, Optional<Duration>> durationConverter = (object, context) -> {
String value = object.toString().trim();
if (value.startsWith("P")) {
Expand Down Expand Up @@ -179,7 +179,7 @@ public void register(ConversionService<?> conversionService) {
addTemporalToDateConverter(conversionService, LocalDateTime.class, ldt -> ldt.toInstant(ZoneOffset.UTC));
}

private <T extends TemporalAccessor> void addTemporalStringConverter(ConversionService<?> conversionService, Class<T> temporalType, DateTimeFormatter isoFormatter, TemporalQuery<T> query) {
private <T extends TemporalAccessor> void addTemporalStringConverter(MutableConversionService conversionService, Class<T> temporalType, DateTimeFormatter isoFormatter, TemporalQuery<T> query) {
conversionService.addConverter(CharSequence.class, temporalType, (CharSequence object, Class<T> targetType, ConversionContext context) -> {
if (StringUtils.isEmpty(object)) {
return Optional.empty();
Expand Down Expand Up @@ -213,7 +213,7 @@ private <T extends TemporalAccessor> void addTemporalStringConverter(ConversionS
});
}

private <T extends TemporalAccessor> void addTemporalToDateConverter(ConversionService<?> conversionService, Class<T> temporalType, Function<T, Instant> toInstant) {
private <T extends TemporalAccessor> void addTemporalToDateConverter(MutableConversionService conversionService, Class<T> temporalType, Function<T, Instant> toInstant) {
conversionService.addConverter(temporalType, Date.class, (T object, Class<Date> targetType, ConversionContext context) -> Optional.of(Date.from(toInstant.apply(object))));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public class ScheduledMethodProcessor implements ExecutableMethodProcessor<Sched
private static final String MEMBER_SCHEDULER = "scheduler";

private final BeanContext beanContext;
private final ConversionService<?> conversionService;
private final ConversionService conversionService;
private final Queue<ScheduledFuture<?>> scheduledTasks = new ConcurrentLinkedDeque<>();
private final TaskExceptionHandler<?, ?> taskExceptionHandler;

Expand All @@ -76,7 +76,7 @@ public class ScheduledMethodProcessor implements ExecutableMethodProcessor<Sched
* @param taskExceptionHandler The default task exception handler
*/
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
public ScheduledMethodProcessor(BeanContext beanContext, Optional<ConversionService<?>> conversionService, TaskExceptionHandler<?, ?> taskExceptionHandler) {
public ScheduledMethodProcessor(BeanContext beanContext, Optional<ConversionService> conversionService, TaskExceptionHandler<?, ?> taskExceptionHandler) {
this.beanContext = beanContext;
this.conversionService = conversionService.orElse(ConversionService.SHARED);
this.taskExceptionHandler = taskExceptionHandler;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,27 +13,25 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.micronaut.runtime.converters.reactive;
package io.micronaut.core.async.converters;

import io.micronaut.context.annotation.Requires;
import io.micronaut.core.annotation.Internal;
import io.micronaut.core.async.publisher.Publishers;
import io.micronaut.core.convert.ConversionService;
import io.micronaut.core.convert.MutableConversionService;
import io.micronaut.core.convert.TypeConverterRegistrar;
import org.reactivestreams.Publisher;
import jakarta.inject.Singleton;

/**
* Registers converters for Reactive types such as {@link Publisher}.
*
* @author Sergio del Amo
* @since 3.0.0
*/
@Singleton
@Requires(classes = Publishers.class)
@Internal
public class ReactiveTypeConverterRegistrar implements TypeConverterRegistrar {

@Override
public void register(ConversionService<?> conversionService) {
public void register(MutableConversionService conversionService) {
conversionService.addConverter(Object.class, Publisher.class, obj -> {
if (obj instanceof Publisher) {
return (Publisher) obj;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
io.micronaut.core.async.converters.ReactiveTypeConverterRegistrar
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,14 @@
public abstract class AbstractAnnotatedArgumentBinder<A extends Annotation, T, S> implements AnnotatedArgumentBinder<A, T, S> {

private static final String DEFAULT_VALUE_MEMBER = "defaultValue";
private final ConversionService<?> conversionService;
protected final ConversionService conversionService;

/**
* Constructor.
*
* @param conversionService conversionService
*/
protected AbstractAnnotatedArgumentBinder(ConversionService<?> conversionService) {
protected AbstractAnnotatedArgumentBinder(ConversionService conversionService) {
this.conversionService = conversionService;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,49 +15,24 @@
*/
package io.micronaut.core.convert;

import io.micronaut.core.annotation.Nullable;
import io.micronaut.core.convert.exceptions.ConversionErrorException;
import io.micronaut.core.type.Argument;
import io.micronaut.core.annotation.Nullable;

import java.util.Optional;
import java.util.function.Function;

/**
* A service for allowing conversion from one type to another.
*
* @param <Impl> The type
* @author Graeme Rocher
* @since 1.0
*/
public interface ConversionService<Impl extends ConversionService> {
public interface ConversionService {

/**
* The default shared conversion service.
*/
ConversionService<?> SHARED = new DefaultConversionService();

/**
* Adds a type converter.
*
* @param sourceType The source type
* @param targetType The target type
* @param typeConverter The type converter
* @param <S> The source generic type
* @param <T> The target generic type
* @return This conversion service
*/
<S, T> Impl addConverter(Class<S> sourceType, Class<T> targetType, Function<S, T> typeConverter);

/**
* Adds a type converter.
*
* @param sourceType The source type
* @param targetType The target type
* @param typeConverter The type converter
* @param <S> The source generic type
* @param <T> The target generic type
* @return This conversion service
*/
<S, T> Impl addConverter(Class<S> sourceType, Class<T> targetType, TypeConverter<S, T> typeConverter);
ConversionService SHARED = new DefaultMutableConversionService();

/**
* Attempts to convert the given object to the given target type. If conversion fails or is not possible an empty {@link Optional} is returned.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright 2017-2022 original 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 io.micronaut.core.convert;

import io.micronaut.core.annotation.NonNull;

/**
* Interface used when the component requires to set up bean context's {@link ConversionService}.
*
* @author Denis Stepanov
* @since 4.0.0
*/
public interface ConversionServiceAware {

/**
* Sets the conversion service.
*
* @param conversionService The conversion service
*/
void setConversionService(@NonNull ConversionService conversionService);

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2017-2020 original authors
* Copyright 2017-2022 original authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -13,10 +13,24 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.micronaut.core.convert;

import io.micronaut.core.annotation.NonNull;

/**
* Contains classes for reactive streams conversion.
* Interface for a component to provide the access to its {@link ConversionService}.
*
* @author Sergio del Amo
* @since 3.0.0
* @author Denis Stepanov
* @since 4.0.0
*/
package io.micronaut.runtime.converters.reactive;
public interface ConversionServiceProvider {

/**
* Provides the conversion service.
*
* @return the conversion service
*/
@NonNull
ConversionService getConversionService();

}
Loading

0 comments on commit 8b2d53b

Please sign in to comment.