diff --git a/README.md b/README.md
index a0cf979384ecb10741a65ec702e0250e620600fb..05e98b80b025c0cca47a8c7a6c8a935e5f485fa4 100644
--- a/README.md
+++ b/README.md
@@ -72,3 +72,13 @@ curl -s -D - -H "Accept: application/json"  \
   http://localhost:9998/myapp/biblio/auteurs/1000
 ```
 
+Filter resources with query parameters :
+```shell
+curl -v -H "Accept: application/json"  \
+ "http://127.0.0.1:9998/myapp/biblio/auteurs/filter?nom=Durand&prenom⁼Marie"
+```
+Control sort key with header param (default value "nom") :
+```shell
+curl -v -H "Accept: application/json"  -H "sortKey: prenom"\
+"http://127.0.0.1:9998/myapp/biblio/auteurs/filter"
+```
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 99e295d738afa2ea9c3b727591deb08d11d79b5c..d9fc501a209e58467ba08053907a389ec92b728f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -114,8 +114,8 @@
                 <version>3.8.1</version>
                 <inherited>true</inherited>
                 <configuration>
-                    <source>8</source>
-                    <target>8</target>
+                    <source>15</source>
+                    <target>15</target>
                 </configuration>
             </plugin>
 
@@ -269,7 +269,7 @@
                                     <version>3.5.4</version>
                                 </requireMavenVersion>
                                 <requireJavaVersion>
-                                    <version>11</version>
+                                    <version>15</version>
                                 </requireJavaVersion>
                             </rules>
                         </configuration>
@@ -319,6 +319,71 @@
                 <artifactId>maven-site-plugin</artifactId>
                 <version>3.9.1</version>
             </plugin>
+
+            <!-- Builds a jar that can merge the artifact and its dependencies
+                https://maven.apache.org/plugins/maven-shade-plugin/
+                WARNING minimizeJar can cause trouble, disable it in the child project if needed
+
+                The manifest mainclass can be given with the property ${app.main.class}.
+
+                Its is added to the package phase.
+                -->
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-shade-plugin</artifactId>
+                <version>3.2.3</version>
+                <configuration>
+                    <createDependencyReducedPom>true</createDependencyReducedPom>
+                    <minimizeJar>false</minimizeJar>
+                    <!-- The shaded artifact is not the main artifact -->
+                    <shadedArtifactAttached>true</shadedArtifactAttached>
+                    <shadedClassifierName>withdependencies</shadedClassifierName>
+
+                    <transformers>
+                        <!-- merge services ressource for SPI -->
+                        <transformer
+                            implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer" />
+
+                        <!-- makes a default entry point in the shaded jar -->
+                        <transformer
+                            implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
+                            <manifestEntries>
+                                <Main-Class>${main.class}</Main-Class>
+                                <X-Compile-Source-JDK>${java.version}</X-Compile-Source-JDK>
+                                <X-Compile-Target-JDK>${java.version}</X-Compile-Target-JDK>
+                            </manifestEntries>
+                        </transformer>
+
+                        <!-- keep a default config file -->
+                        <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
+                            <resource>config.properties</resource>
+                            <resource>log4j.properties</resource>
+                        </transformer>
+                    </transformers>
+
+                    <!-- removes signatures in uberjar -->
+                    <filters>
+                        <filter>
+                            <artifact>*:*</artifact>
+                            <excludes>
+                                <exclude>META-INF/*.SF</exclude>
+                                <exclude>META-INF/*.DSA</exclude>
+                                <exclude>META-INF/*.RSA</exclude>
+                            </excludes>
+                        </filter>
+                    </filters>
+
+                </configuration>
+                <executions>
+                    <execution>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>shade</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+
         </plugins>
     </build>
     <properties>
diff --git a/src/main/java/fr/univtln/bruno/samples/jaxrs/client/BiblioClient.java b/src/main/java/fr/univtln/bruno/samples/jaxrs/client/BiblioClient.java
index 00f1854ad5b058adb5b772401336733e28f12b5a..903059bdaddfabfc2ca7fd4f0f948f178d7366a0 100644
--- a/src/main/java/fr/univtln/bruno/samples/jaxrs/client/BiblioClient.java
+++ b/src/main/java/fr/univtln/bruno/samples/jaxrs/client/BiblioClient.java
@@ -1,7 +1,6 @@
 package fr.univtln.bruno.samples.jaxrs.client;
 
 import fr.univtln.bruno.samples.jaxrs.model.BiblioModel.Auteur;
-import fr.univtln.bruno.samples.jaxrs.server.BiblioServer;
 import jakarta.ws.rs.client.Client;
 import jakarta.ws.rs.client.ClientBuilder;
 import jakarta.ws.rs.client.Entity;
diff --git a/src/main/java/fr/univtln/bruno/samples/jaxrs/exceptions/IllegalArgumentException.java b/src/main/java/fr/univtln/bruno/samples/jaxrs/exceptions/IllegalArgumentException.java
index 363591b97dd8057f9a9b96409757e61de097aad5..7a8e69d1bb7286cfb36119731c6b9838e7aabb9e 100644
--- a/src/main/java/fr/univtln/bruno/samples/jaxrs/exceptions/IllegalArgumentException.java
+++ b/src/main/java/fr/univtln/bruno/samples/jaxrs/exceptions/IllegalArgumentException.java
@@ -1,9 +1,9 @@
 package fr.univtln.bruno.samples.jaxrs.exceptions;
 
-import jakarta.ws.rs.core.Response;
+import static jakarta.ws.rs.core.Response.*;
 
 public class IllegalArgumentException extends BusinessException {
     public IllegalArgumentException() {
-        super(Response.Status.NOT_ACCEPTABLE);
+        super(Status.NOT_ACCEPTABLE);
     }
 }
diff --git a/src/main/java/fr/univtln/bruno/samples/jaxrs/model/BiblioModel.java b/src/main/java/fr/univtln/bruno/samples/jaxrs/model/BiblioModel.java
index e5159c6946907f66e5c864c4f589bd576b8f656e..4859aa67d8275dc68d333aeeb35742ab1d2e2b34 100644
--- a/src/main/java/fr/univtln/bruno/samples/jaxrs/model/BiblioModel.java
+++ b/src/main/java/fr/univtln/bruno/samples/jaxrs/model/BiblioModel.java
@@ -7,6 +7,7 @@ import jakarta.xml.bind.annotation.XmlAccessorType;
 import jakarta.xml.bind.annotation.XmlAttribute;
 import jakarta.xml.bind.annotation.XmlRootElement;
 import lombok.*;
+import lombok.experimental.Delegate;
 import lombok.experimental.FieldDefaults;
 import lombok.extern.java.Log;
 import org.eclipse.collections.api.map.primitive.MutableLongObjectMap;
@@ -20,6 +21,8 @@ import java.io.Serializable;
 @NoArgsConstructor(staticName = "of")
 public class BiblioModel {
     private static long lastId = 0;
+
+    @Delegate
     final MutableLongObjectMap<Auteur> auteurs = LongObjectMaps.mutable.empty();
 
     public Auteur addAuteur(Auteur auteur) throws IllegalArgumentException {
diff --git a/src/main/java/fr/univtln/bruno/samples/jaxrs/resources/BiblioResource.java b/src/main/java/fr/univtln/bruno/samples/jaxrs/resources/BiblioResource.java
index 2be41d5b16a00158a4cdfaf2797e8890d11e89f6..1ec34be52876397cee81d4af754c3328f887d273 100644
--- a/src/main/java/fr/univtln/bruno/samples/jaxrs/resources/BiblioResource.java
+++ b/src/main/java/fr/univtln/bruno/samples/jaxrs/resources/BiblioResource.java
@@ -8,9 +8,15 @@ import fr.univtln.bruno.samples.jaxrs.model.BiblioModel.Auteur;
 import fr.univtln.bruno.samples.jaxrs.status.Status;
 import jakarta.ws.rs.*;
 import jakarta.ws.rs.core.MediaType;
+import lombok.extern.java.Log;
 
+import java.security.InvalidParameterException;
 import java.util.Collection;
+import java.util.Comparator;
+import java.util.List;
+import java.util.stream.Collectors;
 
+@Log
 // The Java class will be hosted at the URI path "/biblio"
 @Path("biblio")
 @Produces({MediaType.APPLICATION_JSON, MediaType.TEXT_XML})
@@ -28,7 +34,7 @@ public class BiblioResource {
     @Path("init")
     public int init() throws IllegalArgumentException {
         modeleBibliotheque.supprimerAuteurs();
-        modeleBibliotheque.addAuteur(Auteur.builder().prenom("Jean").nom("Martin").build());
+        modeleBibliotheque.addAuteur(Auteur.builder().prenom("Alfred").nom("Martin").build());
         modeleBibliotheque.addAuteur(Auteur.builder().prenom("Marie").nom("Durand").build());
         return modeleBibliotheque.getAuteurSize();
     }
@@ -78,4 +84,26 @@ public class BiblioResource {
     public Collection<Auteur> getAuteurs() {
         return modeleBibliotheque.getAuteurs().values();
     }
+
+    @GET
+    @Path("auteurs/filter")
+    public List<Auteur> getFilteredAuteurs(@QueryParam("nom") String nom, @QueryParam("prenom") String prenom, @QueryParam("biograpĥie") String biographie,
+                                           @HeaderParam("sortKey") @DefaultValue("nom") String sortKey) {
+        log.info("Sort Key: "+sortKey);
+        //Demo purpose ONLY sorting have to be done in the model
+        return modeleBibliotheque
+                .stream()
+                .filter(auteur -> nom == null || auteur.getNom().equalsIgnoreCase(nom))
+                .filter(auteur -> prenom == null || auteur.getPrenom().equalsIgnoreCase(prenom))
+                .filter(auteur -> biographie == null || auteur.getBiographie().contains(biographie))
+                //We use the news Java 15 switch syntax and value
+                .sorted(Comparator.comparing(auteur -> switch (sortKey) {
+                    case "nom" -> auteur.getNom();
+                    case "prenom" -> auteur.getPrenom();
+                    default -> throw new InvalidParameterException();
+                }))
+                .collect(Collectors.toList());
+    }
+
+
 }
diff --git a/src/main/java/fr/univtln/bruno/samples/jaxrs/status/Status.java b/src/main/java/fr/univtln/bruno/samples/jaxrs/status/Status.java
index 1b45ac449ad2e454ea62728b8347fcf7c908ee3d..7a69da2d6c782e0cfdb9156e51414dc34b6f22aa 100644
--- a/src/main/java/fr/univtln/bruno/samples/jaxrs/status/Status.java
+++ b/src/main/java/fr/univtln/bruno/samples/jaxrs/status/Status.java
@@ -1,7 +1,6 @@
 package fr.univtln.bruno.samples.jaxrs.status;
 
 import jakarta.ws.rs.NameBinding;
-import jakarta.ws.rs.core.Response;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
diff --git a/src/test/java/fr/univtln/bruno/samples/jaxrs/ServerIT.java b/src/test/java/fr/univtln/bruno/samples/jaxrs/ServerIT.java
index 97bde0834322e8b470689b88f5585a13658b0080..8d2e71437163720252a382109595ad829f3e0193 100644
--- a/src/test/java/fr/univtln/bruno/samples/jaxrs/ServerIT.java
+++ b/src/test/java/fr/univtln/bruno/samples/jaxrs/ServerIT.java
@@ -14,6 +14,7 @@ import org.glassfish.jersey.message.internal.MediaTypes;
 import org.junit.*;
 
 import java.util.Collection;
+import java.util.List;
 
 import static org.junit.Assert.*;
 
@@ -74,7 +75,7 @@ public class ServerIT {
     public void testGetAuteurJSON() {
         Auteur responseAuteur = webTarget.path("biblio/auteurs/1").request(MediaType.APPLICATION_JSON).get(Auteur.class);
         assertNotNull(responseAuteur);
-        assertEquals("Jean", responseAuteur.getPrenom());
+        assertEquals("Alfred", responseAuteur.getPrenom());
         assertEquals("Martin", responseAuteur.getNom());
     }
 
@@ -85,7 +86,7 @@ public class ServerIT {
     public void testGetAuteurXML() {
         Auteur responseAuteur = webTarget.path("biblio/auteurs/1").request(MediaType.TEXT_XML).get(Auteur.class);
         assertNotNull(responseAuteur);
-        assertEquals("Jean", responseAuteur.getPrenom());
+        assertEquals("Alfred", responseAuteur.getPrenom());
         assertEquals("Martin", responseAuteur.getNom());
     }
 
@@ -190,4 +191,18 @@ public class ServerIT {
                 .get(String.class);
         assertTrue(serviceWadl.length() > 0);
     }
+
+    /**
+     * Tests filters and query param.
+     */
+    @Test
+    public void filter() {
+        List<Auteur> auteurs = webTarget.path("biblio/auteurs/filter")
+                .queryParam("prenom","Marie")
+                .request(MediaType.APPLICATION_JSON)
+                .get(new GenericType<>() {});
+
+        assertEquals(1, auteurs.size());
+        assertEquals("Marie", auteurs.get(0).getPrenom());
+    }
 }