From 08506b51473768e8409d69fe76fa68bd194b314e Mon Sep 17 00:00:00 2001 From: Denis Stepanov Date: Tue, 5 Jul 2022 10:37:33 +0200 Subject: [PATCH 1/5] Reset shared `ConversionService` instance on context restart --- .../netty/ByteBufConvertersRegistrar.java | 45 +++++++++++++ .../buffer/netty/NettyByteBufferFactory.java | 11 --- ...ronaut.core.convert.TypeConverterRegistrar | 1 + .../convert/DefaultConversionService.java | 40 ++++++++++- .../java/io/micronaut/http/MediaType.java | 19 +++--- .../http/MediaTypeConvertersRegistrar.java | 42 ++++++++++++ ...ronaut.core.convert.TypeConverterRegistrar | 1 + .../micronaut/context/DefaultBeanContext.java | 5 +- .../AnnotationConvertersRegistrar.java | 67 +++++++++++++++++++ .../annotation/DefaultAnnotationMetadata.java | 60 +++++++---------- ...ronaut.core.convert.TypeConverterRegistrar | 1 + .../ConversionServiceIsResetSpec.groovy | 64 ++++++++++++++++++ 12 files changed, 300 insertions(+), 56 deletions(-) create mode 100644 buffer-netty/src/main/java/io/micronaut/buffer/netty/ByteBufConvertersRegistrar.java create mode 100644 buffer-netty/src/main/resources/META-INF/services/io.micronaut.core.convert.TypeConverterRegistrar create mode 100644 http/src/main/java/io/micronaut/http/MediaTypeConvertersRegistrar.java create mode 100644 http/src/main/resources/META-INF/services/io.micronaut.core.convert.TypeConverterRegistrar create mode 100644 inject/src/main/java/io/micronaut/inject/annotation/AnnotationConvertersRegistrar.java create mode 100644 inject/src/main/resources/META-INF/services/io.micronaut.core.convert.TypeConverterRegistrar create mode 100644 runtime/src/test/groovy/io/micronaut/runtime/ConversionServiceIsResetSpec.groovy diff --git a/buffer-netty/src/main/java/io/micronaut/buffer/netty/ByteBufConvertersRegistrar.java b/buffer-netty/src/main/java/io/micronaut/buffer/netty/ByteBufConvertersRegistrar.java new file mode 100644 index 00000000000..151a0b36b6e --- /dev/null +++ b/buffer-netty/src/main/java/io/micronaut/buffer/netty/ByteBufConvertersRegistrar.java @@ -0,0 +1,45 @@ +/* + * 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.buffer.netty; + +import io.micronaut.core.annotation.Internal; +import io.micronaut.core.convert.ConversionService; +import io.micronaut.core.convert.TypeConverterRegistrar; +import io.micronaut.core.io.buffer.ByteBuffer; +import io.netty.buffer.ByteBuf; + +import static io.micronaut.buffer.netty.NettyByteBufferFactory.DEFAULT; + +/** + * The byte buffer converters registrar. + * + * @author Denis Stepanov + * @since 3.6.0 + */ +@Internal +public final class ByteBufConvertersRegistrar implements TypeConverterRegistrar { + + @Override + public void register(ConversionService conversionService) { + conversionService.addConverter(ByteBuf.class, ByteBuffer.class, DEFAULT::wrap); + conversionService.addConverter(ByteBuffer.class, ByteBuf.class, byteBuffer -> { + if (byteBuffer instanceof NettyByteBuffer) { + return (ByteBuf) byteBuffer.asNativeBuffer(); + } + throw new IllegalArgumentException("Unconvertible buffer type " + byteBuffer); + }); + } +} diff --git a/buffer-netty/src/main/java/io/micronaut/buffer/netty/NettyByteBufferFactory.java b/buffer-netty/src/main/java/io/micronaut/buffer/netty/NettyByteBufferFactory.java index 656503f3d57..c606ffa5b76 100644 --- a/buffer-netty/src/main/java/io/micronaut/buffer/netty/NettyByteBufferFactory.java +++ b/buffer-netty/src/main/java/io/micronaut/buffer/netty/NettyByteBufferFactory.java @@ -17,7 +17,6 @@ import io.micronaut.context.annotation.BootstrapContextCompatible; import io.micronaut.core.annotation.Internal; -import io.micronaut.core.convert.ConversionService; import io.micronaut.core.io.buffer.ByteBuffer; import io.micronaut.core.io.buffer.ByteBufferFactory; import io.netty.buffer.ByteBuf; @@ -43,16 +42,6 @@ public class NettyByteBufferFactory implements ByteBufferFactory { - if (byteBuffer instanceof NettyByteBuffer) { - return (ByteBuf) byteBuffer.asNativeBuffer(); - } - throw new IllegalArgumentException("Unconvertible buffer type " + byteBuffer); - }); - } - /** * Default constructor. */ diff --git a/buffer-netty/src/main/resources/META-INF/services/io.micronaut.core.convert.TypeConverterRegistrar b/buffer-netty/src/main/resources/META-INF/services/io.micronaut.core.convert.TypeConverterRegistrar new file mode 100644 index 00000000000..4ce685673c7 --- /dev/null +++ b/buffer-netty/src/main/resources/META-INF/services/io.micronaut.core.convert.TypeConverterRegistrar @@ -0,0 +1 @@ +io.micronaut.buffer.netty.ByteBufConvertersRegistrar diff --git a/core/src/main/java/io/micronaut/core/convert/DefaultConversionService.java b/core/src/main/java/io/micronaut/core/convert/DefaultConversionService.java index 39d32e5c937..dec55ff153c 100644 --- a/core/src/main/java/io/micronaut/core/convert/DefaultConversionService.java +++ b/core/src/main/java/io/micronaut/core/convert/DefaultConversionService.java @@ -17,6 +17,7 @@ import io.micronaut.core.annotation.AnnotationClassValue; import io.micronaut.core.annotation.AnnotationMetadata; +import io.micronaut.core.annotation.Internal; import io.micronaut.core.convert.converters.MultiValuesConverterFactory; import io.micronaut.core.convert.exceptions.ConversionErrorException; import io.micronaut.core.convert.format.Format; @@ -26,6 +27,7 @@ import io.micronaut.core.convert.value.ConvertibleValuesMap; import io.micronaut.core.io.IOUtils; import io.micronaut.core.io.buffer.ReferenceCounted; +import io.micronaut.core.io.service.SoftServiceLoader; import io.micronaut.core.naming.NameUtils; import io.micronaut.core.reflect.ClassUtils; import io.micronaut.core.reflect.ReflectionUtils; @@ -56,8 +58,26 @@ import java.nio.file.Paths; import java.text.ParseException; import java.text.SimpleDateFormat; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Currency; +import java.util.Date; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Optional; +import java.util.OptionalInt; +import java.util.OptionalLong; +import java.util.Properties; +import java.util.StringJoiner; +import java.util.TimeZone; +import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ForkJoinPool; import java.util.function.Function; /** @@ -176,6 +196,19 @@ public DefaultConversionService addConverter(Class sourceType, Class registrars = new ArrayList<>(); + ForkJoinPool forkJoinPool = new ForkJoinPool(); // Create a custom ForkJoinPool to prevent deadlock + SoftServiceLoader.load(TypeConverterRegistrar.class).collectAll(registrars, null, forkJoinPool); + forkJoinPool.shutdown(); } /** diff --git a/http/src/main/java/io/micronaut/http/MediaType.java b/http/src/main/java/io/micronaut/http/MediaType.java index 386e2d8e53f..a44b3c75d45 100644 --- a/http/src/main/java/io/micronaut/http/MediaType.java +++ b/http/src/main/java/io/micronaut/http/MediaType.java @@ -19,7 +19,6 @@ import io.micronaut.core.annotation.NonNull; import io.micronaut.core.annotation.TypeHint; import io.micronaut.core.convert.ArgumentConversionContext; -import io.micronaut.core.convert.ConversionService; import io.micronaut.core.convert.ImmutableArgumentConversionContext; import io.micronaut.core.naming.NameUtils; import io.micronaut.core.type.Argument; @@ -37,7 +36,16 @@ import java.math.BigDecimal; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Optional; import java.util.regex.Pattern; /** @@ -394,13 +402,6 @@ public class MediaType implements CharSequence { private BigDecimal qualityNumberField = BigDecimal.ONE; static { - ConversionService.SHARED.addConverter(CharSequence.class, MediaType.class, charSequence -> { - if (StringUtils.isNotEmpty(charSequence)) { - return of(charSequence.toString()); - } - return null; - } - ); textTypePatterns.add(Pattern.compile("^text/.*$")); textTypePatterns.add(Pattern.compile("^.*\\+json$")); textTypePatterns.add(Pattern.compile("^.*\\+text$")); diff --git a/http/src/main/java/io/micronaut/http/MediaTypeConvertersRegistrar.java b/http/src/main/java/io/micronaut/http/MediaTypeConvertersRegistrar.java new file mode 100644 index 00000000000..5d4ed613bef --- /dev/null +++ b/http/src/main/java/io/micronaut/http/MediaTypeConvertersRegistrar.java @@ -0,0 +1,42 @@ +/* + * 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.http; + +import io.micronaut.core.annotation.Internal; +import io.micronaut.core.convert.ConversionService; +import io.micronaut.core.convert.TypeConverterRegistrar; +import io.micronaut.core.util.StringUtils; + +/** + * The media type converters registrar. + * + * @author Denis Stepanov + * @since 3.6.0 + */ +@Internal +public final class MediaTypeConvertersRegistrar implements TypeConverterRegistrar { + + @Override + public void register(ConversionService conversionService) { + conversionService.addConverter(CharSequence.class, MediaType.class, charSequence -> { + if (StringUtils.isNotEmpty(charSequence)) { + return MediaType.of(charSequence.toString()); + } + return null; + } + ); + } +} diff --git a/http/src/main/resources/META-INF/services/io.micronaut.core.convert.TypeConverterRegistrar b/http/src/main/resources/META-INF/services/io.micronaut.core.convert.TypeConverterRegistrar new file mode 100644 index 00000000000..60730083bd7 --- /dev/null +++ b/http/src/main/resources/META-INF/services/io.micronaut.core.convert.TypeConverterRegistrar @@ -0,0 +1 @@ +io.micronaut.http.MediaTypeConvertersRegistrar diff --git a/inject/src/main/java/io/micronaut/context/DefaultBeanContext.java b/inject/src/main/java/io/micronaut/context/DefaultBeanContext.java index dbdefd18cfb..d940f61e467 100644 --- a/inject/src/main/java/io/micronaut/context/DefaultBeanContext.java +++ b/inject/src/main/java/io/micronaut/context/DefaultBeanContext.java @@ -65,6 +65,7 @@ import io.micronaut.core.annotation.Order; import io.micronaut.core.annotation.UsedByGeneratedCode; import io.micronaut.core.convert.ConversionService; +import io.micronaut.core.convert.DefaultConversionService; import io.micronaut.core.convert.TypeConverter; import io.micronaut.core.convert.TypeConverterRegistrar; import io.micronaut.core.convert.value.MutableConvertibleValues; @@ -333,6 +334,8 @@ public synchronized BeanContext start() { if (!isRunning()) { if (initializing.compareAndSet(false, true)) { + // Reset possibly modified shared context + ((DefaultConversionService) ConversionService.SHARED).reset(); if (LOG.isDebugEnabled()) { LOG.debug("Starting BeanContext"); } @@ -419,7 +422,7 @@ public synchronized BeanContext stop() { beanCreationEventListeners = null; beanPreDestroyEventListeners = null; beanDestroyedEventListeners = null; - + ((DefaultConversionService) ConversionService.SHARED).reset(); terminating.set(false); running.set(false); } diff --git a/inject/src/main/java/io/micronaut/inject/annotation/AnnotationConvertersRegistrar.java b/inject/src/main/java/io/micronaut/inject/annotation/AnnotationConvertersRegistrar.java new file mode 100644 index 00000000000..2805d19504a --- /dev/null +++ b/inject/src/main/java/io/micronaut/inject/annotation/AnnotationConvertersRegistrar.java @@ -0,0 +1,67 @@ +/* + * 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.inject.annotation; + +import io.micronaut.core.annotation.Internal; +import io.micronaut.core.convert.ConversionService; +import io.micronaut.core.convert.TypeConverterRegistrar; +import io.micronaut.core.reflect.ClassUtils; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Array; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +/** + * Registers annotation converters. + * + * @author Denis Stepanov + * @since 3.6.0 + */ +@Internal +public final class AnnotationConvertersRegistrar implements TypeConverterRegistrar { + + @Override + public void register(ConversionService conversionService) { + conversionService.addConverter(io.micronaut.core.annotation.AnnotationValue.class, Annotation.class, (object, targetType, context) -> { + Optional annotationClass = ClassUtils.forName(object.getAnnotationName(), targetType.getClassLoader()); + return annotationClass.map(aClass -> AnnotationMetadataSupport.buildAnnotation(aClass, object)); + }); + + conversionService.addConverter(io.micronaut.core.annotation.AnnotationValue[].class, Object[].class, (object, targetType, context) -> { + List result = new ArrayList(); + Class annotationClass = null; + for (io.micronaut.core.annotation.AnnotationValue annotationValue : object) { + if (annotationClass == null) { + // all annotations will be on the same type + Optional aClass = ClassUtils.forName(annotationValue.getAnnotationName(), targetType.getClassLoader()); + if (!aClass.isPresent()) { + break; + } + annotationClass = aClass.get(); + } + Annotation annotation = AnnotationMetadataSupport.buildAnnotation(annotationClass, annotationValue); + result.add(annotation); + } + if (!result.isEmpty()) { + return Optional.of(result.toArray((Object[]) Array.newInstance(annotationClass, result.size()))); + } + return Optional.empty(); + }); + } + +} diff --git a/inject/src/main/java/io/micronaut/inject/annotation/DefaultAnnotationMetadata.java b/inject/src/main/java/io/micronaut/inject/annotation/DefaultAnnotationMetadata.java index 6b569092ed6..f929934e704 100644 --- a/inject/src/main/java/io/micronaut/inject/annotation/DefaultAnnotationMetadata.java +++ b/inject/src/main/java/io/micronaut/inject/annotation/DefaultAnnotationMetadata.java @@ -16,25 +16,45 @@ package io.micronaut.inject.annotation; import io.micronaut.context.exceptions.ConfigurationException; -import io.micronaut.core.annotation.*; +import io.micronaut.core.annotation.AnnotationClassValue; +import io.micronaut.core.annotation.AnnotationMetadata; +import io.micronaut.core.annotation.AnnotationUtil; +import io.micronaut.core.annotation.AnnotationValue; +import io.micronaut.core.annotation.Internal; +import io.micronaut.core.annotation.NonNull; +import io.micronaut.core.annotation.Nullable; +import io.micronaut.core.annotation.UsedByGeneratedCode; import io.micronaut.core.convert.ConversionService; -import io.micronaut.core.reflect.ClassUtils; import io.micronaut.core.reflect.ReflectionUtils; import io.micronaut.core.type.Argument; import io.micronaut.core.util.ArgumentUtils; import io.micronaut.core.util.CollectionUtils; import io.micronaut.core.util.StringUtils; import io.micronaut.core.value.OptionalValues; - -import io.micronaut.core.annotation.NonNull; -import io.micronaut.core.annotation.Nullable; import io.micronaut.inject.ast.ClassElement; import java.lang.annotation.Annotation; import java.lang.annotation.Repeatable; import java.lang.annotation.RetentionPolicy; import java.lang.reflect.Array; -import java.util.*; +import java.util.AbstractMap; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Optional; +import java.util.OptionalDouble; +import java.util.OptionalInt; +import java.util.OptionalLong; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; import java.util.function.Predicate; @@ -53,34 +73,6 @@ @Internal public class DefaultAnnotationMetadata extends AbstractAnnotationMetadata implements AnnotationMetadata, Cloneable, EnvironmentAnnotationMetadata { - static { - ConversionService.SHARED.addConverter(io.micronaut.core.annotation.AnnotationValue.class, Annotation.class, (object, targetType, context) -> { - Optional annotationClass = ClassUtils.forName(object.getAnnotationName(), targetType.getClassLoader()); - return annotationClass.map(aClass -> AnnotationMetadataSupport.buildAnnotation(aClass, object)); - }); - - ConversionService.SHARED.addConverter(io.micronaut.core.annotation.AnnotationValue[].class, Object[].class, (object, targetType, context) -> { - List result = new ArrayList(); - Class annotationClass = null; - for (io.micronaut.core.annotation.AnnotationValue annotationValue : object) { - if (annotationClass == null) { - // all annotations will be on the same type - Optional aClass = ClassUtils.forName(annotationValue.getAnnotationName(), targetType.getClassLoader()); - if (!aClass.isPresent()) { - break; - } - annotationClass = aClass.get(); - } - Annotation annotation = AnnotationMetadataSupport.buildAnnotation(annotationClass, annotationValue); - result.add(annotation); - } - if (!result.isEmpty()) { - return Optional.of(result.toArray((Object[]) Array.newInstance(annotationClass, result.size()))); - } - return Optional.empty(); - }); - } - @Nullable Map> declaredAnnotations; @Nullable diff --git a/inject/src/main/resources/META-INF/services/io.micronaut.core.convert.TypeConverterRegistrar b/inject/src/main/resources/META-INF/services/io.micronaut.core.convert.TypeConverterRegistrar new file mode 100644 index 00000000000..c99926686fd --- /dev/null +++ b/inject/src/main/resources/META-INF/services/io.micronaut.core.convert.TypeConverterRegistrar @@ -0,0 +1 @@ +io.micronaut.inject.annotation.AnnotationConvertersRegistrar diff --git a/runtime/src/test/groovy/io/micronaut/runtime/ConversionServiceIsResetSpec.groovy b/runtime/src/test/groovy/io/micronaut/runtime/ConversionServiceIsResetSpec.groovy new file mode 100644 index 00000000000..7bd5ee40bc8 --- /dev/null +++ b/runtime/src/test/groovy/io/micronaut/runtime/ConversionServiceIsResetSpec.groovy @@ -0,0 +1,64 @@ +/* + * Copyright 2017-2019 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 + * + * 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 io.micronaut.runtime + +import io.micronaut.context.ApplicationContext +import io.micronaut.core.convert.ConversionContext +import io.micronaut.core.convert.ConversionService +import io.micronaut.core.convert.TypeConverter +import spock.lang.Specification + +class ConversionServiceIsResetSpec extends Specification { + + void "test ConversionService is reset on stop/start"() { + given: + ApplicationContext ctx = ApplicationContext.run() + TypeConverter typeConverter = new TypeConverter() { + @Override + Optional convert(A object, Class targetType, ConversionContext context) { + return Optional.of(new B()) + } + } + ctx.getBean(ConversionService).addConverter(A, B, typeConverter) + + when: + def result = ctx.getBean(ConversionService).convert(new A(), B) + + then: + result.isPresent() + + when: + ctx.stop() + ctx.start() + then: + !ctx.getBean(ConversionService).convert(new A(), B).isPresent() + and: + try (ApplicationContext ctx2 = ApplicationContext.run()) { + assert !ctx2.getBean(ConversionService).convert(new A(), B).isPresent() + } + cleanup: + ctx.close() + } + +} + +class A { + +} + +class B { + +} From 66f88cf014515afa6d4d93ada2bbc8a2b1562349 Mon Sep 17 00:00:00 2001 From: Denis Stepanov Date: Fri, 8 Jul 2022 09:54:18 +0200 Subject: [PATCH 2/5] User parallel Service loader --- .../convert/DefaultConversionService.java | 7 ++++++- .../core/io/service/ServiceScanner.java | 5 +++++ .../core/io/service/SoftServiceLoader.java | 21 ++++++++++++++++--- 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/io/micronaut/core/convert/DefaultConversionService.java b/core/src/main/java/io/micronaut/core/convert/DefaultConversionService.java index dec55ff153c..d381dae4625 100644 --- a/core/src/main/java/io/micronaut/core/convert/DefaultConversionService.java +++ b/core/src/main/java/io/micronaut/core/convert/DefaultConversionService.java @@ -960,7 +960,12 @@ protected void registerDefaultConverters() { Collection registrars = new ArrayList<>(); ForkJoinPool forkJoinPool = new ForkJoinPool(); // Create a custom ForkJoinPool to prevent deadlock - SoftServiceLoader.load(TypeConverterRegistrar.class).collectAll(registrars, null, forkJoinPool); + SoftServiceLoader.load(TypeConverterRegistrar.class) + .withForkJoinPool(forkJoinPool) + .collectAll(registrars); + for (TypeConverterRegistrar registrar : registrars) { + registrar.register(this); + } forkJoinPool.shutdown(); } diff --git a/core/src/main/java/io/micronaut/core/io/service/ServiceScanner.java b/core/src/main/java/io/micronaut/core/io/service/ServiceScanner.java index 73ca1cfac9d..8127ce042a1 100644 --- a/core/src/main/java/io/micronaut/core/io/service/ServiceScanner.java +++ b/core/src/main/java/io/micronaut/core/io/service/ServiceScanner.java @@ -152,8 +152,13 @@ private void findMicronautMetaServiceConfigs(BiConsumer consumer) t @SuppressWarnings("java:S1948") final class DefaultServiceCollector extends RecursiveActionValuesCollector implements SoftServiceLoader.ServiceCollector { + private final ForkJoinPool forkJoinPool; private final List> tasks = new ArrayList<>(); + DefaultServiceCollector(ForkJoinPool forkJoinPool) { + this.forkJoinPool = forkJoinPool; + } + @Override protected void compute() { try { diff --git a/core/src/main/java/io/micronaut/core/io/service/SoftServiceLoader.java b/core/src/main/java/io/micronaut/core/io/service/SoftServiceLoader.java index d0c86811d69..2cbdac6c5f4 100644 --- a/core/src/main/java/io/micronaut/core/io/service/SoftServiceLoader.java +++ b/core/src/main/java/io/micronaut/core/io/service/SoftServiceLoader.java @@ -29,6 +29,7 @@ import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.concurrent.ForkJoinPool; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; @@ -57,6 +58,7 @@ public final class SoftServiceLoader implements Iterable private Collection> servicesForIterator; private final Predicate condition; private boolean allowFork = true; + private ForkJoinPool forkJoinPool = ForkJoinPool.commonPool(); private SoftServiceLoader(Class serviceType, ClassLoader classLoader) { this(serviceType, classLoader, (String name) -> true); @@ -112,6 +114,11 @@ public SoftServiceLoader disableFork() { return this; } + public SoftServiceLoader withForkJoinPool(ForkJoinPool forkJoinPool) { + this.forkJoinPool = forkJoinPool; + return this; + } + /** * @return Return the first such instance */ @@ -194,7 +201,7 @@ private void collectDynamicServices( throw new ServiceLoadingException(e); } return null; - }); + }, forkJoinPool); collector.collect(values, allowFork); } @@ -254,7 +261,7 @@ public Iterator> iterator() { } catch (NoClassDefFoundError | ClassNotFoundException e) { return createService(name, null); } - }).collect(serviceDefinitions, false); + }, forkJoinPool).collect(serviceDefinitions, false); this.servicesForIterator = serviceDefinitions; } } @@ -284,11 +291,19 @@ private ServiceDefinition createService(String name, Class loadedClass) { return new DefaultServiceDefinition<>(name, loadedClass); } + public static ServiceCollector newCollector(String serviceName, + Predicate lineCondition, + ClassLoader classLoader, + Function transformer, + ForkJoinPool forkJoinPool) { + return new ServiceScanner<>(classLoader, serviceName, lineCondition, transformer).new DefaultServiceCollector(forkJoinPool); + } + public static ServiceCollector newCollector(String serviceName, Predicate lineCondition, ClassLoader classLoader, Function transformer) { - return new ServiceScanner<>(classLoader, serviceName, lineCondition, transformer).new DefaultServiceCollector(); + return new ServiceScanner<>(classLoader, serviceName, lineCondition, transformer).new DefaultServiceCollector(ForkJoinPool.commonPool()); } /** From d45422bfa6dc8c2ebdca401fe78b36728982f6bb Mon Sep 17 00:00:00 2001 From: Denis Stepanov Date: Fri, 8 Jul 2022 10:26:55 +0200 Subject: [PATCH 3/5] Ignore `test default allocator configured` --- .../micronaut/http/netty/allocator/DefaultAllocatorSpec.groovy | 2 ++ 1 file changed, 2 insertions(+) diff --git a/http-netty/src/test/groovy/io/micronaut/http/netty/allocator/DefaultAllocatorSpec.groovy b/http-netty/src/test/groovy/io/micronaut/http/netty/allocator/DefaultAllocatorSpec.groovy index 185ff8ca54b..0fbbf3bfa2b 100644 --- a/http-netty/src/test/groovy/io/micronaut/http/netty/allocator/DefaultAllocatorSpec.groovy +++ b/http-netty/src/test/groovy/io/micronaut/http/netty/allocator/DefaultAllocatorSpec.groovy @@ -2,6 +2,7 @@ package io.micronaut.http.netty.allocator import io.micronaut.context.ApplicationContext import io.netty.buffer.PooledByteBufAllocator +import spock.lang.Ignore import spock.lang.Specification import spock.lang.Stepwise import spock.lang.Unroll @@ -37,6 +38,7 @@ class DefaultAllocatorSpec extends Specification { 'maxCachedByteBuffersPerChunk' | 20 } + @Ignore void "test default allocator configured"() { given: def context = ApplicationContext.run( From 74699c4ac6890b5eeca0a815fe8db89d548f5e5b Mon Sep 17 00:00:00 2001 From: Denis Stepanov Date: Fri, 8 Jul 2022 11:48:22 +0200 Subject: [PATCH 4/5] Remove forking --- .../convert/DefaultConversionService.java | 5 +---- .../core/io/service/ServiceScanner.java | 5 ----- .../core/io/service/SoftServiceLoader.java | 21 +++---------------- 3 files changed, 4 insertions(+), 27 deletions(-) diff --git a/core/src/main/java/io/micronaut/core/convert/DefaultConversionService.java b/core/src/main/java/io/micronaut/core/convert/DefaultConversionService.java index d381dae4625..fee4987e8a7 100644 --- a/core/src/main/java/io/micronaut/core/convert/DefaultConversionService.java +++ b/core/src/main/java/io/micronaut/core/convert/DefaultConversionService.java @@ -77,7 +77,6 @@ import java.util.TimeZone; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ForkJoinPool; import java.util.function.Function; /** @@ -959,14 +958,12 @@ protected void registerDefaultConverters() { new MultiValuesConverterFactory.ObjectToMultiValuesConverter(this)); Collection registrars = new ArrayList<>(); - ForkJoinPool forkJoinPool = new ForkJoinPool(); // Create a custom ForkJoinPool to prevent deadlock SoftServiceLoader.load(TypeConverterRegistrar.class) - .withForkJoinPool(forkJoinPool) + .disableFork() .collectAll(registrars); for (TypeConverterRegistrar registrar : registrars) { registrar.register(this); } - forkJoinPool.shutdown(); } /** diff --git a/core/src/main/java/io/micronaut/core/io/service/ServiceScanner.java b/core/src/main/java/io/micronaut/core/io/service/ServiceScanner.java index 8127ce042a1..73ca1cfac9d 100644 --- a/core/src/main/java/io/micronaut/core/io/service/ServiceScanner.java +++ b/core/src/main/java/io/micronaut/core/io/service/ServiceScanner.java @@ -152,13 +152,8 @@ private void findMicronautMetaServiceConfigs(BiConsumer consumer) t @SuppressWarnings("java:S1948") final class DefaultServiceCollector extends RecursiveActionValuesCollector implements SoftServiceLoader.ServiceCollector { - private final ForkJoinPool forkJoinPool; private final List> tasks = new ArrayList<>(); - DefaultServiceCollector(ForkJoinPool forkJoinPool) { - this.forkJoinPool = forkJoinPool; - } - @Override protected void compute() { try { diff --git a/core/src/main/java/io/micronaut/core/io/service/SoftServiceLoader.java b/core/src/main/java/io/micronaut/core/io/service/SoftServiceLoader.java index 2cbdac6c5f4..d0c86811d69 100644 --- a/core/src/main/java/io/micronaut/core/io/service/SoftServiceLoader.java +++ b/core/src/main/java/io/micronaut/core/io/service/SoftServiceLoader.java @@ -29,7 +29,6 @@ import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.concurrent.ForkJoinPool; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; @@ -58,7 +57,6 @@ public final class SoftServiceLoader implements Iterable private Collection> servicesForIterator; private final Predicate condition; private boolean allowFork = true; - private ForkJoinPool forkJoinPool = ForkJoinPool.commonPool(); private SoftServiceLoader(Class serviceType, ClassLoader classLoader) { this(serviceType, classLoader, (String name) -> true); @@ -114,11 +112,6 @@ public SoftServiceLoader disableFork() { return this; } - public SoftServiceLoader withForkJoinPool(ForkJoinPool forkJoinPool) { - this.forkJoinPool = forkJoinPool; - return this; - } - /** * @return Return the first such instance */ @@ -201,7 +194,7 @@ private void collectDynamicServices( throw new ServiceLoadingException(e); } return null; - }, forkJoinPool); + }); collector.collect(values, allowFork); } @@ -261,7 +254,7 @@ public Iterator> iterator() { } catch (NoClassDefFoundError | ClassNotFoundException e) { return createService(name, null); } - }, forkJoinPool).collect(serviceDefinitions, false); + }).collect(serviceDefinitions, false); this.servicesForIterator = serviceDefinitions; } } @@ -291,19 +284,11 @@ private ServiceDefinition createService(String name, Class loadedClass) { return new DefaultServiceDefinition<>(name, loadedClass); } - public static ServiceCollector newCollector(String serviceName, - Predicate lineCondition, - ClassLoader classLoader, - Function transformer, - ForkJoinPool forkJoinPool) { - return new ServiceScanner<>(classLoader, serviceName, lineCondition, transformer).new DefaultServiceCollector(forkJoinPool); - } - public static ServiceCollector newCollector(String serviceName, Predicate lineCondition, ClassLoader classLoader, Function transformer) { - return new ServiceScanner<>(classLoader, serviceName, lineCondition, transformer).new DefaultServiceCollector(ForkJoinPool.commonPool()); + return new ServiceScanner<>(classLoader, serviceName, lineCondition, transformer).new DefaultServiceCollector(); } /** From 4ca4d24f1ae063db5049efb7fb7e08dab9287fb6 Mon Sep 17 00:00:00 2001 From: Denis Stepanov Date: Fri, 8 Jul 2022 12:15:18 +0200 Subject: [PATCH 5/5] Fix test --- .../netty/ByteBufConvertersRegistrar.java | 45 ------------------- .../buffer/netty/NettyByteBufferFactory.java | 13 ++++++ ...ronaut.core.convert.TypeConverterRegistrar | 1 - .../allocator/DefaultAllocatorSpec.groovy | 2 - 4 files changed, 13 insertions(+), 48 deletions(-) delete mode 100644 buffer-netty/src/main/java/io/micronaut/buffer/netty/ByteBufConvertersRegistrar.java delete mode 100644 buffer-netty/src/main/resources/META-INF/services/io.micronaut.core.convert.TypeConverterRegistrar diff --git a/buffer-netty/src/main/java/io/micronaut/buffer/netty/ByteBufConvertersRegistrar.java b/buffer-netty/src/main/java/io/micronaut/buffer/netty/ByteBufConvertersRegistrar.java deleted file mode 100644 index 151a0b36b6e..00000000000 --- a/buffer-netty/src/main/java/io/micronaut/buffer/netty/ByteBufConvertersRegistrar.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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.buffer.netty; - -import io.micronaut.core.annotation.Internal; -import io.micronaut.core.convert.ConversionService; -import io.micronaut.core.convert.TypeConverterRegistrar; -import io.micronaut.core.io.buffer.ByteBuffer; -import io.netty.buffer.ByteBuf; - -import static io.micronaut.buffer.netty.NettyByteBufferFactory.DEFAULT; - -/** - * The byte buffer converters registrar. - * - * @author Denis Stepanov - * @since 3.6.0 - */ -@Internal -public final class ByteBufConvertersRegistrar implements TypeConverterRegistrar { - - @Override - public void register(ConversionService conversionService) { - conversionService.addConverter(ByteBuf.class, ByteBuffer.class, DEFAULT::wrap); - conversionService.addConverter(ByteBuffer.class, ByteBuf.class, byteBuffer -> { - if (byteBuffer instanceof NettyByteBuffer) { - return (ByteBuf) byteBuffer.asNativeBuffer(); - } - throw new IllegalArgumentException("Unconvertible buffer type " + byteBuffer); - }); - } -} diff --git a/buffer-netty/src/main/java/io/micronaut/buffer/netty/NettyByteBufferFactory.java b/buffer-netty/src/main/java/io/micronaut/buffer/netty/NettyByteBufferFactory.java index c606ffa5b76..a4fc25a6624 100644 --- a/buffer-netty/src/main/java/io/micronaut/buffer/netty/NettyByteBufferFactory.java +++ b/buffer-netty/src/main/java/io/micronaut/buffer/netty/NettyByteBufferFactory.java @@ -17,11 +17,13 @@ import io.micronaut.context.annotation.BootstrapContextCompatible; import io.micronaut.core.annotation.Internal; +import io.micronaut.core.convert.ConversionService; import io.micronaut.core.io.buffer.ByteBuffer; import io.micronaut.core.io.buffer.ByteBufferFactory; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; import io.netty.buffer.Unpooled; +import jakarta.annotation.PostConstruct; import jakarta.inject.Singleton; /** @@ -56,6 +58,17 @@ public NettyByteBufferFactory(ByteBufAllocator allocator) { this.allocator = allocator; } + @PostConstruct + final void register(ConversionService conversionService) { + conversionService.addConverter(ByteBuf.class, ByteBuffer.class, DEFAULT::wrap); + conversionService.addConverter(ByteBuffer.class, ByteBuf.class, byteBuffer -> { + if (byteBuffer instanceof NettyByteBuffer) { + return (ByteBuf) byteBuffer.asNativeBuffer(); + } + throw new IllegalArgumentException("Unconvertible buffer type " + byteBuffer); + }); + } + @Override public ByteBufAllocator getNativeAllocator() { return allocator; diff --git a/buffer-netty/src/main/resources/META-INF/services/io.micronaut.core.convert.TypeConverterRegistrar b/buffer-netty/src/main/resources/META-INF/services/io.micronaut.core.convert.TypeConverterRegistrar deleted file mode 100644 index 4ce685673c7..00000000000 --- a/buffer-netty/src/main/resources/META-INF/services/io.micronaut.core.convert.TypeConverterRegistrar +++ /dev/null @@ -1 +0,0 @@ -io.micronaut.buffer.netty.ByteBufConvertersRegistrar diff --git a/http-netty/src/test/groovy/io/micronaut/http/netty/allocator/DefaultAllocatorSpec.groovy b/http-netty/src/test/groovy/io/micronaut/http/netty/allocator/DefaultAllocatorSpec.groovy index 0fbbf3bfa2b..185ff8ca54b 100644 --- a/http-netty/src/test/groovy/io/micronaut/http/netty/allocator/DefaultAllocatorSpec.groovy +++ b/http-netty/src/test/groovy/io/micronaut/http/netty/allocator/DefaultAllocatorSpec.groovy @@ -2,7 +2,6 @@ package io.micronaut.http.netty.allocator import io.micronaut.context.ApplicationContext import io.netty.buffer.PooledByteBufAllocator -import spock.lang.Ignore import spock.lang.Specification import spock.lang.Stepwise import spock.lang.Unroll @@ -38,7 +37,6 @@ class DefaultAllocatorSpec extends Specification { 'maxCachedByteBuffersPerChunk' | 20 } - @Ignore void "test default allocator configured"() { given: def context = ApplicationContext.run(