diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml
index 94e9a36..1882ae9 100644
--- a/.github/workflows/test.yaml
+++ b/.github/workflows/test.yaml
@@ -12,7 +12,7 @@ jobs:
         strategy:
             matrix:
                 install-args: ['']
-                php-version: ['8.1']
+                php-version: ['8.2']
             fail-fast: false
         steps:
             # Cancel previous runs of the same branch
diff --git a/Tests/Fixtures/Entities/BadClass.php b/Tests/Fixtures/Entities/BadClass.php
deleted file mode 100644
index 7c89188..0000000
--- a/Tests/Fixtures/Entities/BadClass.php
+++ /dev/null
@@ -1,8 +0,0 @@
-<?php
-
-
-// The namespace for this class is broken. It must not impact Symfony.
-class BadClass
-{
-
-}
diff --git a/composer.json b/composer.json
index 7491415..1ad1550 100644
--- a/composer.json
+++ b/composer.json
@@ -18,14 +18,13 @@
   "require" : {
     "php" : ">=8.1",
     "ext-json": "*",
-    "thecodingmachine/graphqlite" : "^6.0",
-    "thecodingmachine/graphqlite-symfony-validator-bridge" : "^6.0",
+    "thecodingmachine/graphqlite" : "^8",
+    "thecodingmachine/graphqlite-symfony-validator-bridge": "^7.1.1",
     "symfony/config": "^6.4 || ^7",
     "symfony/console": "^6.4 || ^7",
     "symfony/framework-bundle": "^6.4 || ^7",
     "symfony/validator": "^6.4 || ^7",
     "symfony/translation": "^6.4 || ^7",
-    "doctrine/annotations": "^1.13 || ^2.0.1",
     "symfony/psr-http-message-bridge": "^2.0 || ^7.0",
     "nyholm/psr7": "^1.1",
     "laminas/laminas-diactoros": "^2.2.2 || ^3",
@@ -42,21 +41,25 @@
     "composer/semver": "^3.4"
   },
   "conflict": {
-    "mouf/classname-mapper": "<1.0.2",
     "symfony/event-dispatcher": "<4.3",
     "symfony/security-core": "<4.3",
     "symfony/routing": "<4.3",
     "phpdocumentor/type-resolver": "<1.4"
   },
   "scripts": {
-    "phpstan": "phpstan analyse GraphQLiteBundle.php DependencyInjection/ Controller/ Resources/ Security/ -c phpstan.neon --level=7 --no-progress"
+    "phpstan": "phpstan analyse -c phpstan.neon --level=7 --no-progress"
   },
   "suggest": {
-    "symfony/security-bundle": "To use @Logged or @Right annotations"
+    "symfony/security-bundle": "To use #[Logged] or #[Right] attributes"
   },
   "autoload" : {
     "psr-4" : {
-      "TheCodingMachine\\GraphQLite\\Bundle\\" : ""
+      "TheCodingMachine\\GraphQLite\\Bundle\\" : "src"
+    }
+  },
+  "autoload-dev" : {
+    "psr-4" : {
+      "TheCodingMachine\\GraphQLite\\Bundle\\Tests\\" : "tests"
     }
   },
   "extra": {
diff --git a/phpstan.neon b/phpstan.neon
index fe0c558..f4dcf24 100644
--- a/phpstan.neon
+++ b/phpstan.neon
@@ -8,7 +8,7 @@ parameters:
         - vendor
         - cache
         - .phpstan-cache
-        - Tests
+        - tests
     level: max
     polluteScopeWithLoopInitialAssignments: false
     polluteScopeWithAlwaysIterableForeach: false
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
index cdfcc0f..97d95df 100644
--- a/phpunit.xml.dist
+++ b/phpunit.xml.dist
@@ -16,22 +16,17 @@
     </php>
 
     <testsuites>
-        <testsuite name="Graphql controllers bundle Test Suite">
-            <directory>./Tests/</directory>
+        <testsuite name="GraphQLite Bundle Test Suite">
+            <directory>./tests/</directory>
         </testsuite>
     </testsuites>
 
 
     <filter>
         <whitelist>
-            <directory>./</directory>
+            <directory>./src/</directory>
             <exclude>
-                <directory>cache</directory>
-                <directory>build</directory>
-                <directory>./Resources</directory>
-                <directory>./Tests</directory>
-                <directory>./vendor</directory>
-                <directory>./var</directory>
+                <directory>./src/Resources</directory>
             </exclude>
         </whitelist>
     </filter>
diff --git a/Command/DumpSchemaCommand.php b/src/Command/DumpSchemaCommand.php
similarity index 100%
rename from Command/DumpSchemaCommand.php
rename to src/Command/DumpSchemaCommand.php
diff --git a/Context/SymfonyGraphQLContext.php b/src/Context/SymfonyGraphQLContext.php
similarity index 100%
rename from Context/SymfonyGraphQLContext.php
rename to src/Context/SymfonyGraphQLContext.php
diff --git a/Context/SymfonyRequestContextInterface.php b/src/Context/SymfonyRequestContextInterface.php
similarity index 100%
rename from Context/SymfonyRequestContextInterface.php
rename to src/Context/SymfonyRequestContextInterface.php
diff --git a/Controller/GraphQL/InvalidUserPasswordException.php b/src/Controller/GraphQL/InvalidUserPasswordException.php
similarity index 87%
rename from Controller/GraphQL/InvalidUserPasswordException.php
rename to src/Controller/GraphQL/InvalidUserPasswordException.php
index 48bdbbc..e409002 100644
--- a/Controller/GraphQL/InvalidUserPasswordException.php
+++ b/src/Controller/GraphQL/InvalidUserPasswordException.php
@@ -10,6 +10,6 @@ class InvalidUserPasswordException extends GraphQLException
 {
     public static function create(Exception $previous = null): self
     {
-        return new self('The provided user / password is incorrect.', 401, $previous, 'Security');
+        return new self('The provided user / password is incorrect.', 401, $previous, ['category' => 'Security']);
     }
 }
diff --git a/Controller/GraphQL/LoginController.php b/src/Controller/GraphQL/LoginController.php
similarity index 97%
rename from Controller/GraphQL/LoginController.php
rename to src/Controller/GraphQL/LoginController.php
index de07ddf..08ed1f2 100644
--- a/Controller/GraphQL/LoginController.php
+++ b/src/Controller/GraphQL/LoginController.php
@@ -54,11 +54,7 @@ public function __construct(UserProviderInterface $userProvider, UserPasswordHas
         $this->eventDispatcher = $eventDispatcher;
     }
 
-    /**
-     * @Mutation()
-     *
-     * @phpstan-return TUser
-     */
+    #[Mutation]
     public function login(string $userName, string $password, Request $request): UserInterface
     {
         try {
@@ -95,9 +91,7 @@ public function login(string $userName, string $password, Request $request): Use
         return $user;
     }
 
-    /**
-     * @Mutation()
-     */
+    #[Mutation]
     public function logout(Request $request): bool
     {
         $this->tokenStorage->setToken(null);
diff --git a/Controller/GraphQL/MeController.php b/src/Controller/GraphQL/MeController.php
similarity index 96%
rename from Controller/GraphQL/MeController.php
rename to src/Controller/GraphQL/MeController.php
index 087832a..16c389c 100644
--- a/Controller/GraphQL/MeController.php
+++ b/src/Controller/GraphQL/MeController.php
@@ -18,9 +18,7 @@ public function __construct(TokenStorageInterface $tokenStorage)
         $this->tokenStorage = $tokenStorage;
     }
 
-    /**
-     * @Query()
-     */
+    #[Query]
     public function me(): ?UserInterface
     {
         $token = $this->tokenStorage->getToken();
diff --git a/Controller/GraphQLiteController.php b/src/Controller/GraphQLiteController.php
similarity index 100%
rename from Controller/GraphQLiteController.php
rename to src/Controller/GraphQLiteController.php
index 6988566..9ef3d44 100644
--- a/Controller/GraphQLiteController.php
+++ b/src/Controller/GraphQLiteController.php
@@ -4,22 +4,17 @@
 namespace TheCodingMachine\GraphQLite\Bundle\Controller;
 
 
-use Laminas\Diactoros\ResponseFactory;
-use Laminas\Diactoros\ServerRequestFactory;
-use Laminas\Diactoros\StreamFactory;
-use Laminas\Diactoros\UploadedFileFactory;
-use Symfony\Bridge\PsrHttpMessage\Factory\PsrHttpFactory;
-use TheCodingMachine\GraphQLite\Http\HttpCodeDecider;
-use TheCodingMachine\GraphQLite\Http\HttpCodeDeciderInterface;
-use function array_map;
 use GraphQL\Executor\ExecutionResult;
 use GraphQL\Server\ServerConfig;
 use GraphQL\Server\StandardServer;
 use GraphQL\Upload\UploadMiddleware;
-use function class_exists;
-use function json_decode;
+use Laminas\Diactoros\ResponseFactory;
+use Laminas\Diactoros\ServerRequestFactory;
+use Laminas\Diactoros\StreamFactory;
+use Laminas\Diactoros\UploadedFileFactory;
 use Psr\Http\Message\ServerRequestInterface;
 use RuntimeException;
+use Symfony\Bridge\PsrHttpMessage\Factory\PsrHttpFactory;
 use Symfony\Bridge\PsrHttpMessage\HttpMessageFactoryInterface;
 use Symfony\Component\HttpFoundation\JsonResponse;
 use Symfony\Component\HttpFoundation\Request;
@@ -27,6 +22,11 @@
 use Symfony\Component\Routing\Route;
 use Symfony\Component\Routing\RouteCollection;
 use TheCodingMachine\GraphQLite\Bundle\Context\SymfonyGraphQLContext;
+use TheCodingMachine\GraphQLite\Http\HttpCodeDecider;
+use TheCodingMachine\GraphQLite\Http\HttpCodeDeciderInterface;
+use function array_map;
+use function class_exists;
+use function json_decode;
 
 /**
  * Listens to every single request and forward Graphql requests to Graphql Webonix standardServer.
diff --git a/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php
similarity index 100%
rename from DependencyInjection/Configuration.php
rename to src/DependencyInjection/Configuration.php
diff --git a/DependencyInjection/GraphQLiteCompilerPass.php b/src/DependencyInjection/GraphQLiteCompilerPass.php
similarity index 81%
rename from DependencyInjection/GraphQLiteCompilerPass.php
rename to src/DependencyInjection/GraphQLiteCompilerPass.php
index bee4783..acc29d0 100644
--- a/DependencyInjection/GraphQLiteCompilerPass.php
+++ b/src/DependencyInjection/GraphQLiteCompilerPass.php
@@ -3,36 +3,26 @@
 
 namespace TheCodingMachine\GraphQLite\Bundle\DependencyInjection;
 
-use Doctrine\Common\Annotations\PsrCachedReader;
+use Generator;
 use GraphQL\Server\ServerConfig;
 use GraphQL\Validator\Rules\DisableIntrospection;
 use GraphQL\Validator\Rules\QueryComplexity;
 use GraphQL\Validator\Rules\QueryDepth;
+use Kcs\ClassFinder\Finder\ComposerFinder;
+use Psr\SimpleCache\CacheInterface;
+use ReflectionClass;
+use ReflectionMethod;
 use ReflectionNamedType;
+use ReflectionParameter;
 use Symfony\Component\Cache\Adapter\ApcuAdapter;
 use Symfony\Component\Cache\Adapter\PhpFilesAdapter;
 use Symfony\Component\Cache\Psr16Cache;
-use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
-use TheCodingMachine\GraphQLite\Mappers\StaticClassListTypeMapperFactory;
-use Webmozart\Assert\Assert;
-use function assert;
-use function class_exists;
-use Doctrine\Common\Annotations\AnnotationReader as DoctrineAnnotationReader;
-use Doctrine\Common\Annotations\AnnotationRegistry;
-use Mouf\Composer\ClassNameMapper;
-use Psr\SimpleCache\CacheInterface;
-use ReflectionParameter;
-use function filter_var;
-use function function_exists;
-use ReflectionClass;
-use ReflectionMethod;
-use function ini_get;
-use function interface_exists;
-use function strpos;
+use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument;
 use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
 use Symfony\Component\DependencyInjection\ContainerBuilder;
 use Symfony\Component\DependencyInjection\Definition;
 use Symfony\Component\DependencyInjection\Reference;
+use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
 use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
 use Symfony\Component\Security\Core\User\UserInterface;
 use TheCodingMachine\CacheUtils\ClassBoundCache;
@@ -40,7 +30,6 @@
 use TheCodingMachine\CacheUtils\ClassBoundCacheContractInterface;
 use TheCodingMachine\CacheUtils\ClassBoundMemoryAdapter;
 use TheCodingMachine\CacheUtils\FileBoundCache;
-use TheCodingMachine\ClassExplorer\Glob\GlobClassExplorer;
 use TheCodingMachine\GraphQLite\AggregateControllerQueryProviderFactory;
 use TheCodingMachine\GraphQLite\AnnotationReader;
 use TheCodingMachine\GraphQLite\Annotations\Autowire;
@@ -49,25 +38,32 @@
 use TheCodingMachine\GraphQLite\Annotations\Query;
 use TheCodingMachine\GraphQLite\Bundle\Controller\GraphQL\LoginController;
 use TheCodingMachine\GraphQLite\Bundle\Controller\GraphQL\MeController;
+use TheCodingMachine\GraphQLite\Bundle\Types\SymfonyUserInterfaceType;
 use TheCodingMachine\GraphQLite\GraphQLRuntimeException as GraphQLException;
+use TheCodingMachine\GraphQLite\Mappers\StaticClassListTypeMapperFactory;
 use TheCodingMachine\GraphQLite\Mappers\StaticTypeMapper;
 use TheCodingMachine\GraphQLite\SchemaFactory;
-use TheCodingMachine\GraphQLite\Bundle\Types\SymfonyUserInterfaceType;
+use Webmozart\Assert\Assert;
+use function assert;
+use function class_exists;
+use function filter_var;
+use function ini_get;
+use function interface_exists;
+use function strpos;
 
 /**
  * Detects controllers and types automatically and tag them.
  */
 class GraphQLiteCompilerPass implements CompilerPassInterface
 {
-    /**
-     * @var AnnotationReader
-     */
-    private $annotationReader;
+    private ?AnnotationReader $annotationReader = null;
+
+    private string $cacheDir;
+
+    private ?CacheInterface $cache = null;
+
+    private ?ClassBoundCacheContractInterface $codeCache = null;
 
-    /**
-     * @var string
-     */
-    private $cacheDir;
 
     /**
      * You can modify the container here before it is dumped to PHP code.
@@ -240,14 +236,14 @@ public function process(ContainerBuilder $container): void
         }
 
         foreach ($controllersNamespaces as $controllersNamespace) {
-            $schemaFactory->addMethodCall('addControllerNamespace', [ $controllersNamespace ]);
+            $schemaFactory->addMethodCall('addNamespace', [ $controllersNamespace ]);
             foreach ($this->getClassList($controllersNamespace) as $className => $refClass) {
                 $this->makePublicInjectedServices($refClass, $reader, $container, true);
             }
         }
 
         foreach ($typesNamespaces as $typeNamespace) {
-            $schemaFactory->addMethodCall('addTypeNamespace', [ $typeNamespace ]);
+            $schemaFactory->addMethodCall('addNamespace', [ $typeNamespace ]);
             foreach ($this->getClassList($typeNamespace) as $className => $refClass) {
                 $this->makePublicInjectedServices($refClass, $reader, $container, false);
             }
@@ -301,19 +297,25 @@ public function process(ContainerBuilder $container): void
     private function registerController(string $controllerClassName, ContainerBuilder $container): void
     {
         $aggregateQueryProvider = $container->findDefinition(AggregateControllerQueryProviderFactory::class);
+
         $controllersList = $aggregateQueryProvider->getArgument(0);
         if (!is_array($controllersList)){
             throw new GraphQLException(sprintf('Expecting array in %s, arg #1', AggregateControllerQueryProviderFactory::class));
         }
+
         $controllersList[] = $controllerClassName;
         $aggregateQueryProvider->setArgument(0, $controllersList);
+
+        $serviceLocatorMap = [];
+        foreach ($controllersList as $controller) {
+            $serviceLocatorMap[$controller] = new Reference($controller);
+        }
+
+        $aggregateQueryProvider->setArgument(1, new ServiceLocatorArgument($serviceLocatorMap));
     }
 
     /**
      * Register a method call on SchemaFactory for each tagged service, passing the service in parameter.
-     *
-     * @param string $tag
-     * @param string $methodName
      */
     private function mapAdderToTag(string $tag, string $methodName, ContainerBuilder $container, Definition $schemaFactory): void
     {
@@ -365,39 +367,33 @@ private function makePublicInjectedServices(ReflectionClass $refClass, Annotatio
     }
 
     /**
-     * @param ReflectionMethod $method
-     * @param ContainerBuilder $container
      * @return array<string, string> key = value = service name
      */
     private function getListOfInjectedServices(ReflectionMethod $method, ContainerBuilder $container): array
     {
+        /** @var array<string, string> $services */
         $services = [];
 
-        /**
-         * @var Autowire[] $autowireAnnotations
-         */
-        $autowireAnnotations = $this->getAnnotationReader()->getMethodAnnotations($method, Autowire::class);
-
         $parametersByName = null;
 
-        foreach ($autowireAnnotations as $autowire) {
-            $target = $autowire->getTarget();
-
-            if ($parametersByName === null) {
-                $parametersByName = self::getParametersByName($method);
-            }
+        $annotations = $this->getAnnotationReader()->getParameterAnnotationsPerParameter($method->getParameters());
+        foreach ($annotations as $parameterName => $parameterAnnotations) {
+            $parameterAutowireAnnotation = $parameterAnnotations->getAnnotationsByType(Autowire::class);
+            foreach ($parameterAutowireAnnotation as $autowire) {
+                $id = $autowire->getIdentifier();
+                if ($id !== null) {
+                    $services[$id] = $id;
+                    continue;
+                }
 
-            if (!isset($parametersByName[$target])) {
-                throw new GraphQLException('In method '.$method->getDeclaringClass()->getName().'::'.$method->getName().', the @Autowire annotation refers to a non existing parameter named "'.$target.'"');
-            }
+                $parametersByName ??= self::getParametersByName($method);
+                if (!isset($parametersByName[$parameterName])) {
+                    throw new \LogicException('Should not happen');
+                }
 
-            $id = $autowire->getIdentifier();
-            if ($id !== null) {
-                $services[$id] = $id;
-            } else {
-                $parameter = $parametersByName[$target];
+                $parameter = $parametersByName[$parameterName];
                 $type = $parameter->getType();
-                if ($type !== null && $type instanceof ReflectionNamedType) {
+                if ($type instanceof ReflectionNamedType) {
                     $fqcn = $type->getName();
                     if ($container->has($fqcn)) {
                         $services[$fqcn] = $fqcn;
@@ -410,7 +406,6 @@ private function getListOfInjectedServices(ReflectionMethod $method, ContainerBu
     }
 
     /**
-     * @param ReflectionMethod $method
      * @return array<string, ReflectionParameter>
      */
     private static function getParametersByName(ReflectionMethod $method): array
@@ -423,33 +418,14 @@ private static function getParametersByName(ReflectionMethod $method): array
     }
 
     /**
-     * Returns a cached Doctrine annotation reader.
+     * Returns a GraphQLite annotation reader.
      * Note: we cannot get the annotation reader service in the container as we are in a compiler pass.
      */
     private function getAnnotationReader(): AnnotationReader
     {
-        if ($this->annotationReader === null) {
-            // @phpstan-ignore-next-line "registerLoader exists in doctrine/annotations:v1.x"
-            if (method_exists(AnnotationRegistry::class, 'registerLoader')) {
-                AnnotationRegistry::registerLoader('class_exists');
-            }
-
-            $doctrineAnnotationReader = new DoctrineAnnotationReader();
-
-            if (ApcuAdapter::isSupported()) {
-                $doctrineAnnotationReader = new PsrCachedReader($doctrineAnnotationReader, new ApcuAdapter('graphqlite'), true);
-            }
-
-            $this->annotationReader = new AnnotationReader($doctrineAnnotationReader, AnnotationReader::LAX_MODE);
-        }
-        return $this->annotationReader;
+        return $this->annotationReader ??= new AnnotationReader();
     }
 
-    /**
-     * @var CacheInterface
-     */
-    private $cache;
-
     private function getPsr16Cache(): CacheInterface
     {
         if ($this->cache === null) {
@@ -459,54 +435,33 @@ private function getPsr16Cache(): CacheInterface
                 $this->cache = new Psr16Cache(new PhpFilesAdapter('graphqlite_bundle', 0, $this->cacheDir));
             }
         }
+
         return $this->cache;
     }
 
-    /**
-     * @var ClassBoundCacheContractInterface
-     */
-    private $codeCache;
-
     private function getCodeCache(): ClassBoundCacheContractInterface
     {
-        if ($this->codeCache === null) {
-            $this->codeCache = new ClassBoundCacheContract(new ClassBoundMemoryAdapter(new ClassBoundCache(new FileBoundCache($this->getPsr16Cache()))));
-        }
-        return $this->codeCache;
+        return $this->codeCache ??= new ClassBoundCacheContract(
+            new ClassBoundMemoryAdapter(new ClassBoundCache(new FileBoundCache($this->getPsr16Cache())))
+        );
     }
 
     /**
      * Returns the array of globbed classes.
      * Only instantiable classes are returned.
      *
-     * @return array<string,ReflectionClass<object>> Key: fully qualified class name
+     * @return Generator<class-string, ReflectionClass<object>, void, void>
      */
-    private function getClassList(string $namespace, int $globTtl = 2, bool $recursive = true): array
+    private function getClassList(string $namespace): Generator
     {
-        $explorer = new GlobClassExplorer($namespace, $this->getPsr16Cache(), $globTtl, ClassNameMapper::createFromComposerFile(null, null, true), $recursive);
-        $allClasses = $explorer->getClassMap();
-        $classes = [];
-        foreach ($allClasses as $className => $phpFile) {
-            if (! class_exists($className, false)) {
-                // Let's try to load the file if it was not imported yet.
-                // We are importing the file manually to avoid triggering the autoloader.
-                // The autoloader might trigger errors if the file does not respect PSR-4 or if the
-                // Symfony DebugAutoLoader is installed. (see https://github.com/thecodingmachine/graphqlite/issues/216)
-                require_once $phpFile;
-                // @phpstan-ignore-next-line Does it exist now?
-                if (! class_exists($className, false)) {
-                    continue;
-                }
-            }
-
-            $refClass = new ReflectionClass($className);
-            if (! $refClass->isInstantiable()) {
-                continue;
-            }
-            $classes[$className] = $refClass;
+        // dev note: this code will be broken if there's a broken class (which has mismatch in real namespace
+        //  with PSR-4 configuration) in the configured namespace
+        // see also: https://github.com/alekitto/class-finder/issues/24#issuecomment-2480847327
+        $finder = new ComposerFinder();
+        foreach ($finder->inNamespace($namespace) as $class) {
+            assert($class instanceof ReflectionClass);
+            yield $class->getName() => $class;
         }
-
-        return $classes;
     }
 
 }
diff --git a/DependencyInjection/GraphQLiteExtension.php b/src/DependencyInjection/GraphQLiteExtension.php
similarity index 97%
rename from DependencyInjection/GraphQLiteExtension.php
rename to src/DependencyInjection/GraphQLiteExtension.php
index 8fa97ce..7142518 100644
--- a/DependencyInjection/GraphQLiteExtension.php
+++ b/src/DependencyInjection/GraphQLiteExtension.php
@@ -5,15 +5,15 @@
 
 
 use GraphQL\Error\DebugFlag;
-use TheCodingMachine\GraphQLite\Mappers\Root\RootTypeMapperFactoryInterface;
-use function array_map;
 use GraphQL\Server\ServerConfig;
 use GraphQL\Type\Definition\ObjectType;
-use function rtrim;
 use Symfony\Component\Config\FileLocator;
 use Symfony\Component\DependencyInjection\ContainerBuilder;
 use Symfony\Component\DependencyInjection\Extension\Extension;
 use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
+use TheCodingMachine\GraphQLite\Mappers\Root\RootTypeMapperFactoryInterface;
+use function array_map;
+use function rtrim;
 
 class GraphQLiteExtension extends Extension
 {
@@ -43,7 +43,7 @@ public function load(array $configs, ContainerBuilder $container): void
             }
             $namespaceController = array_map(
                 function($namespace): string {
-                    return rtrim($namespace, '\\') . '\\';
+                    return rtrim($namespace, '\\');
                 },
                 $controllers
             );
@@ -57,7 +57,7 @@ function($namespace): string {
             }
             $namespaceType = array_map(
                 function($namespace): string {
-                    return rtrim($namespace, '\\') . '\\';
+                    return rtrim($namespace, '\\');
                 },
                 $types
             );
diff --git a/DependencyInjection/OverblogGraphiQLEndpointWiringPass.php b/src/DependencyInjection/OverblogGraphiQLEndpointWiringPass.php
similarity index 100%
rename from DependencyInjection/OverblogGraphiQLEndpointWiringPass.php
rename to src/DependencyInjection/OverblogGraphiQLEndpointWiringPass.php
diff --git a/GraphQLiteBundle.php b/src/GraphQLiteBundle.php
similarity index 100%
rename from GraphQLiteBundle.php
rename to src/GraphQLiteBundle.php
index b9005ab..95f9c16 100644
--- a/GraphQLiteBundle.php
+++ b/src/GraphQLiteBundle.php
@@ -3,13 +3,13 @@
 
 namespace TheCodingMachine\GraphQLite\Bundle;
 
-use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
-use TheCodingMachine\GraphQLite\Bundle\DependencyInjection\GraphQLiteExtension;
-use TheCodingMachine\GraphQLite\Bundle\DependencyInjection\OverblogGraphiQLEndpointWiringPass;
 use Symfony\Component\DependencyInjection\Compiler\PassConfig;
 use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
 use Symfony\Component\HttpKernel\Bundle\Bundle;
 use TheCodingMachine\GraphQLite\Bundle\DependencyInjection\GraphQLiteCompilerPass;
+use TheCodingMachine\GraphQLite\Bundle\DependencyInjection\GraphQLiteExtension;
+use TheCodingMachine\GraphQLite\Bundle\DependencyInjection\OverblogGraphiQLEndpointWiringPass;
 
 class GraphQLiteBundle extends Bundle
 {
diff --git a/GraphiQL/EndpointResolver.php b/src/GraphiQL/EndpointResolver.php
similarity index 100%
rename from GraphiQL/EndpointResolver.php
rename to src/GraphiQL/EndpointResolver.php
diff --git a/Mappers/RequestParameter.php b/src/Mappers/RequestParameter.php
similarity index 100%
rename from Mappers/RequestParameter.php
rename to src/Mappers/RequestParameter.php
diff --git a/Mappers/RequestParameterMiddleware.php b/src/Mappers/RequestParameterMiddleware.php
similarity index 100%
rename from Mappers/RequestParameterMiddleware.php
rename to src/Mappers/RequestParameterMiddleware.php
diff --git a/Resources/config/container/graphqlite.xml b/src/Resources/config/container/graphqlite.xml
similarity index 95%
rename from Resources/config/container/graphqlite.xml
rename to src/Resources/config/container/graphqlite.xml
index bda653f..545ec0e 100644
--- a/Resources/config/container/graphqlite.xml
+++ b/src/Resources/config/container/graphqlite.xml
@@ -5,10 +5,6 @@
            xsi:schemaLocation="http://symfony.com/schema/dic/services
                                http://symfony.com/schema/dic/services/services-1.0.xsd"
 >
-    <parameters>
-        <parameter key="graphqlite.annotations.error_mode">LAX_MODE</parameter>
-    </parameters>
-
     <services>
         <defaults autowire="true" autoconfigure="true" public="false" />
 
@@ -30,19 +26,20 @@
         </service>
 
         <service id="TheCodingMachine\GraphQLite\AggregateControllerQueryProviderFactory">
+            <!-- Controller classes list will be generated by compiler pass -->
             <argument type="collection">
             </argument>
-            <argument type="service" id="service_container">
+            <!-- Service locator will be generated by compiler pass -->
+            <argument type="service_locator">
             </argument>
+
             <tag name="graphql.queryprovider_factory" />
         </service>
 
         <service id="GraphQL\Type\Schema" alias="TheCodingMachine\GraphQLite\Schema" />
 
 
-        <service id="TheCodingMachine\GraphQLite\AnnotationReader" >
-            <argument key="$mode">%graphqlite.annotations.error_mode%</argument>
-        </service>
+        <service id="TheCodingMachine\GraphQLite\AnnotationReader" />
 
         <service id="TheCodingMachine\GraphQLite\Bundle\Security\AuthenticationService">
             <argument type="service" id="security.token_storage" on-invalid="null" />
diff --git a/Resources/config/routes.xml b/src/Resources/config/routes.xml
similarity index 100%
rename from Resources/config/routes.xml
rename to src/Resources/config/routes.xml
diff --git a/Security/AuthenticationService.php b/src/Security/AuthenticationService.php
similarity index 100%
rename from Security/AuthenticationService.php
rename to src/Security/AuthenticationService.php
diff --git a/Security/AuthorizationService.php b/src/Security/AuthorizationService.php
similarity index 100%
rename from Security/AuthorizationService.php
rename to src/Security/AuthorizationService.php
diff --git a/Server/ServerConfig.php b/src/Server/ServerConfig.php
similarity index 100%
rename from Server/ServerConfig.php
rename to src/Server/ServerConfig.php
diff --git a/Types/SymfonyUserInterfaceType.php b/src/Types/SymfonyUserInterfaceType.php
similarity index 93%
rename from Types/SymfonyUserInterfaceType.php
rename to src/Types/SymfonyUserInterfaceType.php
index f895319..26ea2f4 100644
--- a/Types/SymfonyUserInterfaceType.php
+++ b/src/Types/SymfonyUserInterfaceType.php
@@ -9,14 +9,10 @@
 use Symfony\Component\Security\Core\User\UserInterface;
 use TheCodingMachine\GraphQLite\FieldNotFoundException;
 
-/**
- * @Type(class=UserInterface::class)
- */
+#[Type(class: UserInterface::class)]
 class SymfonyUserInterfaceType
 {
-    /**
-     * @Field
-     */
+    #[Field]
     public function getUserName(UserInterface $user): string
     {
         // @phpstan-ignore-next-line Forward Compatibility for Symfony >=5.3
@@ -33,9 +29,9 @@ public function getUserName(UserInterface $user): string
     }
 
     /**
-     * @Field()
      * @return string[]
      */
+    #[Field]
     public function getRoles(UserInterface $user): array
     {
         $roles = [];
diff --git a/Tests/Command/DumpSchemaCommandTest.php b/tests/Command/DumpSchemaCommandTest.php
similarity index 100%
rename from Tests/Command/DumpSchemaCommandTest.php
rename to tests/Command/DumpSchemaCommandTest.php
diff --git a/Tests/Fixtures/Controller/MyException.php b/tests/Fixtures/Controller/MyException.php
similarity index 100%
rename from Tests/Fixtures/Controller/MyException.php
rename to tests/Fixtures/Controller/MyException.php
diff --git a/Tests/Fixtures/Controller/TestGraphqlController.php b/tests/Fixtures/Controller/TestGraphqlController.php
similarity index 70%
rename from Tests/Fixtures/Controller/TestGraphqlController.php
rename to tests/Fixtures/Controller/TestGraphqlController.php
index 17c5ba0..d768e61 100644
--- a/Tests/Fixtures/Controller/TestGraphqlController.php
+++ b/tests/Fixtures/Controller/TestGraphqlController.php
@@ -20,19 +20,16 @@
 
 class TestGraphqlController
 {
-
-    /**
-     * @Query()
-     */
+    #[Query]
     public function test(string $foo): string
     {
         return 'echo ' .$foo;
     }
 
     /**
-     * @Query()
      * @return Product[]
      */
+    #[Query]
     public function products(): array
     {
         return [
@@ -40,99 +37,76 @@ public function products(): array
         ];
     }
 
-    /**
-     * @Query()
-     */
+    #[Query]
     public function contact(): Contact
     {
         return new Contact('Mouf');
     }
 
-    /**
-     * @Mutation()
-     */
+    #[Mutation]
     public function saveProduct(Product $product): Product
     {
         return $product;
     }
 
     /**
-     * @Query()
      * @return Contact[]
      */
+    #[Query]
     public function contacts(): ArrayResult
     {
         return new ArrayResult([new Contact('Mouf')]);
     }
 
-    /**
-     * @Query()
-     * @return string
-     */
+    #[Query]
     public function triggerException(int $code = 0): string
     {
         throw new MyException('Boom', $code);
     }
 
-    /**
-     * @Query()
-     * @return string
-     */
+    #[Query]
     public function triggerAggregateException(): string
     {
         $exception1 = new GraphQLException('foo', 401);
-        $exception2 = new GraphQLException('bar', 404, null, 'MyCat', ['field' => 'baz', 'category' => 'MyCat']);
+        $exception2 = new GraphQLException('bar', 404, null, ['field' => 'baz', 'category' => 'MyCat']);
         throw new GraphQLAggregateException([$exception1, $exception2]);
     }
 
-    /**
-     * @Query()
-     * @Logged()
-     * @FailWith(null)
-     * @return string
-     */
+    #[Query]
+    #[Logged]
+    #[FailWith(null)]
     public function loggedQuery(): string
     {
         return 'foo';
     }
 
-    /**
-     * @Query()
-     * @Right("ROLE_ADMIN")
-     * @FailWith(null)
-     * @return string
-     */
+    #[Query]
+    #[Right('ROLE_ADMIN')]
+    #[FailWith(null)]
     public function withAdminRight(): string
     {
         return 'foo';
     }
 
-    /**
-     * @Query()
-     * @Right("ROLE_USER")
-     * @FailWith(null)
-     * @return string
-     */
+    #[Query]
+    #[Right('ROLE_USER')]
+    #[FailWith(null)]
     public function withUserRight(): string
     {
         return 'foo';
     }
 
-    /**
-     * @Query()
-     * @return string
-     */
+    #[Query]
     public function getUri(Request $request): string
     {
         return $request->getPathInfo();
     }
 
-    /**
-     * @Query
-     * @Assertion(for="email", constraint=@Assert\Email())
-     */
-    public function findByMail(string $email = 'a@a.com'): string
-    {
+    #[Query]
+    public function findByMail(
+        #[Assertion(constraint: new Assert\Email())]
+        string $email = 'a@a.com'
+    ): string {
         return $email;
     }
 }
diff --git a/Tests/Fixtures/Controller/TestPhp8GraphqlController.php b/tests/Fixtures/Controller/TestPhp8GraphqlController.php
similarity index 100%
rename from Tests/Fixtures/Controller/TestPhp8GraphqlController.php
rename to tests/Fixtures/Controller/TestPhp8GraphqlController.php
diff --git a/Tests/Fixtures/Entities/Contact.php b/tests/Fixtures/Entities/Contact.php
similarity index 59%
rename from Tests/Fixtures/Entities/Contact.php
rename to tests/Fixtures/Entities/Contact.php
index bfbbb5c..fc90f60 100644
--- a/Tests/Fixtures/Entities/Contact.php
+++ b/tests/Fixtures/Entities/Contact.php
@@ -1,18 +1,14 @@
 <?php
 
-
 namespace TheCodingMachine\GraphQLite\Bundle\Tests\Fixtures\Entities;
 
-
 use stdClass;
 use TheCodingMachine\GraphQLite\Annotations\Field;
 use TheCodingMachine\GraphQLite\Annotations\Type;
 use TheCodingMachine\GraphQLite\Bundle\Tests\Fixtures\Controller\TestGraphqlController;
 use TheCodingMachine\GraphQLite\Annotations\Autowire;
 
-/**
- * @Type()
- */
+#[Type]
 class Contact
 {
     /**
@@ -25,51 +21,46 @@ public function __construct(string $name)
         $this->name = $name;
     }
 
-    /**
-     * @Field(name="name")
-     */
+    #[Field(name: 'name')]
     public function getName(): string
     {
         return $this->name;
     }
 
-    /**
-     * @Field()
-     * @Autowire(for="$testService")
-     * @Autowire(for="$someService", identifier="someService")
-     * @Autowire(for="$someAlias", identifier="someAlias")
-     * @return string
-     */
-    public function injectService(TestGraphqlController $testService = null, stdClass $someService = null, stdClass $someAlias = null): string
-    {
+    #[Field]
+    public function injectService(
+        #[Autowire]
+        TestGraphqlController $testService = null,
+        #[Autowire(identifier: 'someService')]
+        stdClass $someService = null,
+        #[Autowire(identifier: 'someAlias')]
+        stdClass $someAlias = null,
+    ): string {
         if (!$testService instanceof TestGraphqlController || $someService === null || $someAlias === null) {
             return 'KO';
         }
+
         return 'OK';
     }
 
-    /**
-     * @Field(prefetchMethod="prefetchData")
-     */
+    #[Field(prefetchMethod: 'prefetchData')]
     public function injectServicePrefetch($prefetchData): string
     {
         return $prefetchData;
     }
 
-    /**
-     * @Autowire(for="$someOtherService", identifier="someOtherService")
-     */
-    public function prefetchData(iterable $iterable, stdClass $someOtherService = null)
-    {
+    public function prefetchData(
+        iterable $iterable,
+        #[Autowire(identifier: 'someOtherService')]
+        stdClass $someOtherService = null,
+    ) {
         if ($someOtherService === null) {
             return 'KO';
         }
         return 'OK';
     }
 
-    /**
-     * @Field()
-     */
+    #[Field]
     public function getManager(): ?Contact
     {
         return null;
diff --git a/Tests/Fixtures/Entities/Product.php b/tests/Fixtures/Entities/Product.php
similarity index 99%
rename from Tests/Fixtures/Entities/Product.php
rename to tests/Fixtures/Entities/Product.php
index b77e094..d33194a 100644
--- a/Tests/Fixtures/Entities/Product.php
+++ b/tests/Fixtures/Entities/Product.php
@@ -1,9 +1,7 @@
 <?php
 
-
 namespace TheCodingMachine\GraphQLite\Bundle\Tests\Fixtures\Entities;
 
-
 class Product
 {
     /**
diff --git a/Tests/Fixtures/Types/ContactType.php b/tests/Fixtures/Types/ContactType.php
similarity index 84%
rename from Tests/Fixtures/Types/ContactType.php
rename to tests/Fixtures/Types/ContactType.php
index 0e2c5c1..9340ac6 100644
--- a/Tests/Fixtures/Types/ContactType.php
+++ b/tests/Fixtures/Types/ContactType.php
@@ -9,14 +9,10 @@
 use TheCodingMachine\GraphQLite\Bundle\Tests\Fixtures\Entities\Contact;
 
 
-/**
- * @ExtendType(class=Contact::class)
- */
+#[ExtendType(class: Contact::class)]
 class ContactType
 {
-    /**
-     * @Field()
-     */
+    #[Field]
     public function uppercaseName(Contact $contact): string
     {
         return strtoupper($contact->getName());
diff --git a/Tests/Fixtures/Types/ProductFactory.php b/tests/Fixtures/Types/ProductFactory.php
similarity index 90%
rename from Tests/Fixtures/Types/ProductFactory.php
rename to tests/Fixtures/Types/ProductFactory.php
index c28f853..1e38b91 100644
--- a/Tests/Fixtures/Types/ProductFactory.php
+++ b/tests/Fixtures/Types/ProductFactory.php
@@ -9,10 +9,7 @@
 
 class ProductFactory
 {
-
-    /**
-     * @Factory()
-     */
+    #[Factory]
     public function buildProduct(string $name, float $price): Product
     {
         return new Product($name, $price);
diff --git a/Tests/Fixtures/Types/ProductType.php b/tests/Fixtures/Types/ProductType.php
similarity index 79%
rename from Tests/Fixtures/Types/ProductType.php
rename to tests/Fixtures/Types/ProductType.php
index 94e3d8c..2aa3831 100644
--- a/Tests/Fixtures/Types/ProductType.php
+++ b/tests/Fixtures/Types/ProductType.php
@@ -10,16 +10,12 @@
 use TheCodingMachine\GraphQLite\Bundle\Tests\Fixtures\Entities\Product;
 
 
-/**
- * @Type(class=Product::class)
- * @SourceField(name="name")
- * @SourceField(name="price")
- */
+#[Type(class: Product::class)]
+#[SourceField(name: 'name')]
+#[SourceField(name: 'price')]
 class ProductType
 {
-    /**
-     * @Field()
-     */
+    #[Field]
     public function getSeller(Product $product): ?Contact
     {
         return null;
diff --git a/Tests/Fixtures/config/services.yaml b/tests/Fixtures/config/services.yaml
similarity index 100%
rename from Tests/Fixtures/config/services.yaml
rename to tests/Fixtures/config/services.yaml
diff --git a/Tests/FunctionalTest.php b/tests/FunctionalTest.php
similarity index 100%
rename from Tests/FunctionalTest.php
rename to tests/FunctionalTest.php
index 896485f..cdc90ed 100644
--- a/Tests/FunctionalTest.php
+++ b/tests/FunctionalTest.php
@@ -2,17 +2,17 @@
 
 namespace TheCodingMachine\GraphQLite\Bundle\Tests;
 
-use Symfony\Component\Security\Core\User\InMemoryUser;
-use function json_decode;
 use PHPUnit\Framework\TestCase;
 use Psr\Container\ContainerInterface;
 use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\HttpFoundation\Session\Session;
 use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
 use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
+use Symfony\Component\Security\Core\User\InMemoryUser;
 use TheCodingMachine\GraphQLite\Bundle\Controller\GraphQLiteController;
 use TheCodingMachine\GraphQLite\GraphQLRuntimeException as GraphQLException;
 use TheCodingMachine\GraphQLite\Schema;
+use function json_decode;
 
 class FunctionalTest extends TestCase
 {
diff --git a/Tests/GraphQLiteTestingKernel.php b/tests/GraphQLiteTestingKernel.php
similarity index 92%
rename from Tests/GraphQLiteTestingKernel.php
rename to tests/GraphQLiteTestingKernel.php
index 5ec06d1..c92ad95 100644
--- a/Tests/GraphQLiteTestingKernel.php
+++ b/tests/GraphQLiteTestingKernel.php
@@ -188,7 +188,7 @@ public function configureContainer(ContainerBuilder $c, LoaderInterface $loader)
 
             $container->loadFromExtension('graphqlite', $graphqliteConf);
         });
-        $confDir = $this->getProjectDir().'/Tests/Fixtures/config';
+        $confDir = $this->getProjectDir().'/tests/Fixtures/config';
 
         $loader->load($confDir.'/{packages}/*'.self::CONFIG_EXTS, 'glob');
         $loader->load($confDir.'/{packages}/'.$this->environment.'/**/*'.self::CONFIG_EXTS, 'glob');
@@ -199,12 +199,19 @@ public function configureContainer(ContainerBuilder $c, LoaderInterface $loader)
     // Note: typing is disabled because using different classes in Symfony 4 and 5
     protected function configureRoutes(/*RoutingConfigurator*/ $routes)
     {
-        $routes->import(__DIR__.'/../Resources/config/routes.xml');
+        $routes->import(__DIR__.'/../src/Resources/config/routes.xml');
     }
 
     public function getCacheDir(): string
     {
-        return __DIR__.'/../cache/'.($this->enableSession?'withSession':'withoutSession').$this->enableLogin.($this->enableSecurity?'withSecurity':'withoutSecurity').$this->enableMe.'_'.($this->introspection?'withIntrospection':'withoutIntrospection').'_'.$this->maximumQueryComplexity.'_'.$this->maximumQueryDepth.'_'.md5(serialize($this->controllersNamespace).'_'.md5(serialize($this->typesNamespace)));
+        $prefix = ($this->enableSession?'withSession':'withoutSession')
+            .$this->enableLogin
+            .($this->enableSecurity?'withSecurity':'withoutSecurity')
+            .$this->enableMe
+            .'_'
+            .($this->introspection?'withIntrospection':'withoutIntrospection');
+
+        return __DIR__.'/../cache/'.$prefix.'_'.$this->maximumQueryComplexity.'_'.$this->maximumQueryDepth.'_'.md5(serialize($this->controllersNamespace).'_'.md5(serialize($this->typesNamespace)));
     }
 
     public function process(ContainerBuilder $container): void
diff --git a/Tests/NoSecurityBundleFixtures/Controller/EchoController.php b/tests/NoSecurityBundleFixtures/Controller/EchoController.php
similarity index 88%
rename from Tests/NoSecurityBundleFixtures/Controller/EchoController.php
rename to tests/NoSecurityBundleFixtures/Controller/EchoController.php
index 64dfe19..3521ed2 100644
--- a/Tests/NoSecurityBundleFixtures/Controller/EchoController.php
+++ b/tests/NoSecurityBundleFixtures/Controller/EchoController.php
@@ -1,16 +1,12 @@
 <?php
 
-
 namespace TheCodingMachine\GraphQLite\Bundle\Tests\NoSecurityBundleFixtures\Controller;
 
-
 use TheCodingMachine\GraphQLite\Annotations\Query;
 
 class EchoController
 {
-    /**
-     * @Query()
-     */
+    #[Query]
     public function echoMsg(string $message): string {
         return $message;
     }
diff --git a/Tests/NoSecurityBundleTest.php b/tests/NoSecurityBundleTest.php
similarity index 78%
rename from Tests/NoSecurityBundleTest.php
rename to tests/NoSecurityBundleTest.php
index 46f6e13..91632fb 100644
--- a/Tests/NoSecurityBundleTest.php
+++ b/tests/NoSecurityBundleTest.php
@@ -2,6 +2,7 @@
 
 namespace TheCodingMachine\GraphQLite\Bundle\Tests;
 
+use Symfony\Component\Cache\Adapter\ApcuAdapter;
 use function json_decode;
 use PHPUnit\Framework\TestCase;
 use Symfony\Component\HttpFoundation\Request;
@@ -15,10 +16,16 @@ class NoSecurityBundleTest extends TestCase
 {
     public function testServiceWiring(): void
     {
+        // tech debt: for some reason when we're running full test suite
+        // - from APCu cache we're getting old controllers for available graphql and this fails test
+        if (ApcuAdapter::isSupported()) {
+            $apcu = new ApcuAdapter();
+            $apcu->clear();
+        }
+
         $kernel = new GraphQLiteTestingKernel(true, null, false, null, true, null, null, ['TheCodingMachine\\GraphQLite\\Bundle\\Tests\\NoSecurityBundleFixtures\\Controller\\']);
         $kernel->boot();
         $container = $kernel->getContainer();
-        self::assertNotNull($container);
 
         $schema = $container->get(Schema::class);
         $this->assertInstanceOf(Schema::class, $schema);