Skip to content

Commit

Permalink
Avoid loading all MessageBodyReader classes at startup
Browse files Browse the repository at this point in the history
The classes themselves aren't really needed
for the lookup process, but loading them all
does incur a non-zero cost
  • Loading branch information
geoand committed Jan 3, 2025
1 parent 16fa2e2 commit abcadde
Show file tree
Hide file tree
Showing 7 changed files with 21 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public void registerWriter(Serialisers serialisers, String entityClassName,

public void registerReader(Serialisers serialisers, String entityClassName,
ResourceReader reader) {
serialisers.addReader(loadClass(entityClassName), reader);
serialisers.addReader(entityClassName, reader);
}

protected static <T> Class<T> loadClass(String name) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ public void registerBuiltins(RuntimeType constraint) {
resourceReader.setMediaTypeStrings(Collections.singletonList(builtinReader.mediaType));
// FIXME: we could still support beans
resourceReader.setFactory(new UnmanagedBeanFactory<MessageBodyReader<?>>(reader));
addReader(builtinReader.entityClass, resourceReader);
addReader(builtinReader.entityClass.getName(), resourceReader);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,10 @@ public abstract class Serialisers {
public static final WriterInterceptor[] NO_WRITER_INTERCEPTOR = new WriterInterceptor[0];
// FIXME: spec says we should use generic type, but not sure how to pass that type from Jandex to reflection
protected final QuarkusMultivaluedMap<Class<?>, ResourceWriter> writers = new QuarkusMultivaluedHashMap<>();
protected final QuarkusMultivaluedMap<Class<?>, ResourceReader> readers = new QuarkusMultivaluedHashMap<>();
// for readers the key is a string in order to avoid loading all the reader classes at startup
// for writers we can't really do the same trick because we need to go through (potentially) all the writers
// at startup in order to determine the writer used for each resource method
protected final QuarkusMultivaluedMap<String, ResourceReader> readers = new QuarkusMultivaluedHashMap<>();

public List<MessageBodyReader<?>> findReaders(ConfigurationImpl configuration, Class<?> entityType,
MediaType mediaType) {
Expand All @@ -45,7 +48,7 @@ public List<MessageBodyReader<?>> findReaders(ConfigurationImpl configuration, C
List<MessageBodyReader<?>> ret = new ArrayList<>();
Deque<Class<?>> toProcess = new LinkedList<>();
Class<?> klass = lookupPrimitiveWrapper(entityType);
QuarkusMultivaluedMap<Class<?>, ResourceReader> readers;
QuarkusMultivaluedMap<String, ResourceReader> readers;
if (configuration != null && !configuration.getResourceReaders().isEmpty()) {
readers = new QuarkusMultivaluedHashMap<>();
readers.addAll(configuration.getResourceReaders());
Expand All @@ -61,7 +64,7 @@ public List<MessageBodyReader<?>> findReaders(ConfigurationImpl configuration, C
Set<Class<?>> seen = new HashSet<>(toProcess);
while (!toProcess.isEmpty()) {
Class<?> iface = toProcess.poll();
List<ResourceReader> goodTypeReaders = readers.get(iface);
List<ResourceReader> goodTypeReaders = readers.get(iface.getName());
readerLookup(mediaType, runtimeType, desired, ret, goodTypeReaders);
for (Class<?> i : iface.getInterfaces()) {
if (!seen.contains(i)) {
Expand All @@ -71,7 +74,7 @@ public List<MessageBodyReader<?>> findReaders(ConfigurationImpl configuration, C
}
}
}
List<ResourceReader> goodTypeReaders = readers.get(klass);
List<ResourceReader> goodTypeReaders = readers.get(klass.getName());
readerLookup(mediaType, runtimeType, desired, ret, goodTypeReaders);
if (klass.isInterface()) {
klass = Object.class;
Expand Down Expand Up @@ -111,8 +114,8 @@ public <T> void addWriter(Class<T> entityClass, ResourceWriter writer) {
writers.add(entityClass, writer);
}

public <T> void addReader(Class<T> entityClass, ResourceReader reader) {
readers.add(entityClass, reader);
public <T> void addReader(String entityClassName, ResourceReader reader) {
readers.add(entityClassName, reader);
}

public List<MessageBodyWriter<?>> findBuildTimeWriters(Class<?> entityType, RuntimeType runtimeType,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public class ConfigurationImpl implements Configuration {
private final MultivaluedMap<Integer, WriterInterceptor> writerInterceptors;
private final MultivaluedMap<Integer, ReaderInterceptor> readerInterceptors;
private final MultivaluedMap<Class<?>, ResourceWriter> resourceWriters;
private final MultivaluedMap<Class<?>, ResourceReader> resourceReaders;
private final MultivaluedMap<String, ResourceReader> resourceReaders;
private final MultivaluedMap<Class<?>, RxInvokerProvider<?>> rxInvokerProviders;
private final Map<Class<?>, MultivaluedMap<Integer, ContextResolver<?>>> contextResolvers;

Expand Down Expand Up @@ -284,8 +284,8 @@ private void register(Object component, Integer priority) {
resourceReader.setPriority(priority);
}
Type[] args = Types.findParameterizedTypes(componentClass, MessageBodyReader.class);
resourceReaders.add(args != null && args.length == 1 ? Types.getRawType(args[0]) : Object.class,
resourceReader);
Class<?> clazz = args != null && args.length == 1 ? Types.getRawType(args[0]) : Object.class;
resourceReaders.add(clazz.getName(), resourceReader);
}
}
if (component instanceof MessageBodyWriter) {
Expand Down Expand Up @@ -404,8 +404,8 @@ public void register(Object component, Map<Class<?>, Integer> componentContracts
.setMediaTypeStrings(
consumes != null ? Arrays.asList(consumes.value()) : WILDCARD_STRING_LIST);
Type[] args = Types.findParameterizedTypes(componentClass, MessageBodyReader.class);
resourceReaders.add(args != null && args.length == 1 ? Types.getRawType(args[0]) : Object.class,
resourceReader);
Class<?> clazz = args != null && args.length == 1 ? Types.getRawType(args[0]) : Object.class;
resourceReaders.add(clazz.getName(), resourceReader);
}
}
priority = componentContracts.get(MessageBodyWriter.class);
Expand Down Expand Up @@ -455,7 +455,7 @@ public void registerMessageBodyReader(MessageBodyReader<?> reader, Class<?> hand
resourceReader.setBuiltin(builtin);
resourceReader.setPriority(priority);
resourceReader.setConstraint(runtimeType);
resourceReaders.add(handledType, resourceReader);
resourceReaders.add(handledType.getName(), resourceReader);
allInstances.put(reader.getClass(), reader);
}

Expand Down Expand Up @@ -578,7 +578,7 @@ private int determinePriority(Class<?> object) {
return priority.value();
}

public MultivaluedMap<Class<?>, ResourceReader> getResourceReaders() {
public MultivaluedMap<String, ResourceReader> getResourceReaders() {
return resourceReaders;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import java.util.Map;

import org.jboss.resteasy.reactive.common.core.Serialisers;
import org.jboss.resteasy.reactive.common.model.ResourceReader;
import org.jboss.resteasy.reactive.common.model.ResourceWriter;

public abstract class DeploymentUtils {
Expand All @@ -22,11 +21,6 @@ public static void registerWriter(Serialisers serialisers, String entityClassNam
serialisers.addWriter(loadClass(entityClassName), writer);
}

public static void registerReader(Serialisers serialisers, String entityClassName,
ResourceReader reader) {
serialisers.addReader(loadClass(entityClassName), reader);
}

public static <T> Class<T> loadClass(String name) {
if (primitiveTypes.containsKey(name)) {
return (Class<T>) primitiveTypes.get(name);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,7 @@ public void addScannedSerializers() throws ClassNotFoundException {
.setFactory(new ReflectionBeanFactory<>(i.getClassName())));
}
for (var i : sa.serializerScanningResult.getReaders()) {
serialisers.addReader(classLoader.loadClass(i.getHandledClassName()),
serialisers.addReader(i.getHandledClassName(),
new ResourceReader()
.setMediaTypeStrings(i.getMediaTypeStrings())
.setConstraint(i.getRuntimeType())
Expand All @@ -361,7 +361,7 @@ public void addScannedSerializers() throws ClassNotFoundException {
.setMediaTypeStrings(Collections.singletonList(i.getMediaType())));
}
for (var i : sa.readers.get()) {
serialisers.addReader(classLoader.loadClass(i.getEntityClass()),
serialisers.addReader(i.getEntityClass(),
new ResourceReader().setFactory(ReflectiveContextInjectedBeanFactory.create((i.getHandlerClass())))
.setConstraint(i.getConstraint())
.setMediaTypeStrings(Collections.singletonList(i.getMediaType())));
Expand All @@ -370,7 +370,7 @@ public void addScannedSerializers() throws ClassNotFoundException {

public void addBuiltinSerializers() {
for (Serialisers.BuiltinReader builtinReader : ServerSerialisers.BUILTIN_READERS) {
serialisers.addReader(builtinReader.entityClass,
serialisers.addReader(builtinReader.entityClass.getName(),
new ResourceReader().setFactory(ReflectiveContextInjectedBeanFactory.create(builtinReader.readerClass))
.setConstraint(builtinReader.constraint)
.setMediaTypeStrings(Collections.singletonList(builtinReader.mediaType)).setBuiltin(true));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@
import org.jboss.resteasy.reactive.common.core.Serialisers;
import org.jboss.resteasy.reactive.common.headers.HeaderUtil;
import org.jboss.resteasy.reactive.common.jaxrs.ConfigurationImpl;
import org.jboss.resteasy.reactive.common.model.ResourceReader;
import org.jboss.resteasy.reactive.common.model.ResourceWriter;
import org.jboss.resteasy.reactive.common.util.MediaTypeHelper;
import org.jboss.resteasy.reactive.common.util.QuarkusMultivaluedHashMap;
Expand Down Expand Up @@ -271,10 +270,6 @@ public MultivaluedMap<Class<?>, ResourceWriter> getWriters() {
return writers;
}

public MultivaluedMap<Class<?>, ResourceReader> getReaders() {
return readers;
}

/**
* Find the best matching writer based on the 'Accept' HTTP header
* This is probably more complex than it needs to be, but some RESTEasy tests show that the response type
Expand Down

0 comments on commit abcadde

Please sign in to comment.