diff --git a/scm-annotations/src/main/java/sonia/scm/api/v2/resources/Enrich.java b/scm-annotations/src/main/java/sonia/scm/api/v2/resources/Enrich.java
new file mode 100644
index 0000000000..a1269dfc00
--- /dev/null
+++ b/scm-annotations/src/main/java/sonia/scm/api/v2/resources/Enrich.java
@@ -0,0 +1,26 @@
+package sonia.scm.api.v2.resources;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation to specify the source of an enricher.
+ *
+ * @author Sebastian Sdorra
+ * @since 2.0.0
+ */
+@Documented
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Enrich {
+
+ /**
+ * Source mapping class.
+ *
+ * @return source mapping class
+ */
+ Class> value();
+}
diff --git a/scm-core/src/main/java/sonia/scm/api/v2/resources/LinkEnricher.java b/scm-core/src/main/java/sonia/scm/api/v2/resources/LinkEnricher.java
index b9cc3c5059..c16d6f6482 100644
--- a/scm-core/src/main/java/sonia/scm/api/v2/resources/LinkEnricher.java
+++ b/scm-core/src/main/java/sonia/scm/api/v2/resources/LinkEnricher.java
@@ -1,11 +1,18 @@
package sonia.scm.api.v2.resources;
+import sonia.scm.plugin.ExtensionPoint;
+
/**
* A {@link LinkEnricher} can be used to append hateoas links to a specific json response.
+ * To register an enricher use the {@link Enrich} annotation or the {@link LinkEnricherRegistry} which is available
+ * via injection.
+ *
+ * Warning: enrichers are always registered as singletons.
*
* @author Sebastian Sdorra
* @since 2.0.0
*/
+@ExtensionPoint
@FunctionalInterface
public interface LinkEnricher {
diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/LinkEnricherAutoRegistration.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/LinkEnricherAutoRegistration.java
new file mode 100644
index 0000000000..890e268ed5
--- /dev/null
+++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/LinkEnricherAutoRegistration.java
@@ -0,0 +1,45 @@
+package sonia.scm.api.v2.resources;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import sonia.scm.plugin.Extension;
+
+import javax.inject.Inject;
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+import java.util.Set;
+
+/**
+ * Registers every {@link LinkEnricher} which is annotated with an {@link Enrich} annotation.
+ */
+@Extension
+public class LinkEnricherAutoRegistration implements ServletContextListener {
+
+ private static final Logger LOG = LoggerFactory.getLogger(LinkEnricherAutoRegistration.class);
+
+ private final LinkEnricherRegistry registry;
+ private final Set enrichers;
+
+ @Inject
+ public LinkEnricherAutoRegistration(LinkEnricherRegistry registry, Set enrichers) {
+ this.registry = registry;
+ this.enrichers = enrichers;
+ }
+
+ @Override
+ public void contextInitialized(ServletContextEvent sce) {
+ for (LinkEnricher enricher : enrichers) {
+ Enrich annotation = enricher.getClass().getAnnotation(Enrich.class);
+ if (annotation != null) {
+ registry.register(annotation.value(), enricher);
+ } else {
+ LOG.warn("found LinkEnricher extension {} without Enrich annotation", enricher.getClass());
+ }
+ }
+ }
+
+ @Override
+ public void contextDestroyed(ServletContextEvent sce) {
+ // nothing todo
+ }
+}
diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/LinkEnricherAutoRegistrationTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/LinkEnricherAutoRegistrationTest.java
new file mode 100644
index 0000000000..a2b72abc49
--- /dev/null
+++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/LinkEnricherAutoRegistrationTest.java
@@ -0,0 +1,64 @@
+package sonia.scm.api.v2.resources;
+
+import com.google.common.collect.ImmutableSet;
+import org.junit.jupiter.api.Test;
+
+import java.util.Set;
+
+import static org.assertj.core.api.Java6Assertions.assertThat;
+
+class LinkEnricherAutoRegistrationTest {
+
+ @Test
+ void shouldRegisterAllAvailableLinkEnrichers() {
+ LinkEnricher one = new One();
+ LinkEnricher two = new Two();
+ LinkEnricher three = new Three();
+ LinkEnricher four = new Four();
+ Set enrichers = ImmutableSet.of(one, two, three, four);
+
+ LinkEnricherRegistry registry = new LinkEnricherRegistry();
+
+ LinkEnricherAutoRegistration autoRegistration = new LinkEnricherAutoRegistration(registry, enrichers);
+ autoRegistration.contextInitialized(null);
+
+ assertThat(registry.allByType(String.class)).containsOnly(one, two);
+ assertThat(registry.allByType(Integer.class)).containsOnly(three);
+ }
+
+ @Enrich(String.class)
+ public static class One implements LinkEnricher {
+
+ @Override
+ public void enrich(LinkEnricherContext context, LinkAppender appender) {
+
+ }
+ }
+
+ @Enrich(String.class)
+ public static class Two implements LinkEnricher {
+
+ @Override
+ public void enrich(LinkEnricherContext context, LinkAppender appender) {
+
+ }
+ }
+
+ @Enrich(Integer.class)
+ public static class Three implements LinkEnricher {
+
+ @Override
+ public void enrich(LinkEnricherContext context, LinkAppender appender) {
+
+ }
+ }
+
+ public static class Four implements LinkEnricher {
+
+ @Override
+ public void enrich(LinkEnricherContext context, LinkAppender appender) {
+
+ }
+ }
+
+}