thanks spec default methods creating call loops....fixing it + a adding simpletimer first representation in json and openmetrics endpoints
diff --git a/geronimo-metrics-common/src/main/java/org/apache/geronimo/microprofile/metrics/common/RegistryImpl.java b/geronimo-metrics-common/src/main/java/org/apache/geronimo/microprofile/metrics/common/RegistryImpl.java
index c85cc5a..881450c 100644
--- a/geronimo-metrics-common/src/main/java/org/apache/geronimo/microprofile/metrics/common/RegistryImpl.java
+++ b/geronimo-metrics-common/src/main/java/org/apache/geronimo/microprofile/metrics/common/RegistryImpl.java
@@ -167,6 +167,11 @@
     }
 
     @Override
+    public Gauge<?> gauge(final String name, final Gauge<?> gauge, final Tag...tags) {
+        return register(Metadata.builder().reusable().withName(name).build(), gauge, tags);
+    }
+
+    @Override
     public Histogram histogram(final Metadata metadata) {
         return histogram(metadata, NO_TAG);
     }
diff --git a/geronimo-metrics-common/src/main/java/org/apache/geronimo/microprofile/metrics/common/TimerImpl.java b/geronimo-metrics-common/src/main/java/org/apache/geronimo/microprofile/metrics/common/TimerImpl.java
index 38cf11e..6067b09 100644
--- a/geronimo-metrics-common/src/main/java/org/apache/geronimo/microprofile/metrics/common/TimerImpl.java
+++ b/geronimo-metrics-common/src/main/java/org/apache/geronimo/microprofile/metrics/common/TimerImpl.java
@@ -26,10 +26,12 @@
 import java.time.Duration;
 import java.util.concurrent.Callable;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.LongAdder;
 
 public class TimerImpl implements Timer {
     private final Histogram histogram;
     private final Meter meter;
+    private final LongAdder elapsed = new LongAdder();
 
     public TimerImpl(final String unit) {
         this.histogram = new HistogramImpl(unit);
@@ -43,6 +45,7 @@
         }
         histogram.update(duration.toNanos());
         meter.mark();
+        elapsed.add(duration.toNanos());
     }
 
     @Override
@@ -73,7 +76,7 @@
 
     @Override
     public Duration getElapsedTime() {
-        return null;
+        return Duration.ofNanos(elapsed.longValue());
     }
 
     @Override
diff --git a/geronimo-metrics-common/src/main/java/org/apache/geronimo/microprofile/metrics/common/jaxrs/MetricsEndpoints.java b/geronimo-metrics-common/src/main/java/org/apache/geronimo/microprofile/metrics/common/jaxrs/MetricsEndpoints.java
index ced84dd..6e38041 100644
--- a/geronimo-metrics-common/src/main/java/org/apache/geronimo/microprofile/metrics/common/jaxrs/MetricsEndpoints.java
+++ b/geronimo-metrics-common/src/main/java/org/apache/geronimo/microprofile/metrics/common/jaxrs/MetricsEndpoints.java
@@ -23,14 +23,17 @@
 import static java.util.stream.Collectors.joining;
 import static java.util.stream.Collectors.toMap;
 
+import java.time.Duration;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Objects;
+import java.util.TreeMap;
 import java.util.function.Function;
 import java.util.regex.Pattern;
 import java.util.stream.Stream;
 
+import javax.json.JsonValue;
 import javax.ws.rs.GET;
 import javax.ws.rs.OPTIONS;
 import javax.ws.rs.Path;
@@ -54,6 +57,7 @@
 import org.eclipse.microprofile.metrics.Metric;
 import org.eclipse.microprofile.metrics.MetricID;
 import org.eclipse.microprofile.metrics.MetricRegistry;
+import org.eclipse.microprofile.metrics.SimpleTimer;
 import org.eclipse.microprofile.metrics.Snapshot;
 import org.eclipse.microprofile.metrics.Timer;
 
@@ -255,9 +259,23 @@
     private Object toJson(final Object metric, final String nameSuffix) {
         if (Timer.class.isInstance(metric)) {
             final Timer meter = Timer.class.cast(metric);
-            final Map<Object, Object> map = new HashMap<>(15);
+            final Map<Object, Object> map = new TreeMap<>();
             map.putAll(snapshot(meter.getSnapshot(), nameSuffix));
             map.putAll(meter(meter, nameSuffix));
+            final Duration elapsedTime = meter.getElapsedTime();
+            map.put("elapsedTime" + nameSuffix, elapsedTime == null ? 0 : elapsedTime.toNanos());
+            return map;
+        }
+        if (SimpleTimer.class.isInstance(metric)) {
+            final SimpleTimer simpleTimer = SimpleTimer.class.cast(metric);
+            final Map<Object, Object> map = new TreeMap<>();
+            map.put("count" + nameSuffix, simpleTimer.getCount());
+            final Duration elapsedTime = simpleTimer.getElapsedTime();
+            map.put("elapsedTime" + nameSuffix, elapsedTime == null ? 0 : elapsedTime.toNanos());
+            final Duration minTimeDuration = simpleTimer.getMinTimeDuration();
+            map.put("minTimeDuration" + nameSuffix, minTimeDuration == null ? JsonValue.NULL : minTimeDuration.toNanos());
+            final Duration maxTimeDuration = simpleTimer.getMaxTimeDuration();
+            map.put("maxTimeDuration" + nameSuffix, maxTimeDuration == null ? JsonValue.NULL : maxTimeDuration.toNanos());
             return map;
         }
         if (Meter.class.isInstance(metric)) {
@@ -265,14 +283,14 @@
         }
         if (Histogram.class.isInstance(metric)) {
             final Histogram histogram = Histogram.class.cast(metric);
-            final Map<Object, Object> map = new HashMap<>(11);
+            final Map<Object, Object> map = new TreeMap<>();
             map.putAll(snapshot(histogram.getSnapshot(), nameSuffix));
             map.put("count" + nameSuffix, histogram.getCount());
             return map;
         }
         if (ConcurrentGauge.class.isInstance(metric)) {
             final ConcurrentGauge concurrentGauge = ConcurrentGauge.class.cast(metric);
-            final Map<Object, Object> map = new HashMap<>(3);
+            final Map<Object, Object> map = new TreeMap<>();
             map.put("min" + nameSuffix, concurrentGauge.getMin());
             map.put("current" + nameSuffix, concurrentGauge.getCount());
             map.put("max" + nameSuffix, concurrentGauge.getMax());
@@ -283,7 +301,7 @@
     }
 
     private Map<String, Object> meter(final Metered metered, final String nameSuffix) {
-        final Map<String, Object> map = new HashMap<>(5);
+        final Map<String, Object> map = new TreeMap<>();
         map.put("count" + nameSuffix, metered.getCount());
         map.put("meanRate" + nameSuffix, metered.getMeanRate());
         map.put("oneMinRate" + nameSuffix, metered.getOneMinuteRate());
@@ -293,7 +311,7 @@
     }
 
     private Map<String, Object> snapshot(final Snapshot snapshot, final String nameSuffix) {
-        final Map<String, Object> map = new HashMap<>(10);
+        final Map<String, Object> map = new TreeMap<>();
         map.put("p50" + nameSuffix, snapshot.getMedian());
         map.put("p75" + nameSuffix, snapshot.get75thPercentile());
         map.put("p95" + nameSuffix, snapshot.get95thPercentile());
diff --git a/geronimo-metrics-common/src/main/java/org/apache/geronimo/microprofile/metrics/common/prometheus/OpenMetricsFormatter.java b/geronimo-metrics-common/src/main/java/org/apache/geronimo/microprofile/metrics/common/prometheus/OpenMetricsFormatter.java
new file mode 100644
index 0000000..ebb751f
--- /dev/null
+++ b/geronimo-metrics-common/src/main/java/org/apache/geronimo/microprofile/metrics/common/prometheus/OpenMetricsFormatter.java
@@ -0,0 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.geronimo.microprofile.metrics.common.prometheus;
+
+// just to expose it "correctly" named
+public class OpenMetricsFormatter extends PrometheusFormatter {
+}
diff --git a/geronimo-metrics-common/src/main/java/org/apache/geronimo/microprofile/metrics/common/prometheus/PrometheusFormatter.java b/geronimo-metrics-common/src/main/java/org/apache/geronimo/microprofile/metrics/common/prometheus/PrometheusFormatter.java
index 09b16d6..ddd0e8f 100644
--- a/geronimo-metrics-common/src/main/java/org/apache/geronimo/microprofile/metrics/common/prometheus/PrometheusFormatter.java
+++ b/geronimo-metrics-common/src/main/java/org/apache/geronimo/microprofile/metrics/common/prometheus/PrometheusFormatter.java
@@ -36,6 +36,7 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.lang.reflect.Modifier;
+import java.time.Duration;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
@@ -81,7 +82,7 @@
 
     public PrometheusFormatter enableOverriding() {
         try (final InputStream source = Thread.currentThread().getContextClassLoader()
-                                              .getResourceAsStream("META-INF/geronimo-metrics/prometheus-mapping.properties")) {
+                .getResourceAsStream("META-INF/geronimo-metrics/prometheus-mapping.properties")) {
             if (source != null) {
                 final Properties properties = new Properties();
                 properties.load(source);
@@ -91,8 +92,8 @@
             // no-op
         }
         System.getProperties().stringPropertyNames().stream()
-              .filter(it -> it.startsWith("geronimo.metrics.prometheus.mapping."))
-              .forEach(k -> keyMapping.put(k.substring("geronimo.metrics.prometheus.mapping.".length()), System.getProperty(k)));
+                .filter(it -> it.startsWith("geronimo.metrics.prometheus.mapping."))
+                .forEach(k -> keyMapping.put(k.substring("geronimo.metrics.prometheus.mapping.".length()), System.getProperty(k)));
         afterOverride();
         return this;
     }
@@ -103,9 +104,9 @@
             prefixFilter = null;
         } else {
             final List<String> prefixes = Stream.of(prefix.split(","))
-                                               .map(String::trim)
-                                               .filter(it -> !it.isEmpty())
-                                               .collect(toList());
+                    .map(String::trim)
+                    .filter(it -> !it.isEmpty())
+                    .collect(toList());
             final Predicate<String> directPredicate = name -> prefixes.stream().anyMatch(name::startsWith);
             prefixFilter = name -> directPredicate.test(name) || directPredicate.test(keyMapping.getOrDefault(name, name));
         }
@@ -181,50 +182,65 @@
     }
 
     private StringBuilder histogram(final String registryKey, final Entry entry, final List<Tag> tagsAsList, final String keyBase, final String keyUnit, final Histogram histogram) {
+        final String type = entry.metadata == null ? null : entry.metadata.getType();
         return new StringBuilder()
-                .append(type(registryKey, keyBase + keyUnit + " summary", entry.metadata))
-                .append(value(registryKey, keyBase + keyUnit + "_count", histogram.getCount(), entry.metadata, tagsAsList))
+                .append(type(registryKey, keyBase + keyUnit + " summary", type))
+                .append(value(registryKey, keyBase + keyUnit + "_count", histogram.getCount(), type, entry.metadata, tagsAsList))
                 .append(toPrometheus(registryKey, keyBase, keyUnit, histogram.getSnapshot(), entry.metadata, tagsAsList));
     }
 
     private StringBuilder timer(final String registryKey, final Entry entry, final List<Tag> tagsAsList, final String keyBase, final String keyUnit, final Timer timer) {
+        final Duration elapsedTime = timer.getElapsedTime();
+        final String type = entry.metadata == null ? null : entry.metadata.getType();
         return new StringBuilder()
-                .append(type(registryKey, keyBase + keyUnit + " summary", entry.metadata))
-                .append(value(registryKey, keyBase + keyUnit + "_count", timer.getCount(), entry.metadata, tagsAsList))
+                .append(type(registryKey, keyBase + keyUnit + " summary", type))
+                .append(value(registryKey, keyBase + keyUnit + "_count", timer.getCount(), type, entry.metadata, tagsAsList))
+                .append(value(registryKey, keyBase + "_elapsedTime", elapsedTime == null ? 0 : elapsedTime.toNanos(), type, entry.metadata, tagsAsList))
                 .append(meter(registryKey, entry, tagsAsList, timer, keyBase))
                 .append(toPrometheus(registryKey, keyBase, keyUnit, timer.getSnapshot(), entry.metadata, tagsAsList));
     }
 
-    private StringBuilder simpleTimer(final String registryKey, final Entry entry, final List<Tag> tagsAsList, final String keyBase, final String keyUnit, final SimpleTimer timer) {
-        return new StringBuilder()
-                .append(type(registryKey, keyBase + keyUnit + " summary", entry.metadata))
-                .append(value(registryKey, keyBase + keyUnit + "_count", timer.getCount(), entry.metadata, tagsAsList));
+    private StringBuilder simpleTimer(final String registryKey, final Entry entry, final List<Tag> tagsAsList,
+                                      final String keyBase, final String keyUnit, final SimpleTimer timer) {
+        final Duration elapsedTime = timer.getElapsedTime();
+        final StringBuilder builder = new StringBuilder()
+                .append(type(registryKey, keyBase + keyUnit + " summary", "simple timer"))
+                .append(value(registryKey, keyBase + "_total", timer.getCount(), "counter", entry.metadata, tagsAsList))
+                .append(value(registryKey, keyBase + "_elapsedTime" + keyUnit, elapsedTime == null ? 0 : elapsedTime.toNanos(), "simple timer", entry.metadata, tagsAsList));
+        final Duration minTimeDuration = timer.getMinTimeDuration();
+        builder.append(value(registryKey, keyBase + "_minTimeDuration" + keyUnit, minTimeDuration == null ? Double.NaN : minTimeDuration.toNanos(), "simple timer", entry.metadata, tagsAsList));
+        final Duration maxTimeDuration = timer.getMaxTimeDuration();
+        builder.append(value(registryKey, keyBase + "_maxTimeDuration" + keyUnit, maxTimeDuration == null ? Double.NaN : maxTimeDuration.toNanos(), "simple timer", entry.metadata, tagsAsList));
+        return builder;
     }
 
     private StringBuilder meter(final String registryKey, final Entry entry, final List<Tag> tagsAsList, final Metered meter, final String keyBase) {
+        final String type = entry.metadata == null ? null : entry.metadata.getType();
         return new StringBuilder()
-                .append(value(registryKey, keyBase + "_rate_per_second", meter.getMeanRate(), entry.metadata, tagsAsList))
-                .append(value(registryKey, keyBase + "_one_min_rate_per_second", meter.getOneMinuteRate(), entry.metadata, tagsAsList))
-                .append(value(registryKey, keyBase + "_five_min_rate_per_second", meter.getFiveMinuteRate(), entry.metadata, tagsAsList))
-                .append(value(registryKey, keyBase + "_fifteen_min_rate_per_second", meter.getFifteenMinuteRate(), entry.metadata, tagsAsList))
-                .append(value(registryKey, keyBase + "_total", meter.getCount(), entry.metadata, tagsAsList));
+                .append(value(registryKey, keyBase + "_rate_per_second", meter.getMeanRate(), type, entry.metadata, tagsAsList))
+                .append(value(registryKey, keyBase + "_one_min_rate_per_second", meter.getOneMinuteRate(), type, entry.metadata, tagsAsList))
+                .append(value(registryKey, keyBase + "_five_min_rate_per_second", meter.getFiveMinuteRate(), type, entry.metadata, tagsAsList))
+                .append(value(registryKey, keyBase + "_fifteen_min_rate_per_second", meter.getFifteenMinuteRate(), type, entry.metadata, tagsAsList))
+                .append(value(registryKey, keyBase + "_total", meter.getCount(), type, entry.metadata, tagsAsList));
     }
 
     private StringBuilder gauge(final String registryKey, final Entry entry, final List<Tag> tagsAsList, final Number value, final String key) {
         return new StringBuilder()
-                .append(value(registryKey, key, value.doubleValue(), entry.metadata, tagsAsList));
+                .append(value(registryKey, key, value.doubleValue(), entry.metadata == null ? null : entry.metadata.getType(), entry.metadata, tagsAsList));
     }
 
     private StringBuilder concurrentGauge(final String registryKey, final Entry entry, final List<Tag> tagsAsList, final String key, final ConcurrentGauge concurrentGauge) {
+        final String type = entry.metadata == null ? null : entry.metadata.getType();
         return new StringBuilder()
-                .append(value(registryKey, key + "_current", concurrentGauge.getCount(), entry.metadata, tagsAsList))
-                .append(value(registryKey, key + "_min", concurrentGauge.getMin(), entry.metadata, tagsAsList))
-                .append(value(registryKey, key + "_max", concurrentGauge.getMax(), entry.metadata, tagsAsList));
+                .append(value(registryKey, key + "_current", concurrentGauge.getCount(), type, entry.metadata, tagsAsList))
+                .append(value(registryKey, key + "_min", concurrentGauge.getMin(), type, entry.metadata, tagsAsList))
+                .append(value(registryKey, key + "_max", concurrentGauge.getMax(), type, entry.metadata, tagsAsList));
     }
 
     private StringBuilder counter(final String registryKey, final Entry entry, final List<Tag> tagsAsList, final String key) {
         return new StringBuilder()
-                .append(value(registryKey, key, Counter.class.cast(entry.metric).getCount(), entry.metadata, tagsAsList));
+                .append(value(registryKey, key, Counter.class.cast(entry.metric).getCount(),
+                        entry.metadata == null ? null : entry.metadata.getType(), entry.metadata, tagsAsList));
     }
 
     private StringBuilder toPrometheus(final String registryKey, final String keyBase, final String keyUnit,
@@ -232,22 +248,23 @@
         final Function<Stream<Tag>, Collection<Tag>> metaFactory = newTags -> Stream.concat(
                 tags == null ? Stream.empty() : tags.stream(), newTags).distinct().collect(toList());
         final String completeKey = keyBase + keyUnit;
+        final String type = metadata == null ? null : metadata.getType();
         return new StringBuilder()
-                .append(value(registryKey, keyBase + "_min" + keyUnit, snapshot.getMin(), metadata, tags))
-                .append(value(registryKey, keyBase + "_max" + keyUnit, snapshot.getMax(), metadata, tags))
-                .append(value(registryKey, keyBase + "_mean" + keyUnit, snapshot.getMean(), metadata, tags))
-                .append(value(registryKey, keyBase + "_stddev" + keyUnit, snapshot.getStdDev(), metadata, tags))
-                .append(value(registryKey, completeKey, snapshot.getMedian(), metadata,
+                .append(value(registryKey, keyBase + "_min" + keyUnit, snapshot.getMin(), type, metadata, tags))
+                .append(value(registryKey, keyBase + "_max" + keyUnit, snapshot.getMax(), type, metadata, tags))
+                .append(value(registryKey, keyBase + "_mean" + keyUnit, snapshot.getMean(), type, metadata, tags))
+                .append(value(registryKey, keyBase + "_stddev" + keyUnit, snapshot.getStdDev(), type, metadata, tags))
+                .append(value(registryKey, completeKey, snapshot.getMedian(), type, metadata,
                         metaFactory.apply(Stream.of(new Tag("quantile", "0.5")))))
-                .append(value(registryKey, completeKey, snapshot.get75thPercentile(), metadata,
+                .append(value(registryKey, completeKey, snapshot.get75thPercentile(), type, metadata,
                         metaFactory.apply(Stream.of(new Tag("quantile", "0.75")))))
-                .append(value(registryKey, completeKey, snapshot.get95thPercentile(), metadata,
+                .append(value(registryKey, completeKey, snapshot.get95thPercentile(), type, metadata,
                         metaFactory.apply(Stream.of(new Tag("quantile", "0.95")))))
-                .append(value(registryKey, completeKey, snapshot.get98thPercentile(), metadata,
+                .append(value(registryKey, completeKey, snapshot.get98thPercentile(), type, metadata,
                         metaFactory.apply(Stream.of(new Tag("quantile", "0.98")))))
-                .append(value(registryKey, completeKey, snapshot.get99thPercentile(), metadata,
+                .append(value(registryKey, completeKey, snapshot.get99thPercentile(), type, metadata,
                         metaFactory.apply(Stream.of(new Tag("quantile", "0.99")))))
-                .append(value(registryKey, completeKey, snapshot.get999thPercentile(), metadata,
+                .append(value(registryKey, completeKey, snapshot.get999thPercentile(), type, metadata,
                         metaFactory.apply(Stream.of(new Tag("quantile", "0.999")))));
     }
 
@@ -256,15 +273,15 @@
     }
 
     private String toUnitSuffix(final Metadata metadata, final boolean enforceValid) {
-        final String unit = enforceValid ? getValidUnit(metadata) : metadata.getUnit().orElse(MetricUnits.NONE) ;
+        final String unit = enforceValid ? getValidUnit(metadata) : metadata.getUnit().orElse(MetricUnits.NONE);
         return MetricUnits.NONE.equalsIgnoreCase(unit) || (enforceValid && !validUnits.contains(unit)) ? "" : ("_" + toPrometheusUnit(unit));
     }
 
     private StringBuilder value(final String registryKey, final String key, final double value,
-                                final Metadata metadata, final Collection<Tag> tags) {
+                                final String type, final Metadata metadata, final Collection<Tag> tags) {
         final String builtKey = registryKey + '_' + key;
         return new StringBuilder()
-                .append(type(registryKey, key, metadata))
+                .append(type(registryKey, key, type))
                 .append(keyMapping.getOrDefault(builtKey, builtKey))
                 .append(of(tags)
                         .filter(t -> !t.isEmpty())
@@ -285,12 +302,12 @@
         return unit;
     }
 
-    private StringBuilder type(final String registryKey, final String key, final Metadata metadata) {
+    private StringBuilder type(final String registryKey, final String key, final String type) {
         final String builtKey = registryKey + '_' + key;
         final StringBuilder builder = new StringBuilder()
                 .append("# TYPE ").append(keyMapping.getOrDefault(builtKey, builtKey));
-        if (metadata != null) {
-            builder.append(' ').append(metadata.getType());
+        if (type != null) {
+            builder.append(' ').append(type);
         }
         return builder.append("\n");
     }
diff --git a/geronimo-metrics/src/main/java/org/apache/geronimo/microprofile/metrics/cdi/MetricsExtension.java b/geronimo-metrics/src/main/java/org/apache/geronimo/microprofile/metrics/cdi/MetricsExtension.java
index 79e6b90..ccd6ad4 100644
--- a/geronimo-metrics/src/main/java/org/apache/geronimo/microprofile/metrics/cdi/MetricsExtension.java
+++ b/geronimo-metrics/src/main/java/org/apache/geronimo/microprofile/metrics/cdi/MetricsExtension.java
@@ -45,10 +45,12 @@
 import javax.enterprise.event.Observes;
 import javax.enterprise.inject.Any;
 import javax.enterprise.inject.Default;
+import javax.enterprise.inject.Produces;
 import javax.enterprise.inject.Stereotype;
 import javax.enterprise.inject.spi.AfterBeanDiscovery;
 import javax.enterprise.inject.spi.AfterDeploymentValidation;
 import javax.enterprise.inject.spi.Annotated;
+import javax.enterprise.inject.spi.AnnotatedCallable;
 import javax.enterprise.inject.spi.AnnotatedType;
 import javax.enterprise.inject.spi.Bean;
 import javax.enterprise.inject.spi.BeanManager;
@@ -155,7 +157,7 @@
             return;
         }
         final Class<?> clazz = findClass(processProducerMethod.getAnnotated().getBaseType());
-        if (clazz == null || !Metric.class.isAssignableFrom(clazz)) {
+        if (clazz == null || !Gauge.class.isAssignableFrom(clazz)) {
             return;
         }
         final Member javaMember = processProducerMethod.getAnnotatedProducerMethod().getJavaMember();
@@ -248,114 +250,8 @@
         Stream.concat(annotatedType.getMethods().stream(), annotatedType.getConstructors().stream())
                 .filter(method -> method.getJavaMember().getDeclaringClass() == javaClass || Modifier.isAbstract(method.getJavaMember().getDeclaringClass().getModifiers()))
                 .filter(method -> !method.getJavaMember().isSynthetic() && !Modifier.isPrivate(method.getJavaMember().getModifiers()))
-                .forEach(method -> {
-                    final Member javaMember = method.getJavaMember();
-
-                    final Counted counted = ofNullable(method.getAnnotation(Counted.class)).orElseGet(() ->
-                            getAnnotation(annotatedType, Counted.class));
-                    if (counted != null) {
-                        final boolean isMethod = method.isAnnotationPresent(Counted.class);
-                        final String name = Names.findName(javaClass, javaMember, isMethod ? counted.name() : "", counted.absolute(),
-                                ofNullable(getAnnotation(annotatedType, Counted.class)).map(Counted::name).orElse(""));
-                        final Metadata metadata = Metadata.builder()
-                                .withName(name)
-                                .withDisplayName(counted.displayName())
-                                .withDescription(counted.description())
-                                .withType(MetricType.COUNTER)
-                                .withUnit(counted.unit())
-                                .build();
-                        final MetricID metricID = new MetricID(name, createTags(counted.tags()));
-                        addRegistration(metadata, metricID, counted.reusable() || !isMethod);
-                    }
-
-                    final ConcurrentGauge concurrentGauge = ofNullable(method.getAnnotation(ConcurrentGauge.class)).orElseGet(() ->
-                            getAnnotation(annotatedType, ConcurrentGauge.class));
-                    if (concurrentGauge != null) {
-                        final boolean isMethod = method.isAnnotationPresent(ConcurrentGauge.class);
-                        final String name = Names.findName(javaClass, javaMember, isMethod ? concurrentGauge.name() : "", concurrentGauge.absolute(),
-                                ofNullable(getAnnotation(annotatedType, ConcurrentGauge.class)).map(ConcurrentGauge::name).orElse(""));
-                        final Metadata metadata = Metadata.builder()
-                                .withName(name)
-                                .withDisplayName(concurrentGauge.displayName())
-                                .withDescription(concurrentGauge.description())
-                                .withType(MetricType.CONCURRENT_GAUGE)
-                                .withUnit(concurrentGauge.unit())
-                                .build();
-                        final MetricID metricID = new MetricID(name, createTags(concurrentGauge.tags()));
-                        addRegistration(metadata, metricID, concurrentGauge.reusable() || !isMethod);
-                    }
-
-                    final Timed timed = ofNullable(method.getAnnotation(Timed.class)).orElseGet(() -> getAnnotation(annotatedType, Timed.class));
-                    if (timed != null) {
-                        final boolean isMethod = method.isAnnotationPresent(Timed.class);
-                        final String name = Names.findName(javaClass, javaMember, isMethod ? timed.name() : "", timed.absolute(),
-                                ofNullable(getAnnotation(annotatedType, Timed.class)).map(Timed::name).orElse(""));
-                        final Metadata metadata = Metadata.builder()
-                                .withName(name)
-                                .withDisplayName(timed.displayName())
-                                .withDescription(timed.description())
-                                .withType(MetricType.TIMER)
-                                .withUnit(timed.unit())
-                                .build();
-                        final MetricID metricID = new MetricID(name, createTags(timed.tags()));
-                        addRegistration(metadata, metricID, timed.reusable() || !isMethod);
-                    }
-
-                    final SimplyTimed simplyTimed = ofNullable(method.getAnnotation(SimplyTimed.class)).orElseGet(() -> getAnnotation(annotatedType, SimplyTimed.class));
-                    if (simplyTimed != null) {
-                        final boolean isMethod = method.isAnnotationPresent(SimplyTimed.class);
-                        final String name = Names.findName(javaClass, javaMember, isMethod ? simplyTimed.name() : "", simplyTimed.absolute(),
-                                ofNullable(getAnnotation(annotatedType, SimplyTimed.class)).map(SimplyTimed::name).orElse(""));
-                        final Metadata metadata = Metadata.builder()
-                                .withName(name)
-                                .withDisplayName(simplyTimed.displayName())
-                                .withDescription(simplyTimed.description())
-                                .withType(MetricType.SIMPLE_TIMER)
-                                .withUnit(simplyTimed.unit())
-                                .build();
-                        final MetricID metricID = new MetricID(name, createTags(simplyTimed.tags()));
-                        addRegistration(metadata, metricID, simplyTimed.reusable() || !isMethod);
-                    }
-
-                    final org.eclipse.microprofile.metrics.annotation.Metered metered = ofNullable(method.getAnnotation(org.eclipse.microprofile.metrics.annotation.Metered.class))
-                            .orElseGet(() -> getAnnotation(annotatedType, org.eclipse.microprofile.metrics.annotation.Metered.class));
-                    if (metered != null) {
-                        final boolean isMethod = method.isAnnotationPresent(Metered.class);
-                        final String name = Names.findName(javaClass, javaMember, isMethod ? metered.name() : "", metered.absolute(),
-                                ofNullable(getAnnotation(annotatedType, Metered.class)).map(Metered::name).orElse(""));
-                        final Metadata metadata = Metadata.builder()
-                                .withName(name)
-                                .withDisplayName(metered.displayName())
-                                .withDescription(metered.description())
-                                .withType(MetricType.METERED)
-                                .withUnit(metered.unit())
-                                .build();
-                        final MetricID metricID = new MetricID(name, createTags(metered.tags()));
-                        addRegistration(metadata, metricID, metered.reusable() || !isMethod);
-                    }
-
-                    final org.eclipse.microprofile.metrics.annotation.Gauge gauge = ofNullable(method.getAnnotation(org.eclipse.microprofile.metrics.annotation.Gauge.class))
-                            .orElseGet(() -> getAnnotation(annotatedType, org.eclipse.microprofile.metrics.annotation.Gauge.class));
-                    if (gauge != null) {
-                        final String name = Names.findName(
-                                javaClass, javaMember, gauge.name(), gauge.absolute(),
-                                ofNullable(getAnnotation(annotatedType, org.eclipse.microprofile.metrics.annotation.Gauge.class)).map(org.eclipse.microprofile.metrics.annotation.Gauge::name).orElse(""));
-                        final Metadata metadata = Metadata.builder()
-                                .withName(name)
-                                .withDisplayName(gauge.displayName())
-                                .withDescription(gauge.description())
-                                .withType(MetricType.GAUGE)
-                                .withUnit(gauge.unit())
-                                .build();
-                        final MetricID metricID = new MetricID(name, createTags(gauge.tags()));
-                        addRegistration(metadata, metricID, false);
-                        gaugeFactories.put(metricID, beanManager -> {
-                            final Object reference = getInstance(javaClass, beanManager);
-                            final Method mtd = Method.class.cast(javaMember);
-                            return new GaugeImpl<>(reference, mtd);
-                        });
-                    }
-                });
+                .filter(method -> !method.isAnnotationPresent(Produces.class))
+                .forEach(method -> doRegisterMetric(annotatedType, javaClass, method));
     }
 
     void afterBeanDiscovery(@Observes final AfterBeanDiscovery afterBeanDiscovery) {
@@ -438,6 +334,115 @@
         creationalContexts.forEach(CreationalContext::release);
     }
 
+    private void doRegisterMetric(final AnnotatedType<?> annotatedType, final Class<?> javaClass, final AnnotatedCallable<?> method) {
+        final Member javaMember = method.getJavaMember();
+
+        final Counted counted = ofNullable(method.getAnnotation(Counted.class)).orElseGet(() ->
+                getAnnotation(annotatedType, Counted.class));
+        if (counted != null) {
+            final boolean isMethod = method.isAnnotationPresent(Counted.class);
+            final String name = Names.findName(javaClass, javaMember, isMethod ? counted.name() : "", counted.absolute(),
+                    ofNullable(getAnnotation(annotatedType, Counted.class)).map(Counted::name).orElse(""));
+            final Metadata metadata = Metadata.builder()
+                    .withName(name)
+                    .withDisplayName(counted.displayName())
+                    .withDescription(counted.description())
+                    .withType(MetricType.COUNTER)
+                    .withUnit(counted.unit())
+                    .build();
+            final MetricID metricID = new MetricID(name, createTags(counted.tags()));
+            addRegistration(metadata, metricID, counted.reusable() || !isMethod);
+        }
+
+        final ConcurrentGauge concurrentGauge = ofNullable(method.getAnnotation(ConcurrentGauge.class)).orElseGet(() ->
+                getAnnotation(annotatedType, ConcurrentGauge.class));
+        if (concurrentGauge != null) {
+            final boolean isMethod = method.isAnnotationPresent(ConcurrentGauge.class);
+            final String name = Names.findName(javaClass, javaMember, isMethod ? concurrentGauge.name() : "", concurrentGauge.absolute(),
+                    ofNullable(getAnnotation(annotatedType, ConcurrentGauge.class)).map(ConcurrentGauge::name).orElse(""));
+            final Metadata metadata = Metadata.builder()
+                    .withName(name)
+                    .withDisplayName(concurrentGauge.displayName())
+                    .withDescription(concurrentGauge.description())
+                    .withType(MetricType.CONCURRENT_GAUGE)
+                    .withUnit(concurrentGauge.unit())
+                    .build();
+            final MetricID metricID = new MetricID(name, createTags(concurrentGauge.tags()));
+            addRegistration(metadata, metricID, concurrentGauge.reusable() || !isMethod);
+        }
+
+        final Timed timed = ofNullable(method.getAnnotation(Timed.class)).orElseGet(() -> getAnnotation(annotatedType, Timed.class));
+        if (timed != null) {
+            final boolean isMethod = method.isAnnotationPresent(Timed.class);
+            final String name = Names.findName(javaClass, javaMember, isMethod ? timed.name() : "", timed.absolute(),
+                    ofNullable(getAnnotation(annotatedType, Timed.class)).map(Timed::name).orElse(""));
+            final Metadata metadata = Metadata.builder()
+                    .withName(name)
+                    .withDisplayName(timed.displayName())
+                    .withDescription(timed.description())
+                    .withType(MetricType.TIMER)
+                    .withUnit(timed.unit())
+                    .build();
+            final MetricID metricID = new MetricID(name, createTags(timed.tags()));
+            addRegistration(metadata, metricID, timed.reusable() || !isMethod);
+        }
+
+        final SimplyTimed simplyTimed = ofNullable(method.getAnnotation(SimplyTimed.class)).orElseGet(() -> getAnnotation(annotatedType, SimplyTimed.class));
+        if (simplyTimed != null) {
+            final boolean isMethod = method.isAnnotationPresent(SimplyTimed.class);
+            final String name = Names.findName(javaClass, javaMember, isMethod ? simplyTimed.name() : "", simplyTimed.absolute(),
+                    ofNullable(getAnnotation(annotatedType, SimplyTimed.class)).map(SimplyTimed::name).orElse(""));
+            final Metadata metadata = Metadata.builder()
+                    .withName(name)
+                    .withDisplayName(simplyTimed.displayName())
+                    .withDescription(simplyTimed.description())
+                    .withType(MetricType.SIMPLE_TIMER)
+                    .withUnit(simplyTimed.unit())
+                    .build();
+            final MetricID metricID = new MetricID(name, createTags(simplyTimed.tags()));
+            addRegistration(metadata, metricID, simplyTimed.reusable() || !isMethod);
+        }
+
+        final Metered metered = ofNullable(method.getAnnotation(Metered.class))
+                .orElseGet(() -> getAnnotation(annotatedType, Metered.class));
+        if (metered != null) {
+            final boolean isMethod = method.isAnnotationPresent(Metered.class);
+            final String name = Names.findName(javaClass, javaMember, isMethod ? metered.name() : "", metered.absolute(),
+                    ofNullable(getAnnotation(annotatedType, Metered.class)).map(Metered::name).orElse(""));
+            final Metadata metadata = Metadata.builder()
+                    .withName(name)
+                    .withDisplayName(metered.displayName())
+                    .withDescription(metered.description())
+                    .withType(MetricType.METERED)
+                    .withUnit(metered.unit())
+                    .build();
+            final MetricID metricID = new MetricID(name, createTags(metered.tags()));
+            addRegistration(metadata, metricID, metered.reusable() || !isMethod);
+        }
+
+        final org.eclipse.microprofile.metrics.annotation.Gauge gauge = ofNullable(method.getAnnotation(org.eclipse.microprofile.metrics.annotation.Gauge.class))
+                .orElseGet(() -> getAnnotation(annotatedType, org.eclipse.microprofile.metrics.annotation.Gauge.class));
+        if (gauge != null) {
+            final String name = Names.findName(
+                    javaClass, javaMember, gauge.name(), gauge.absolute(),
+                    ofNullable(getAnnotation(annotatedType, org.eclipse.microprofile.metrics.annotation.Gauge.class)).map(org.eclipse.microprofile.metrics.annotation.Gauge::name).orElse(""));
+            final Metadata metadata = Metadata.builder()
+                    .withName(name)
+                    .withDisplayName(gauge.displayName())
+                    .withDescription(gauge.description())
+                    .withType(MetricType.GAUGE)
+                    .withUnit(gauge.unit())
+                    .build();
+            final MetricID metricID = new MetricID(name, createTags(gauge.tags()));
+            addRegistration(metadata, metricID, false);
+            gaugeFactories.put(metricID, beanManager -> {
+                final Object reference = getInstance(javaClass, beanManager);
+                final Method mtd = Method.class.cast(javaMember);
+                return new GaugeImpl<>(reference, mtd);
+            });
+        }
+    }
+
     private void registerProducer(final BeanManager beanManager, final org.eclipse.microprofile.metrics.annotation.Metric config,
                                   final Class<?> clazz, final Member javaMember, final Bean<?> bean) {
         Class<?> beanClass = bean.getBeanClass();
diff --git a/pom.xml b/pom.xml
index 616437a..0d8993f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -86,6 +86,12 @@
     </dependency>
     <dependency>
       <groupId>org.apache.geronimo.specs</groupId>
+      <artifactId>geronimo-json_1.1_spec</artifactId>
+      <version>1.3</version>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.geronimo.specs</groupId>
       <artifactId>geronimo-jsonb_1.0_spec</artifactId>
       <version>1.0</version>
       <scope>provided</scope>