diff --git a/resteasy/pom.xml b/resteasy/pom.xml
index 85e32d7e..c6aee130 100644
--- a/resteasy/pom.xml
+++ b/resteasy/pom.xml
@@ -31,7 +31,7 @@
Ozark RESTEasy
- 2.2.1.GA
+ 4.0.0-SNAPSHOT
diff --git a/resteasy/src/main/java/org/mvcspec/ozark/resteasy/metadata/OzarkClassProcessor.java b/resteasy/src/main/java/org/mvcspec/ozark/resteasy/metadata/OzarkClassProcessor.java
new file mode 100644
index 00000000..c73ddea0
--- /dev/null
+++ b/resteasy/src/main/java/org/mvcspec/ozark/resteasy/metadata/OzarkClassProcessor.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright © 2017 Ivar Grimstad (ivar.grimstad@gmail.com)
+ *
+ * Licensed 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.mvcspec.ozark.resteasy.metadata;
+
+import org.jboss.resteasy.spi.metadata.ResourceClass;
+import org.jboss.resteasy.spi.metadata.ResourceClassProcessor;
+import org.mvcspec.ozark.util.AnnotationUtils;
+
+import javax.mvc.annotation.Controller;
+import javax.ws.rs.ext.Provider;
+
+/**
+ * Custom implementation of the RESTEasy {@link ResourceClassProcessor} SPI which adds
+ * @Produces("text/html")
to controller methods if they don't define some other
+ * media type.
+ *
+ * @author Christian Kaltepoth
+ */
+@Provider
+public class OzarkClassProcessor implements ResourceClassProcessor {
+
+ @Override
+ public ResourceClass process(ResourceClass clazz) {
+
+ // we only need to wrap resources with at least one controller method here
+ if (AnnotationUtils.hasAnnotationOnClassOrMethod(clazz.getClazz(), Controller.class)) {
+ return new OzarkResourceClass(clazz);
+ }
+
+ return clazz;
+
+ }
+
+}
diff --git a/resteasy/src/main/java/org/mvcspec/ozark/resteasy/metadata/OzarkResourceClass.java b/resteasy/src/main/java/org/mvcspec/ozark/resteasy/metadata/OzarkResourceClass.java
new file mode 100644
index 00000000..7afef2ec
--- /dev/null
+++ b/resteasy/src/main/java/org/mvcspec/ozark/resteasy/metadata/OzarkResourceClass.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright © 2017 Ivar Grimstad (ivar.grimstad@gmail.com)
+ *
+ * Licensed 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.mvcspec.ozark.resteasy.metadata;
+
+import org.jboss.resteasy.spi.metadata.FieldParameter;
+import org.jboss.resteasy.spi.metadata.ResourceClass;
+import org.jboss.resteasy.spi.metadata.ResourceConstructor;
+import org.jboss.resteasy.spi.metadata.ResourceLocator;
+import org.jboss.resteasy.spi.metadata.ResourceMethod;
+import org.jboss.resteasy.spi.metadata.SetterParameter;
+
+import java.util.Arrays;
+import java.util.stream.Collectors;
+
+/**
+ * Wrapper for {@link ResourceClass} which wraps methods in {@link OzarkResourceMethod}.
+ *
+ * @author Christian Kaltepoth
+ */
+public class OzarkResourceClass implements ResourceClass {
+
+ private final ResourceClass delegate;
+ private final ResourceMethod[] resourceMethods;
+
+ public OzarkResourceClass(ResourceClass delegate) {
+ this.delegate = delegate;
+
+ // wrap methods so we can add @Produces("text/html") if required
+ this.resourceMethods = Arrays.stream(this.delegate.getResourceMethods())
+ .map(OzarkResourceMethod::new)
+ .collect(Collectors.toList())
+ .toArray(new ResourceMethod[0]);
+
+ }
+
+ @Override
+ public String getPath() {
+ return delegate.getPath();
+ }
+
+ @Override
+ public Class> getClazz() {
+ return delegate.getClazz();
+ }
+
+ @Override
+ public ResourceConstructor getConstructor() {
+ return delegate.getConstructor();
+ }
+
+ @Override
+ public FieldParameter[] getFields() {
+ return delegate.getFields();
+ }
+
+ @Override
+ public SetterParameter[] getSetters() {
+ return delegate.getSetters();
+ }
+
+ @Override
+ public ResourceMethod[] getResourceMethods() {
+ return resourceMethods;
+ }
+
+ @Override
+ public ResourceLocator[] getResourceLocators() {
+ return delegate.getResourceLocators();
+ }
+}
diff --git a/resteasy/src/main/java/org/mvcspec/ozark/resteasy/metadata/OzarkResourceMethod.java b/resteasy/src/main/java/org/mvcspec/ozark/resteasy/metadata/OzarkResourceMethod.java
new file mode 100644
index 00000000..d50fc123
--- /dev/null
+++ b/resteasy/src/main/java/org/mvcspec/ozark/resteasy/metadata/OzarkResourceMethod.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright © 2017 Ivar Grimstad (ivar.grimstad@gmail.com)
+ *
+ * Licensed 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.mvcspec.ozark.resteasy.metadata;
+
+import org.jboss.resteasy.spi.metadata.MethodParameter;
+import org.jboss.resteasy.spi.metadata.ResourceClass;
+import org.jboss.resteasy.spi.metadata.ResourceMethod;
+import org.mvcspec.ozark.util.AnnotationUtils;
+
+import javax.mvc.annotation.Controller;
+import javax.ws.rs.core.MediaType;
+import java.lang.reflect.Method;
+import java.lang.reflect.Type;
+import java.util.Set;
+
+/**
+ * Wrapper for {@link ResourceMethod} which adds @Produces("text/html")
to controller
+ * methods if no other media type was specified.
+ *
+ * @author Christian Kaltepoth
+ */
+public class OzarkResourceMethod implements ResourceMethod {
+
+ private final ResourceMethod delegate;
+ private final MediaType[] produces;
+
+ public OzarkResourceMethod(ResourceMethod delegate) {
+ this.delegate = delegate;
+
+ boolean isMediaTypeSpecified = delegate.getProduces() != null && delegate.getProduces().length > 0;
+
+ boolean isControllerMethod = AnnotationUtils.hasAnnotation(delegate.getMethod(), Controller.class)
+ || AnnotationUtils.hasAnnotation(delegate.getResourceClass().getClazz(), Controller.class);
+
+ this.produces = isControllerMethod && !isMediaTypeSpecified
+ ? new MediaType[]{MediaType.TEXT_HTML_TYPE}
+ : delegate.getProduces();
+
+ }
+
+ @Override
+ public Set getHttpMethods() {
+ return delegate.getHttpMethods();
+ }
+
+ @Override
+ public MediaType[] getProduces() {
+ return produces;
+ }
+
+ @Override
+ public MediaType[] getConsumes() {
+ return delegate.getConsumes();
+ }
+
+ @Override
+ public boolean isAsynchronous() {
+ return delegate.isAsynchronous();
+ }
+
+ @Override
+ public void markAsynchronous() {
+ delegate.markAsynchronous();
+ }
+
+ @Override
+ public ResourceClass getResourceClass() {
+ return delegate.getResourceClass();
+ }
+
+ @Override
+ public Class> getReturnType() {
+ return delegate.getReturnType();
+ }
+
+ @Override
+ public Type getGenericReturnType() {
+ return delegate.getGenericReturnType();
+ }
+
+ @Override
+ public Method getMethod() {
+ return delegate.getMethod();
+ }
+
+ @Override
+ public Method getAnnotatedMethod() {
+ return delegate.getAnnotatedMethod();
+ }
+
+ @Override
+ public MethodParameter[] getParams() {
+ return delegate.getParams();
+ }
+
+ @Override
+ public String getFullpath() {
+ return delegate.getFullpath();
+ }
+
+ @Override
+ public String getPath() {
+ return delegate.getPath();
+ }
+}